Kartik Scripts

Garages

Garages

Properties can store vehicles. There are two flavours: a garage point (a spot that opens a store/retrieve menu) and a full IPL garage (a walk-in garage interior with your cars physically parked and displayed across floors).


Garage capacity

Each property has garageSlots (default Config.PropertyDefaults.garageSlots = 2). Fitting a garage can be charged via Config.FeaturePricing.garage, and the minimum is floored for employee-set fit-outs.

Garage points (store / retrieve)

A garage point is placed in the world (the placement previews a ghost vehicle, Config.GaragePreviewVehicle = sultan).

  1. Drive up / walk to the garage point.
  2. Choose Store vehicle (parks your current car) or pick a listed vehicle to retrieve it.
  3. An empty garage tells you so; a full garage respects the slot cap.

Vehicle display names come from Config.VehicleList in shared/config_vehicles.lua:

Config.VehicleList = {
    -- [`spawnname`] = "Display Name",
    ['sultan'] = 'Karin Sultan',
}

IPL garages (physical, multi-floor)

For a richer experience, a property can use an IPL garage, a real garage interior you walk into, with your vehicles physically parked and displayed.

  • Entering plays a short garage entry cutscene/camera, then reveals the interior with your cars parked on display.
  • Vehicles are laid out across floors/pages, retrieve by walking up to the car, and drive out through the garage exit.
  • IPL garages are priced up with Config.Garage.IplPriceMult (2.0) relative to a standard garage.
Config.Garage = {
    IplPriceMult = 2.0, -- price multiplier for IPL-mode garages
}

IPL garages reuse the same instancing model as other IPL/shell interiors, each occupant is in their own routing bucket, so your parked cars are yours alone.

Setting up a garage

  • Add a garage to a property from the creation wizard (garage slots field) or place a garage point afterward.
  • The wizard's garage placement previews a vehicle ghost so you can align the parking spot.

External garage resources

By default the [E] at a garage point opens the built-in menu. You can hand it to a garage resource you already run instead:

-- shared/garage.lua
Config.Garage = {
    IplPriceMult = 2.0,
    UseExternal = true,
    -- 'auto' | 'kartik-garages' | 'op-garages' | 'jg-advancedgarages'
    Provider = 'auto',
}
  • UseExternal = true switches the garage point over to the provider.
  • Provider = 'auto' uses whichever supported garage resource is started. If several are running, it picks the first alphabetically and prints a warning in the console. Set a name to pin one.
  • If no provider is running, the built-in menu is used, so the key always works.
  • The property still decides access and the slot cap before the handoff. A player without access gets nothing, and parking into a full garage is refused.

Vehicles parked this way are saved with garage = 'kp_prop_<propertyId>' and state = 'garage'.

Making your garage script understand property garages

A stock garage script doesn't know what kp_prop_12 is, so a car parked at home looks lost. The external garage API exports fix that without touching our tables:

-- in your garage resource (server)
if exports['kartik-properties']:IsPropertyGarage(vehicle.garage) then
    local g = exports['kartik-properties']:GetPropertyGarage(vehicle.garage)
    garageLabel = g.label         -- "Mirror Park #4"
    garageCoords = g.coords       -- { x, y, z, w }
end

-- list a player's home garages next to the public ones
for _, g in ipairs(exports['kartik-properties']:GetPropertyGarages(cid)) do
    addGarage(g.garageId, g.label, g.coords)
end

Adding another provider

Providers are small client files in bridge/garage/client/. Copy one and register it under the resource's name:

local RES = 'my-garages'

KPGarage = KPGarage or {}
KPGarage.providers = KPGarage.providers or {}

KPGarage.providers[RES] = {
    resource = RES,
    Available = function() return GetResourceState(RES) == 'started' end,

    -- ctx = { garageId, label, coords = {x,y,z,w}, used, slots, canPark }
    Open = function(ctx)
        exports[RES]:OpenGarage(ctx.garageId, ctx.coords)
    end,

    -- called instead of Open when the player is in a vehicle
    Park = function(ctx, vehicle)
        exports[RES]:StoreVehicle(ctx.garageId, vehicle)
    end,
}

On this page