149 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| Utils.Zones = Utils.Zones or {}
 | |
| 
 | |
| -- We'll store all zones in a dictionary keyed by zone id
 | |
| local zones = {}
 | |
| 
 | |
| -- Generates a random, unused zone ID
 | |
| local function generateRandomZoneID()
 | |
|     while true do
 | |
|         -- e.g., "zone_123456789"
 | |
|         local attempt = "zone_" .. math.random(1, 999999999)
 | |
|         if not zones[attempt] then
 | |
|             return attempt
 | |
|         end
 | |
|     end
 | |
| end
 | |
| 
 | |
| --[[
 | |
| A zone looks like this internally:
 | |
| zones[id] = {
 | |
|     id             = string (unique)
 | |
|     coords         = vector3
 | |
|     radius         = number
 | |
|     onEnter        = function() end (optional)
 | |
|     onExit         = function() end (optional)
 | |
|     enabled        = bool (active or not)
 | |
|     isPlayerInside = bool (internal, tracks if player was inside last check)
 | |
| }
 | |
| ]]
 | |
| 
 | |
| ----------------------------------------------------------------------
 | |
| -- Create a zone
 | |
| -- Example usage:
 | |
| --   Utils.Zones.createZone({
 | |
| --       id             = "my_zone",  -- optional
 | |
| --       coords         = vector3(100.0, 200.0, 30.0),
 | |
| --       radius         = 50.0,
 | |
| --       onEnter        = function() ... end,
 | |
| --       onExit         = function() ... end,
 | |
| --   })
 | |
| ----------------------------------------------------------------------
 | |
| function Utils.Zones.createZone(opts)
 | |
|     opts = opts or {}
 | |
| 
 | |
|     local zoneId = opts.id
 | |
|     if not zoneId or zoneId == "" then
 | |
|         -- If the user didn't provide an id, generate one
 | |
|         zoneId = generateRandomZoneID()
 | |
|     end
 | |
| 
 | |
|     zones[zoneId] = {
 | |
|         id = zoneId,
 | |
|         coords = opts.coords or vector3(0.0, 0.0, 0.0),
 | |
|         radius = opts.radius or 50.0,
 | |
|         onEnter = opts.onEnter,
 | |
|         onExit = opts.onExit,
 | |
|         enabled = true,         -- zones are enabled by default
 | |
|         isPlayerInside = false,       -- internal tracking
 | |
|     }
 | |
| 
 | |
|     return zoneId -- Return the final ID so the caller knows what was assigned
 | |
| end
 | |
| 
 | |
| ----------------------------------------------------------------------
 | |
| -- Enable a zone by ID (it will begin checking distances, etc.)
 | |
| ----------------------------------------------------------------------
 | |
| function Utils.Zones.enableZone(id)
 | |
|     local zone = zones[id]
 | |
|     if zone then
 | |
|         zone.enabled = true
 | |
|     end
 | |
| end
 | |
| 
 | |
| ----------------------------------------------------------------------
 | |
| -- Disable a zone by ID (temporarily stops checks and triggers onExit if inside)
 | |
| ----------------------------------------------------------------------
 | |
| function Utils.Zones.disableZone(id)
 | |
|     local zone = zones[id]
 | |
|     if zone and zone.enabled then
 | |
|         zone.enabled = false
 | |
|         if zone.isPlayerInside then
 | |
|             zone.isPlayerInside = false
 | |
|             if zone.onExit then
 | |
|                 zone.onExit()
 | |
|             end
 | |
|         end
 | |
|     end
 | |
| end
 | |
| 
 | |
| ----------------------------------------------------------------------
 | |
| -- Remove a zone by ID entirely (triggers onExit if the player is inside)
 | |
| ----------------------------------------------------------------------
 | |
| function Utils.Zones.removeZone(id)
 | |
|     local zone = zones[id]
 | |
|     if zone then
 | |
|         if zone.isPlayerInside and zone.onExit then
 | |
|             zone.onExit()
 | |
|         end
 | |
|         zones[id] = nil
 | |
|     end
 | |
| end
 | |
| 
 | |
| ----------------------------------------------------------------------
 | |
| -- Update a zone's properties by ID. 
 | |
| -- For example:
 | |
| --   Utils.Zones.updateZone("my_zone", { radius = 80.0 })
 | |
| ----------------------------------------------------------------------
 | |
| function Utils.Zones.updateZone(id, newValues)
 | |
|     local zone = zones[id]
 | |
|     if not zone then return end
 | |
|     for k, v in pairs(newValues) do
 | |
|         zone[k] = v
 | |
|     end
 | |
| end
 | |
| 
 | |
| ----------------------------------------------------------------------
 | |
| -- Main loop: checks each enabled zone for player enter/exit, calls callbacks
 | |
| ----------------------------------------------------------------------
 | |
| CreateThread(function()
 | |
|     while true do
 | |
|         local playerPed = PlayerPedId()
 | |
|         local playerCoords = GetEntityCoords(playerPed)
 | |
| 
 | |
|         for _, zone in pairs(zones) do
 | |
|             if zone.enabled then
 | |
|                 local dist = #(playerCoords - zone.coords)
 | |
| 
 | |
|                 if dist < zone.radius then
 | |
|                     -- Player is inside this zone
 | |
|                     if not zone.isPlayerInside then
 | |
|                         zone.isPlayerInside = true
 | |
|                         if zone.onEnter then
 | |
|                             zone.onEnter()
 | |
|                         end
 | |
|                     end
 | |
|                 else
 | |
|                     -- Player is outside this zone
 | |
|                     if zone.isPlayerInside then
 | |
|                         zone.isPlayerInside = false
 | |
|                         if zone.onExit then
 | |
|                             zone.onExit()
 | |
|                         end
 | |
|                     end
 | |
|                 end
 | |
|             end
 | |
|         end
 | |
| 
 | |
|         Wait(1000)
 | |
|     end
 | |
| end)
 | 
