local Keys = { ["ESC"] = 322, ["F1"] = 288, ["F2"] = 289, ["F3"] = 170, ["F5"] = 166, ["F6"] = 167, ["F7"] = 168, ["F8"] = 169, ["F9"] = 56, ["F10"] = 57, ["~"] = 243, ["1"] = 157, ["2"] = 158, ["3"] = 160, ["4"] = 164, ["5"] = 165, ["6"] = 159, ["7"] = 161, ["8"] = 162, ["9"] = 163, ["-"] = 84, ["="] = 83, ["BACKSPACE"] = 177, ["TAB"] = 37, ["Q"] = 44, ["W"] = 32, ["E"] = 38, ["R"] = 45, ["T"] = 245, ["Y"] = 246, ["U"] = 303, ["P"] = 199, ["["] = 39, ["]"] = 40, ["ENTER"] = 18, ["CAPS"] = 137, ["A"] = 34, ["S"] = 8, ["D"] = 9, ["F"] = 23, ["G"] = 47, ["H"] = 74, ["K"] = 311, ["L"] = 182, ["LEFTSHIFT"] = 21, ["Z"] = 20, ["X"] = 73, ["C"] = 26, ["V"] = 0, ["B"] = 29, ["N"] = 249, ["M"] = 244, [","] = 82, ["."] = 81, ["LEFTCTRL"] = 36, ["LEFTALT"] = 19, ["SPACE"] = 22, ["RIGHTCTRL"] = 70, ["HOME"] = 213, ["PAGEUP"] = 10, ["PAGEDOWN"] = 11, ["DELETE"] = 178, ["LEFT"] = 174, ["RIGHT"] = 175, ["TOP"] = 27, ["DOWN"] = 173, ["NENTER"] = 201, ["N4"] = 108, ["N5"] = 60, ["N6"] = 107, ["N+"] = 96, ["N-"] = 97, ["N7"] = 117, ["N8"] = 61, ["N9"] = 118 } ESX = nil local GUI = {} GUI.Time = 0 local OwnedProperties = {} local Blips = {} local CurrentProperty = nil local LastProperty = nil local LastPart = nil local HasAlreadyEnteredMarker = false local CurrentAction = nil local CurrentActionMsg = '' local CurrentActionData = {} function DrawSub(text, time) ClearPrints() SetTextEntry_2('STRING') AddTextComponentString(text) DrawSubtitleTimed(time, 1) end function CreateBlips() for i=1, #Config.Properties, 1 do local property = Config.Properties[i] if property.entering ~= nil then Blips[property.name] = AddBlipForCoord(property.entering.x, property.entering.y, property.entering.z) SetBlipSprite (Blips[property.name], 369) SetBlipDisplay(Blips[property.name], 4) SetBlipScale (Blips[property.name], 1.0) SetBlipAsShortRange(Blips[property.name], true) BeginTextCommandSetBlipName("STRING") AddTextComponentString("Propriété libre") EndTextCommandSetBlipName(Blips[property.name]) end end end function GetProperties() return Config.Properties end function GetProperty(name) for i=1, #Config.Properties, 1 do if Config.Properties[i].name == name then return Config.Properties[i] end end end function GetGateway(property) for i=1, #Config.Properties, 1 do local property2 = Config.Properties[i] if property2.isGateway and property2.name == property.gateway then return property2 end end end function GetGatewayProperties(property) local properties = {} for i=1, #Config.Properties, 1 do if Config.Properties[i].gateway == property.name then table.insert(properties, Config.Properties[i]) end end return properties end function EnterProperty(name) local property = GetProperty(name) local playerPed = GetPlayerPed(-1) CurrentProperty = property for i=1, #Config.Properties, 1 do if Config.Properties[i].name ~= name then Config.Properties[i].disabled = true end end TriggerServerEvent('esx_property:saveLastProperty', name) TriggerEvent('instance:get', function(instance) if instance.host == nil then TriggerEvent('instance:create') end end) Citizen.CreateThread(function() DoScreenFadeOut(800) while not IsScreenFadedOut() do Citizen.Wait(0) end for i=1, #property.ipls, 1 do RequestIpl(property.ipls[i]) while not IsIplActive(property.ipls[i]) do Citizen.Wait(0) end end SetEntityCoords(playerPed, property.inside.x, property.inside.y, property.inside.z) DoScreenFadeIn(800) DrawSub(property.label, 5000) end) end function ExitProperty(name) local property = GetProperty(name) local playerPed = GetPlayerPed(-1) local outside = nil CurrentProperty = nil if property.isSingle then outside = property.outside else outside = GetGateway(property).outside end TriggerServerEvent('esx_property:deleteLastProperty') Citizen.CreateThread(function() DoScreenFadeOut(800) while not IsScreenFadedOut() do Citizen.Wait(0) end SetEntityCoords(playerPed, outside.x, outside.y, outside.z) TriggerEvent('instance:get', function(instance) if instance.host ~= nil then TriggerEvent('instance:leave') end end) for i=1, #property.ipls, 1 do RemoveIpl(property.ipls[i]) end for i=1, #Config.Properties, 1 do Config.Properties[i].disabled = false end DoScreenFadeIn(800) end) end function SetPropertyOwned(name, owned) local property = GetProperty(name) local entering = nil local enteringName = nil if property.isSingle then entering = property.entering enteringName = property.name else local gateway = GetGateway(property) entering = gateway.entering enteringName = gateway.name end if owned then OwnedProperties[name] = true RemoveBlip(Blips[enteringName]) Blips[enteringName] = AddBlipForCoord(entering.x, entering.y, entering.z) SetBlipSprite(Blips[enteringName], 357) SetBlipAsShortRange(Blips[enteringName], true) BeginTextCommandSetBlipName("STRING") AddTextComponentString("Propriété") EndTextCommandSetBlipName(Blips[enteringName]) else OwnedProperties[name] = nil local found = false for k,v in pairs(OwnedProperties) do local _property = GetProperty(k) local _gateway = GetGateway(_property) if _gateway ~= nil then if _gateway.name == enteringName then found = true break end end end if not found then RemoveBlip(Blips[enteringName]) Blips[enteringName] = AddBlipForCoord(entering.x, entering.y, entering.z) SetBlipSprite(Blips[enteringName], 369) SetBlipAsShortRange(Blips[enteringName], true) BeginTextCommandSetBlipName("STRING") AddTextComponentString("Propriété libre") EndTextCommandSetBlipName(Blips[enteringName]) end end end function PropertyIsOwned(property) return OwnedProperties[property.name] == true end function OpenPropertyMenu(property) local elements = {} if PropertyIsOwned(property) then table.insert(elements, {label = 'Entrer', value = 'enter'}) if not Config.EnablePlayerManagement then table.insert(elements, {label = 'Rendre', value = 'leave'}) end else if not Config.EnablePlayerManagement then table.insert(elements, {label = 'Acheter', value = 'buy'}) table.insert(elements, {label = 'Louer', value = 'rent'}) end table.insert(elements, {label = 'Visiter', value = 'visit'}) end ESX.UI.Menu.Open( 'default', GetCurrentResourceName(), 'property', { title = property.label, align = 'top-left', elements = elements, }, function(data2, menu) menu.close() if data2.current.value == 'enter' then EnterProperty(property.name) end if data2.current.value == 'leave' then TriggerServerEvent('esx_property:removeOwnedProperty', property.name) end if data2.current.value == 'buy' then TriggerServerEvent('esx_property:buyProperty', property.name) end if data2.current.value == 'rent' then TriggerServerEvent('esx_property:rentProperty', property.name) end if data2.current.value == 'visit' then EnterProperty(property.name) end end, function(data, menu) menu.close() CurrentAction = 'property_menu' CurrentActionMsg = 'Appuez sur ~INPUT_CONTEXT~ pour accéder au menu' CurrentActionData = {property = property} end ) end function OpenGatewayMenu(property) if Config.EnablePlayerManagement then OpenGatewayOwnedPropertiesMenu(gatewayProperties) else ESX.UI.Menu.Open( 'default', GetCurrentResourceName(), 'gateway', { title = property.name, align = 'top-left', elements = { {label = 'Propriétés acquises', value = 'owned_properties'}, {label = 'Propriétés disponibles', value = 'available_properties'}, } }, function(data, menu) if data.current.value == 'owned_properties' then OpenGatewayOwnedPropertiesMenu(property) end if data.current.value == 'available_properties' then OpenGatewayAvailablePropertiesMenu(property) end end, function(data, menu) menu.close() CurrentAction = 'gateway_menu' CurrentActionMsg = 'Appuez sur ~INPUT_CONTEXT~ pour accéder au menu' CurrentActionData = {property = property} end ) end end function OpenGatewayOwnedPropertiesMenu(property) local gatewayProperties = GetGatewayProperties(property) local elements = {} for i=1, #gatewayProperties, 1 do if PropertyIsOwned(gatewayProperties[i]) then table.insert(elements, { label = gatewayProperties[i].label, value = gatewayProperties[i].name }) end end ESX.UI.Menu.Open( 'default', GetCurrentResourceName(), 'gateway_owned_properties', { title = property.name .. ' - Propriétés Acquises', align = 'top-left', elements = elements, }, function(data, menu) menu.close() local elements = { {label = 'Entrer', value = 'enter'} } if not Config.EnablePlayerManagement then table.insert(elements, {label = 'Rendre', value = 'leave'}) end ESX.UI.Menu.Open( 'default', GetCurrentResourceName(), 'gateway_owned_properties_actions', { title = data.current.label, align = 'top-left', elements = elements, }, function(data2, menu) menu.close() if data2.current.value == 'enter' then EnterProperty(data.current.value) end if data2.current.value == 'leave' then TriggerServerEvent('esx_property:removeOwnedProperty', data.current.value) end end, function(data, menu) menu.close() end ) end, function(data, menu) menu.close() end ) end function OpenGatewayAvailablePropertiesMenu(property) local gatewayProperties = GetGatewayProperties(property) local elements = {} for i=1, #gatewayProperties, 1 do if not PropertyIsOwned(gatewayProperties[i]) then table.insert(elements, { label = gatewayProperties[i].label .. ' $' .. gatewayProperties[i].price, value = gatewayProperties[i].name, price = gatewayProperties[i].price }) end end ESX.UI.Menu.Open( 'default', GetCurrentResourceName(), 'gateway_available_properties', { title = property.name.. ' - Propriétés Disponbibles', align = 'top-left', elements = elements, }, function(data, menu) menu.close() ESX.UI.Menu.Open( 'default', GetCurrentResourceName(), 'gateway_available_properties_actions', { title = property.name, align = 'top-left', elements = { {label = 'Acheter', value = 'buy'}, {label = 'Louer', value = 'rent'}, {label = 'Visiter', value = 'visit'}, }, }, function(data2, menu) menu.close() if data2.current.value == 'buy' then TriggerServerEvent('esx_property:buyProperty', data.current.value) end if data2.current.value == 'rent' then TriggerServerEvent('esx_property:rentProperty', data.current.value) end if data2.current.value == 'visit' then EnterProperty(data.current.value) end end, function(data, menu) menu.close() end ) end, function(data, menu) menu.close() end ) end function OpenRoomMenu(property) local entering = nil if property.isSingle then entering = property.entering else entering = GetGateway(property).entering end ESX.UI.Menu.CloseAll() ESX.UI.Menu.Open( 'default', GetCurrentResourceName(), 'room', { title = property.label, align = 'top-left', elements = { {label = 'Inviter un joueur', value = 'invite_player'}, {label = 'Dressing', value = 'player_dressing'}, {label = 'Retirer objet', value = 'room_inventory'}, {label = 'Déposer objet', value = 'player_inventory'}, }, }, function(data, menu) if data.current.value == 'invite_player' then local playersInArea = ESX.Game.GetPlayersInArea(entering, 10.0) local elements = {} for i=1, #playersInArea, 1 do if playersInArea[i] ~= PlayerId() then table.insert(elements, {label = GetPlayerName(playersInArea[i]), value = playersInArea[i]}) end end ESX.UI.Menu.Open( 'default', GetCurrentResourceName(), 'room_invite', { title = property.label .. ' - Invite', align = 'top-left', elements = elements, }, function(data, menu) TriggerEvent('instance:invite', GetPlayerServerId(data.current.value), property.inside) end, function(data, menu) menu.close() end ) end if data.current.value == 'player_dressing' then ESX.TriggerServerCallback('esx_property:getPlayerDressing', function(dressing) local elements = {} for i=1, #dressing, 1 do table.insert(elements, {label = dressing[i].label, value = dressing[i].skin}) end ESX.UI.Menu.Open( 'default', GetCurrentResourceName(), 'player_dressing', { title = property.label .. ' - Dressing', align = 'top-left', elements = elements, }, function(data, menu) TriggerEvent('skinchanger:getSkin', function(skin) TriggerEvent('skinchanger:loadClothes', skin, data.current.value) TriggerEvent('skinchanger:getSkin', function(skin) TriggerServerEvent('esx_skin:save', skin) end) end) end, function(data, menu) menu.close() end ) end) end if data.current.value == 'room_inventory' then OpenRoomInventoryMenu(property) end if data.current.value == 'player_inventory' then OpenPlayerInventoryMenu(property) end end, function(data, menu) menu.close() CurrentAction = 'room_menu' CurrentActionMsg = 'Appuez sur ~INPUT_CONTEXT~ pour accéder au menu' CurrentActionData = {property = property} end ) end function OpenRoomInventoryMenu(property) ESX.TriggerServerCallback('esx_property:getPropertyInventory', function(inventory) local elements = {} table.insert(elements, {label = 'Argent sale $' .. inventory.blackMoney, type = 'item_account', value = 'black_money'}) for i=1, #inventory.items, 1 do local item = inventory.items[i] if item.count > 0 then table.insert(elements, {label = item.label .. ' x' .. item.count, type = 'item_standard', value = item.name}) end end for i=1, #inventory.weapons, 1 do local weapon = inventory.weapons[i] table.insert(elements, {label = ESX.GetWeaponLabel(weapon.name) .. ' [' .. weapon.ammo .. ']', type = 'item_weapon', value = weapon.name, ammo = weapon.ammo}) end ESX.UI.Menu.Open( 'default', GetCurrentResourceName(), 'room_inventory', { title = property.label .. ' - Inventaire', align = 'top-left', elements = elements, }, function(data, menu) if data.current.type == 'item_weapon' then menu.close() TriggerServerEvent('esx_property:getItem', data.current.type, data.current.value, data.current.ammo) ESX.SetTimeout(300, function() OpenRoomInventoryMenu(property) end) else ESX.UI.Menu.Open( 'dialog', GetCurrentResourceName(), 'get_item_count', { title = 'Quantité ?', }, function(data2, menu) local quantity = tonumber(data2.value) if quantity == nil then ESX.ShowNotification('Montant invalide') else menu.close() TriggerServerEvent('esx_property:getItem', data.current.type, data.current.value, quantity) ESX.SetTimeout(300, function() OpenRoomInventoryMenu(property) end) end end, function(data2,menu) menu.close() end ) end end, function(data, menu) menu.close() end ) end) end function OpenPlayerInventoryMenu(property) ESX.TriggerServerCallback('esx_property:getPlayerInventory', function(inventory) local elements = {} table.insert(elements, {label = 'Argent sale $' .. inventory.blackMoney, type = 'item_account', value = 'black_money'}) for i=1, #inventory.items, 1 do local item = inventory.items[i] if item.count > 0 then table.insert(elements, {label = item.label .. ' x' .. item.count, type = 'item_standard', value = item.name}) end end local playerPed = GetPlayerPed(-1) local weaponList = ESX.GetWeaponList() for i=1, #weaponList, 1 do local weaponHash = GetHashKey(weaponList[i].name) if HasPedGotWeapon(playerPed, weaponHash, false) and weaponList[i].name ~= 'WEAPON_UNARMED' then local ammo = GetAmmoInPedWeapon(playerPed, weaponHash) table.insert(elements, {label = weaponList[i].label .. ' [' .. ammo .. ']', type = 'item_weapon', value = weaponList[i].name, ammo = ammo}) end end ESX.UI.Menu.Open( 'default', GetCurrentResourceName(), 'player_inventory', { title = property.label .. ' - Inventaire', align = 'top-left', elements = elements, }, function(data, menu) if data.current.type == 'item_weapon' then menu.close() TriggerServerEvent('esx_property:putItem', data.current.type, data.current.value, data.current.ammo) ESX.SetTimeout(300, function() OpenPlayerInventoryMenu(property) end) else ESX.UI.Menu.Open( 'dialog', GetCurrentResourceName(), 'put_item_count', { title = 'Quantité ?', }, function(data2, menu) menu.close() TriggerServerEvent('esx_property:putItem', data.current.type, data.current.value, tonumber(data2.value)) ESX.SetTimeout(300, function() OpenPlayerInventoryMenu(property) end) end, function(data2,menu) menu.close() end ) end end, function(data, menu) menu.close() end ) end) end local FirstSpawn = true AddEventHandler('playerSpawned', function() if FirstSpawn then ESX.TriggerServerCallback('esx_property:getLastProperty', function(propertyName) if propertyName ~= nil then EnterProperty(propertyName) end end) FirstSpawn = false end end) AddEventHandler('esx_property:getProperties', function(cb) cb(GetProperties()) end) AddEventHandler('esx_property:getProperty', function(name, cb) cb(GetProperty(name)) end) AddEventHandler('esx_property:getGateway', function(property, cb) cb(GetGateway(property)) end) RegisterNetEvent('esx_property:setPropertyOwned') AddEventHandler('esx_property:setPropertyOwned', function(name, owned) SetPropertyOwned(name, owned) end) RegisterNetEvent('esx:playerLoaded') AddEventHandler('esx:playerLoaded', function(xPlayer) ESX.TriggerServerCallback('esx_property:getOwnedProperties', function(ownedProperties) for i=1, #ownedProperties, 1 do SetPropertyOwned(ownedProperties[i], true) end end) end) AddEventHandler('esx_property:hasEnteredMarker', function(name, part) local property = GetProperty(name) if part == 'entering' then if property.isSingle then CurrentAction = 'property_menu' CurrentActionMsg = 'Appuez sur ~INPUT_CONTEXT~ pour accéder au menu' CurrentActionData = {property = property} else CurrentAction = 'gateway_menu' CurrentActionMsg = 'Appuez sur ~INPUT_CONTEXT~ pour accéder au menu' CurrentActionData = {property = property} end end if part == 'exit' then ExitProperty(name) end if part == 'roomMenu' then CurrentAction = 'room_menu' CurrentActionMsg = 'Appuez sur ~INPUT_CONTEXT~ pour accéder au menu' CurrentActionData = {property = property} end end) AddEventHandler('esx_property:hasExitedMarker', function(name, part) ESX.UI.Menu.CloseAll() CurrentAction = nil end) -- Init Citizen.CreateThread(function() while ESX == nil do TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) Citizen.Wait(0) end ESX.TriggerServerCallback('esx_property:getProperties', function(properties) Config.Properties = properties CreateBlips() end) end) -- Display markers Citizen.CreateThread(function() while true do Wait(0) local coords = GetEntityCoords(GetPlayerPed(-1)) for i=1, #Config.Properties, 1 do local property = Config.Properties[i] if(property.entering ~= nil and not property.disabled and GetDistanceBetweenCoords(coords, property.entering.x, property.entering.y, property.entering.z, true) < Config.DrawDistance) then DrawMarker(Config.MarkerType, property.entering.x, property.entering.y, property.entering.z, 0.0, 0.0, 0.0, 0, 0.0, 0.0, Config.MarkerSize.x, Config.MarkerSize.y, Config.MarkerSize.z, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, false, false, false, false) end if(property.exit ~= nil and not property.disabled and GetDistanceBetweenCoords(coords, property.exit.x, property.exit.y, property.exit.z, true) < Config.DrawDistance) then DrawMarker(Config.MarkerType, property.exit.x, property.exit.y, property.exit.z, 0.0, 0.0, 0.0, 0, 0.0, 0.0, Config.MarkerSize.x, Config.MarkerSize.y, Config.MarkerSize.z, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, false, false, false, false) end if(property.roomMenu ~= nil and PropertyIsOwned(property) and not property.disabled and GetDistanceBetweenCoords(coords, property.roomMenu.x, property.roomMenu.y, property.roomMenu.z, true) < Config.DrawDistance) then DrawMarker(Config.MarkerType, property.roomMenu.x, property.roomMenu.y, property.roomMenu.z, 0.0, 0.0, 0.0, 0, 0.0, 0.0, Config.MarkerSize.x, Config.MarkerSize.y, Config.MarkerSize.z, Config.RoomMenuMarkerColor.r, Config.RoomMenuMarkerColor.g, Config.RoomMenuMarkerColor.b, 100, false, true, 2, false, false, false, false) end end end end) -- Enter / Exit marker events Citizen.CreateThread(function() while true do Wait(0) local coords = GetEntityCoords(GetPlayerPed(-1)) local isInMarker = false local currentProperty = nil local currentPart = nil for i=1, #Config.Properties, 1 do local property = Config.Properties[i] if(property.entering ~= nil and not property.disabled and GetDistanceBetweenCoords(coords, property.entering.x, property.entering.y, property.entering.z, true) < Config.MarkerSize.x) then isInMarker = true currentProperty = property.name currentPart = 'entering' end if(property.exit ~= nil and not property.disabled and GetDistanceBetweenCoords(coords, property.exit.x, property.exit.y, property.exit.z, true) < Config.MarkerSize.x) then isInMarker = true currentProperty = property.name currentPart = 'exit' end if(property.inside ~= nil and not property.disabled and GetDistanceBetweenCoords(coords, property.inside.x, property.inside.y, property.inside.z, true) < Config.MarkerSize.x) then isInMarker = true currentProperty = property.name currentPart = 'inside' end if(property.outside ~= nil and not property.disabled and GetDistanceBetweenCoords(coords, property.outside.x, property.outside.y, property.outside.z, true) < Config.MarkerSize.x) then isInMarker = true currentProperty = property.name currentPart = 'outside' end if(property.roomMenu ~= nil and PropertyIsOwned(property) and not property.disabled and GetDistanceBetweenCoords(coords, property.roomMenu.x, property.roomMenu.y, property.roomMenu.z, true) < Config.MarkerSize.x) then isInMarker = true currentProperty = property.name currentPart = 'roomMenu' end end if isInMarker and not HasAlreadyEnteredMarker or (isInMarker and (LastProperty ~= currentProperty or LastPart ~= currentPart) ) then HasAlreadyEnteredMarker = true LastProperty = currentProperty LastPart = currentPart TriggerEvent('esx_property:hasEnteredMarker', currentProperty, currentPart) end if not isInMarker and HasAlreadyEnteredMarker then HasAlreadyEnteredMarker = false TriggerEvent('esx_property:hasExitedMarker', LastProperty, LastPart) end end end) -- Key controls Citizen.CreateThread(function() while true do Citizen.Wait(0) if CurrentAction ~= nil then SetTextComponentFormat('STRING') AddTextComponentString(CurrentActionMsg) DisplayHelpTextFromStringLabel(0, 0, 1, -1) if IsControlPressed(0, Keys['E']) and (GetGameTimer() - GUI.Time) > 300 then if CurrentAction == 'property_menu' then OpenPropertyMenu(CurrentActionData.property) end if CurrentAction == 'gateway_menu' then if Config.EnablePlayerManagement then OpenGatewayOwnedPropertiesMenu(CurrentActionData.property) else OpenGatewayMenu(CurrentActionData.property) end end if CurrentAction == 'room_menu' then OpenRoomMenu(CurrentActionData.property) end CurrentAction = nil GUI.Time = GetGameTimer() end end end end)