DRS Motel

v1.9.2 drs_motel
Ver na loja

Motéis com quartos arrendados ao dia ou comprados. Cada jogador novo pode receber um quarto inicial grátis e depois arrendar quartos noutros motéis. Cada quarto tem interior privado (numa dimensão própria), cofre, roupeiro com roupas guardadas, chaves para amigos, campainha, rusga da polícia e parque privado. Os motéis criam-se e editam-se em jogo. Funciona com Qbox, QBCore e ESX.

#Requisitos

RecursoObrigatório
oxmysqlSim
Qbox, QBCore ou ESXSim (deteção automática)
ox_target ou qb-targetNão — sem target usa a tecla E com marcador no chão
ox_inventory ou qb-inventoryNão — sem eles o cofre usa a janela própria da DRS (funciona com qualquer inventário)
illenium-appearance, fivem-appearance ou skinchangerNão — o roupeiro também funciona com as roupas nativas do GTA

#Instalação

  1. Coloca drs_motel em resources.
  2. Adiciona ao server.cfg, depois do oxmysql e da framework:
server.cfg
ensure oxmysql
ensure qb-core
ensure drs_motel
  1. As tabelas são criadas sozinhas no primeiro arranque. Se preferires criá-las à mão, importa o sql/drs_motel.sql.
  2. Para a rusga da polícia, cria o item police_stormram (ou muda Config.Raid.item).
  3. Dá acesso ao criador de motéis à tua staff (os grupos de admin da framework já têm):
server.cfg
add_ace group.admin drs.motel allow

#Como funciona

#Arrendar, comprar e prolongar

Na porta de um quarto livre escolhes arrendar (preço por dia, price) ou comprar (buyPrice), conforme o Config.Mode ('rent', 'buy' ou 'both'). Cada motel pode ter o seu próprio mode. Pagas em dinheiro ou banco, e podes prolongar o arrendamento na porta ou dentro do quarto. Ao entrar na cidade recebes um aviso quando faltam menos de Config.ExpireWarningHours horas.

LimiteOpção
Quartos por pessoa no total (conta o inicial)Config.MaxRooms
Quartos por pessoa em cada motelConfig.RoomsPerMotel
Máximo de dias pagos de uma vezConfig.MaxDays

#Quarto inicial

Com Config.StarterRoom.enabled = true, cada jogador novo recebe (uma vez) um quarto grátis no motel Config.StarterRoom.motel. Com days = 0 nunca acaba; com outro valor acaba ao fim desses dias e pode ser prolongado a pagar.

#Vender o quarto

  • Ao banco: recebes Config.Sell.bankPercent% do valor (comprado = % do preço; arrendado = % dos dias que faltam; o quarto inicial não vale nada).
  • A um jogador perto: escolhes o preço e o comprador aceita com Y ou recusa com X. Fica retida a comissão Config.Sell.playerFee%.

#Dentro do quarto

  • Interior privado: cada quarto numa dimensão própria. Quem sai do jogo dentro do quarto volta à porta.
  • Cofre e roupeiro: só se abrem nos seus pontos dentro do quarto. O cofre fica vazio quando o arrendamento acaba.
  • Roupeiro: guardar a roupa vestida, vestir, mudar o nome e apagar (até Config.MaxOutfits).

#Chaves e campainha

O dono dá e tira chaves a quem está perto (até Config.MaxKeys). Quem tem chave entra e usa o cofre, o roupeiro e o parque. Na campainha, quem está dentro recebe um aviso com contagem e abre com Y ou ignora com X.

#Rusga da polícia

Os empregos de Config.Raid.jobs, com o item police_stormram, arrombam a porta em duration segundos. A porta fica aberta minutes minutos para qualquer pessoa entrar e o dono é avisado.

#Parque privado

Um carro por quarto num lugar livre do motel. O carro aparece trancado para todos e só quem tem acesso o tira. Quando o arrendamento acaba, volta à garagem. A staff tira um carro com /motelremovercarro [matrícula].

#Criador de motéis

/motelcriador abre o criador (staff): criar, editar e apagar motéis, pôr as portas e os lugares de parque onde estás e fazer TP para cada ponto.

TeclaAção
EColocar o ponto onde estás
BACKSPACEDesfazer o último
ENTERTerminar

Os motéis criados em jogo ficam guardados na base de dados.

#Comandos

ComandoQuemO que faz
/motelTodosOs teus quartos, com o tempo que falta e GPS
/motelcriadorStaffCriador de motéis
/motelremovercarro [matrícula]StaffTira um carro do parque

#Opções principais

OpçãoPor defeitoDescrição
Config.Locale'pt'Idioma: pt ou en
Config.Mode'rent'rent, buy ou both
Config.MaxRooms3Quartos por pessoa (0 = sem limite)
Config.StarterRoom.enabledtrueQuarto inicial grátis
Config.Society.enabledfalseParte de cada pagamento para uma empresa
Config.Stash'auto'ox_inventory, qb-inventory, builtin ou custom
Config.Wardrobe'builtin'builtin, illenium ou custom
Config.Raid.enabledtrueRusga da polícia
Config.Parking.enabledtrueParque privado
Config.Interaction'auto'ox_target, qb-target ou key

#Configuração completa

config.lua
Config = {}

-- Idioma / Language: 'pt' ou 'en'
Config.Locale = 'pt'

-- Framework: 'auto' deteta Qbox/QBCore/ESX (ou 'qbx' | 'qb' | 'esx')
Config.Framework = 'auto'

-- Moeda mostrada na interface / Currency shown in the UI
Config.Currency = '€'

-- Como se interage com as portas, o cofre e o roupeiro: 'auto' (ox_target > qb-target > tecla) | 'ox_target' | 'qb-target' | 'key'
-- How doors, stash and wardrobe are used
Config.Interaction = 'auto'
Config.InteractKey = 38            -- E
Config.InteractKeyLabel = 'E'
-- Marcador no chão em modo tecla (false = sem marcador) / Ground marker in key mode
Config.Marker = { type = 20, size = 0.25, color = { 245, 158, 11, 160 } }

Config.UseOxNotify = false         -- notificações do ox_lib / ox_lib notifications

-- ------------------------------------------------------------------ arrendar ou comprar / rent or buy
-- 'rent' = arrendar ao dia (price) | 'buy' = comprar (buyPrice, é teu para sempre) | 'both' = o jogador escolhe
-- Cada motel pode ter o seu: mode = 'buy' dentro do motel, em baixo.
-- Each motel can override it with its own `mode`.
Config.Mode = 'rent'

-- Vender o quarto / Selling the room
-- bankPercent: o banco paga esta % do valor (comprado = % do buyPrice; arrendado = % dos dias que faltam; o inicial não vale nada)
-- playerFee: % que fica retida quando vendes a outro jogador (vai para Config.Society se estiver ligada)
-- The bank pays bankPercent % of the value; playerFee % is kept when selling to another player
Config.Sell = { bankPercent = 80, toPlayer = true, playerFee = 10, offerTimeout = 30 }

-- ------------------------------------------------------------------ arrendamento / renting
Config.MaxDays = 50                -- máximo de dias pagos de uma vez / most days paid ahead
Config.QuickDays = { 1, 3, 7, 14, 30 }
Config.MaxRooms = 3                -- quartos por pessoa no total, com o inicial (0 = sem limite) / rooms per person overall, starter included (0 = no limit)
Config.RoomsPerMotel = 1           -- quartos por pessoa em cada motel / rooms per person in each motel

-- Quarto inicial: cada pessoa recebe (uma vez) um quarto grátis neste motel quando entra na cidade sem quarto.
-- Depois pode arrendar quartos nos outros motéis, até Config.MaxRooms.
-- days = 0: o quarto inicial nunca acaba; days > 0: acaba ao fim desses dias (e pode ser prolongado a pagar).
-- Starter room: everyone gets (once) a free room at this motel when they join without one. days = 0 never ends.
-- enabled = false: os jogadores novos NÃO recebem quarto (têm de arrendar ou comprar) / new players get NO room
Config.StarterRoom = {
    enabled = true,       -- true = jogador novo recebe um quarto grátis / new players get a free room
    motel = 'pinkcage',   -- id do motel (Config.Motels ou criado in-game) / motel id
    days = 0,             -- 0 = sem fim / never ends
}
Config.ExpireWarningHours = 24     -- avisa ao entrar na cidade quando faltam menos horas / warns on join when fewer hours are left

-- Parte do pagamento que vai para uma empresa (ex.: imobiliária). enabled = false desliga.
-- Share of every payment sent to a business account (e.g. real estate). enabled = false turns it off.
Config.Society = { enabled = false, account = 'realestate', percent = 50 }

-- ------------------------------------------------------------------ quarto / room
Config.MaxKeys = 5                 -- pessoas com chave por quarto / key holders per room
Config.KeyDistance = 5.0           -- distância para dar a chave / distance to give a key
Config.BucketBase = 5000           -- cada quarto usa a dimensão BucketBase + id / each room uses routing bucket BucketBase + id

-- Campainha: só quem está dentro do quarto a ouve (false = dono e chaves em qualquer sítio da cidade)
-- Doorbell: only people inside the room hear it (false = owner and key holders anywhere in the city)
Config.Doorbell = { onlyInside = true, timeout = 15, cooldown = 10, acceptKey = 246, acceptLabel = 'Y', denyKey = 73, denyLabel = 'X' }

-- Cofre: 'auto' (ox_inventory > qb-inventory > builtin) | 'ox_inventory' | 'qb-inventory' | 'builtin' | 'custom' (server/editable.lua)
-- Stash: 'builtin' is the DRS stash window (works with any inventory)
-- O cofre fica vazio quando o arrendamento acaba / The stash is emptied when the rent ends
Config.Stash = 'auto'

-- Roupeiro: 'builtin' (roupas guardadas no quarto) | 'illenium' | 'custom' (client/editable.lua)
-- Wardrobe: 'builtin' saves outfits in the room
Config.Wardrobe = 'builtin'
Config.MaxOutfits = 20

-- ------------------------------------------------------------------ polícia / police
-- A polícia com o item pode arrombar a porta: fica aberta durante `minutes` para qualquer pessoa entrar.
-- Police with the item can break the door: it stays open for `minutes` for anyone to enter.
Config.Raid = {
    enabled = true,
    jobs = { 'police', 'sheriff' },
    item = 'police_stormram',      -- nil = não precisa de item / no item needed
    removeItem = false,
    duration = 5,                  -- segundos a arrombar / seconds breaking the door
    minutes = 1,                   -- minutos com a porta aberta / minutes the door stays open
}

-- ------------------------------------------------------------------ parque / parking
Config.Parking = {
    enabled = true,
    distance = 2.5,                -- distância ao lugar / distance to the spot
    ownedOnly = true,              -- só veículos teus (owned_vehicles / player_vehicles) / only owned vehicles
    staffCommand = 'motelremovercarro', -- /motelremovercarro [matrícula] tira um carro do parque (staff)
}

-- Comando para ver os teus quartos com GPS ('' = desligado) / Command listing your rooms with GPS ('' = off)
Config.RoomsCommand = 'motel'

Config.Blip = { sprite = 475, color = 47, scale = 0.7 }

-- ------------------------------------------------------------------ criador in-game / in-game creator
-- /motelcriador abre o criador (staff: ACE `ace` ou grupos de admin). Os motéis criados ficam na base de dados.
-- /motelcriador opens the creator (staff). Motels made there are saved in the database.
Config.Creator = {
    command = 'motelcriador',
    ace = 'drs.motel',
    addKey = 38, addLabel = 'E',          -- colocar aqui / place here
    undoKey = 177, undoLabel = 'BACKSPACE', -- desfazer o último / undo last
    doneKey = 191, doneLabel = 'ENTER',   -- terminar / finish
}

-- ------------------------------------------------------------------ interiores / interiors
-- entry: onde entras (e sais) / where you spawn inside; stash e wardrobe: pontos dentro do quarto
Config.Interiors = {
    standard = {
        entry = vector4(151.4, -1007.88, -99.0, 0.0),
        stash = vector3(151.31, -1003.13, -99.0),
        wardrobe = vector3(151.77, -1001.33, -99.0),
        slots = 50,
        weight = 100000,
    },
}

-- ------------------------------------------------------------------ motéis / motels
-- id: único e sem espaços (fica guardado na base de dados) / unique, no spaces (saved in the database)
-- rooms: id do quarto e posição da porta / room id and door position
-- parking: lugares (x, y, z, direção) / spots (x, y, z, heading)
-- center + radius: zona onde os carros estacionados aparecem / area where parked cars are shown
-- blip = false esconde o blip deste motel / hides this motel's blip
-- mode = 'rent' | 'buy' | 'both' muda o modo só deste motel / changes the mode of this motel only
Config.Motels = {
    {
        id = 'perrera',
        label = 'Perrera Beach',
        price = 500,          -- arrendar: preço por dia / rent: price per day
        buyPrice = 25000,     -- comprar: preço do quarto / buy: price of the room
        interior = 'standard',
        center = vector3(-1472.8, -658.85, 29.11),
        radius = 30.0,
        rooms = {
            { id = '1', door = vector3(-1493.75, -668.37, 29.03) },
            { id = '2', door = vector3(-1498.18, -664.7, 29.03) },
            { id = '3', door = vector3(-1495.36, -661.59, 29.03) },
            { id = '4', door = vector3(-1490.77, -658.24, 29.03) },
            { id = '5', door = vector3(-1486.78, -655.37, 29.58) },
            { id = '6', door = vector3(-1482.18, -652.01, 29.58) },
            { id = '7', door = vector3(-1478.22, -649.14, 29.58) },
            { id = '8', door = vector3(-1473.65, -645.8, 29.58) },
            { id = '9', door = vector3(-1469.65, -642.92, 29.58) },
            { id = '10', door = vector3(-1465.08, -639.58, 29.58) },
            { id = '11', door = vector3(-1461.26, -640.85, 29.58) },
            { id = '12', door = vector3(-1452.36, -653.24, 29.58) },
            { id = '13', door = vector3(-1454.36, -655.97, 29.58) },
            { id = '14', door = vector3(-1458.98, -659.32, 29.58) },
            { id = '15', door = vector3(-1462.96, -662.18, 29.58) },
            { id = '16', door = vector3(-1467.54, -665.56, 29.58) },
            { id = '17', door = vector3(-1471.54, -668.43, 29.58) },
            { id = '18', door = vector3(-1461.45, -641.04, 33.38) },
            { id = '19', door = vector3(-1457.92, -645.51, 33.38) },
            { id = '20', door = vector3(-1455.71, -648.62, 33.38) },
            { id = '21', door = vector3(-1452.48, -653.29, 33.38) },
            { id = '22', door = vector3(-1454.4, -655.94, 33.38) },
            { id = '23', door = vector3(-1458.93, -659.31, 33.38) },
            { id = '24', door = vector3(-1462.92, -662.2, 33.38) },
            { id = '25', door = vector3(-1467.5, -665.53, 33.38) },
            { id = '26', door = vector3(-1471.55, -668.36, 33.38) },
            { id = '27', door = vector3(-1476.11, -671.79, 33.38) },
            { id = '28', door = vector3(-1465.02, -639.63, 33.38) },
            { id = '29', door = vector3(-1469.68, -642.98, 33.38) },
            { id = '30', door = vector3(-1473.61, -645.89, 33.38) },
            { id = '31', door = vector3(-1478.17, -649.13, 33.38) },
            { id = '32', door = vector3(-1482.19, -652.03, 33.38) },
            { id = '33', door = vector3(-1486.78, -655.34, 33.38) },
            { id = '34', door = vector3(-1490.77, -658.25, 33.38) },
            { id = '35', door = vector3(-1495.3, -661.55, 33.38) },
            { id = '36', door = vector3(-1498.1, -664.7, 33.38) },
            { id = '37', door = vector3(-1493.75, -668.29, 33.38) },
            { id = '38', door = vector3(-1489.9, -671.46, 33.38) },
        },
        parking = {
            vector4(-1465.87, -648.57, 28.5, 35.47),
            vector4(-1468.57, -650.68, 28.5, 35.37),
            vector4(-1471.41, -652.78, 28.5, 33.28),
            vector4(-1480.69, -659.38, 27.94, 34.88),
            vector4(-1483.36, -661.61, 27.94, 33.91),
            vector4(-1486.08, -663.68, 27.94, 35.97),
            vector4(-1478.01, -657.2, 27.94, 35.64),
        },
    },
    {
        id = 'pinkcage',
        label = 'The Pink Cage',
        price = 500,          -- arrendar: preço por dia / rent: price per day
        buyPrice = 25000,     -- comprar: preço do quarto / buy: price of the room
        interior = 'standard',
        center = vector3(326.0, -211.15, 54.09),
        radius = 30.0,
        rooms = {
            { id = '1', door = vector3(312.85, -218.86, 54.22) },
            { id = '2', door = vector3(311.01, -218.04, 54.22) },
            { id = '3', door = vector3(307.45, -216.68, 54.22) },
            { id = '4', door = vector3(307.47, -213.27, 54.22) },
            { id = '5.1', door = vector3(309.5, -207.98, 54.22) },
            { id = '5.2', door = vector3(311.31, -203.45, 54.22) },
            { id = '6', door = vector3(313.34, -198.14, 54.22) },
            { id = '7', door = vector3(315.75, -194.9, 54.23) },
            { id = '8', door = vector3(319.4, -196.31, 54.23) },
            { id = '9', door = vector3(321.36, -197.09, 54.23) },
            { id = '11', door = vector3(312.9, -218.81, 58.02) },
            { id = '12', door = vector3(310.86, -218.09, 58.02) },
            { id = '13', door = vector3(307.29, -216.75, 58.02) },
            { id = '14', door = vector3(307.58, -213.3, 58.02) },
            { id = '15', door = vector3(309.51, -207.96, 58.02) },
            { id = '16', door = vector3(311.26, -203.37, 58.02) },
            { id = '17', door = vector3(313.33, -198.07, 58.02) },
            { id = '18', door = vector3(315.84, -194.88, 58.02) },
            { id = '19', door = vector3(319.39, -196.13, 58.02) },
            { id = '20', door = vector3(321.45, -196.93, 58.02) },
            { id = '21', door = vector3(329.39, -225.16, 54.22) },
            { id = '22', door = vector3(331.32, -225.97, 54.22) },
            { id = '23', door = vector3(334.9, -227.37, 54.22) },
            { id = '24', door = vector3(337.18, -224.79, 54.22) },
            { id = '25', door = vector3(339.18, -219.46, 54.22) },
            { id = '26', door = vector3(340.99, -214.91, 54.22) },
            { id = '27', door = vector3(343.01, -209.57, 54.22) },
            { id = '28', door = vector3(344.74, -205.03, 54.22) },
            { id = '29', door = vector3(346.8, -199.73, 54.22) },
            { id = '30', door = vector3(329.37, -225.19, 58.02) },
            { id = '31', door = vector3(331.34, -225.94, 58.02) },
            { id = '32', door = vector3(334.97, -227.34, 58.02) },
            { id = '33', door = vector3(337.15, -224.85, 58.02) },
            { id = '34', door = vector3(339.21, -219.51, 58.02) },
            { id = '35', door = vector3(340.98, -214.92, 58.02) },
            { id = '36', door = vector3(342.99, -209.67, 58.02) },
            { id = '37', door = vector3(344.75, -205.04, 58.02) },
            { id = '39', door = vector3(346.81, -199.73, 58.02) },
        },
        parking = {
            vector4(337.48, -207.39, 53.09, 250.31),
            vector4(336.36, -210.66, 53.09, 250.31),
            vector4(335.22, -213.88, 53.09, 250.31),
            vector4(334.05, -217.05, 53.09, 250.31),
            vector4(314.93, -209.41, 53.09, 67.59),
            vector4(316.08, -206.15, 53.09, 67.59),
            vector4(317.51, -203.02, 53.09, 67.59),
            vector4(318.56, -199.69, 53.09, 67.59),
        },
    },
    {
        id = 'bilingsgate',
        label = 'Bilingsgate',
        price = 500,          -- arrendar: preço por dia / rent: price per day
        buyPrice = 25000,     -- comprar: preço do quarto / buy: price of the room
        interior = 'standard',
        center = vector3(565.73, -1762.93, 29.17),
        radius = 50.0,
        rooms = {
            { id = '1', door = vector3(566.18, -1778.16, 29.35) },
            { id = '2', door = vector3(550.31, -1775.52, 29.31) },
            { id = '3', door = vector3(552.2, -1771.52, 29.31) },
            { id = '4', door = vector3(554.65, -1766.26, 29.31) },
            { id = '5', door = vector3(557.7, -1759.64, 29.31) },
            { id = '6', door = vector3(561.38, -1751.79, 29.28) },
            { id = '7', door = vector3(560.15, -1777.17, 33.44) },
            { id = '8', door = vector3(559.09, -1777.35, 33.44) },
            { id = '10', door = vector3(550.09, -1770.55, 33.44) },
            { id = '11', door = vector3(552.6, -1765.24, 33.44) },
            { id = '12', door = vector3(555.6, -1758.64, 33.44) },
            { id = '14', door = vector3(559.3, -1750.81, 33.44) },
            { id = '15', door = vector3(561.75, -1747.38, 33.44) },
        },
        parking = {
            vector4(567.46, -1799.15, 28.19, 170.95),
            vector4(564.35, -1798.98, 28.2, 170.56),
            vector4(561.38, -1798.52, 28.2, 170.14),
            vector4(558.33, -1798.24, 28.2, 173.09),
            vector4(555.26, -1797.74, 28.2, 171.69),
            vector4(552.26, -1797.26, 28.2, 169.95),
            vector4(549.18, -1796.66, 28.2, 171.47),
            vector4(545.07, -1794.89, 28.2, 171.47),
            vector4(561.23, -1789.0, 28.2, 334.09),
            vector4(558.45, -1787.92, 28.2, 335.03),
            vector4(555.56, -1786.83, 28.2, 335.19),
            vector4(545.02, -1781.77, 28.12, 334.57),
            vector4(542.09, -1780.59, 27.97, 334.21),
        },
    },
    {
        id = 'motor',
        label = 'The Motor',
        price = 500,          -- arrendar: preço por dia / rent: price per day
        buyPrice = 25000,     -- comprar: preço do quarto / buy: price of the room
        interior = 'standard',
        center = vector3(1125.89, 2653.3, 38.0),
        radius = 30.0,
        rooms = {
            { id = '1', door = vector3(1142.4, 2654.69, 38.15) },
            { id = '2', door = vector3(1142.42, 2651.12, 38.14) },
            { id = '3', door = vector3(1142.32, 2643.58, 38.14) },
            { id = '4', door = vector3(1141.15, 2641.68, 38.14) },
            { id = '5', door = vector3(1136.34, 2641.64, 38.14) },
            { id = '6', door = vector3(1132.75, 2641.64, 38.14) },
            { id = '7', door = vector3(1125.22, 2641.64, 38.14) },
            { id = '8', door = vector3(1121.35, 2641.74, 38.14) },
            { id = '9', door = vector3(1114.67, 2641.74, 38.14) },
            { id = '10', door = vector3(1107.16, 2641.64, 38.14) },
            { id = '11', door = vector3(1106.01, 2649.04, 38.14) },
            { id = '12', door = vector3(1106.14, 2652.9, 38.14) },
        },
        parking = {
            vector4(1097.97, 2663.28, 36.96, 179.76),
            vector4(1101.54, 2663.26, 36.97, 180.6),
            vector4(1105.27, 2663.24, 36.97, 178.45),
            vector4(1111.8, 2657.94, 36.99, 89.36),
            vector4(1111.67, 2654.31, 37.0, 88.74),
            vector4(1116.53, 2648.04, 37.0, 179.22),
            vector4(1120.26, 2647.54, 37.0, 178.72),
            vector4(1123.88, 2647.65, 37.0, 179.35),
            vector4(1127.53, 2647.94, 37.0, 179.94),
            vector4(1131.26, 2647.72, 37.0, 177.5),
            vector4(1135.23, 2647.61, 37.0, 178.44),
        },
    },
    {
        id = 'eastern',
        label = 'Eastern',
        price = 500,          -- arrendar: preço por dia / rent: price per day
        buyPrice = 25000,     -- comprar: preço do quarto / buy: price of the room
        interior = 'standard',
        center = vector3(366.34, 2635.42, 44.5),
        radius = 30.0,
        rooms = {
            { id = '1', door = vector3(341.69, 2614.92, 44.67) },
            { id = '2', door = vector3(346.93, 2618.21, 44.68) },
            { id = '3', door = vector3(354.3, 2619.83, 44.67) },
            { id = '4', door = vector3(359.82, 2622.81, 44.67) },
            { id = '5', door = vector3(367.2, 2624.53, 44.67) },
            { id = '6', door = vector3(372.54, 2627.56, 44.67) },
            { id = '7', door = vector3(379.89, 2629.25, 44.67) },
            { id = '8', door = vector3(385.27, 2632.34, 44.67) },
            { id = '9', door = vector3(392.63, 2634.01, 44.67) },
            { id = '10', door = vector3(398.0, 2637.22, 44.67) },
        },
        parking = {
            vector4(336.83, 2619.06, 43.5, 207.68),
            vector4(341.77, 2622.29, 43.51, 210.12),
            vector4(348.36, 2624.71, 43.5, 209.53),
            vector4(353.97, 2627.8, 43.5, 210.82),
            vector4(360.88, 2629.57, 43.5, 210.82),
            vector4(366.48, 2631.84, 43.5, 214.33),
            vector4(373.86, 2634.07, 43.5, 210.59),
            vector4(379.0, 2637.0, 43.5, 211.51),
            vector4(386.37, 2638.51, 43.5, 212.29),
            vector4(391.86, 2641.65, 43.49, 209.54),
        },
    },
    {
        id = 'dreamview',
        label = 'Dream View',
        price = 500,          -- arrendar: preço por dia / rent: price per day
        buyPrice = 25000,     -- comprar: preço do quarto / buy: price of the room
        interior = 'standard',
        center = vector3(-81.11, 6340.18, 31.49),
        radius = 30.0,
        rooms = {
            { id = '1', door = vector3(-111.16, 6322.78, 31.58) },
            { id = '2', door = vector3(-114.33, 6326.08, 31.58) },
            { id = '3', door = vector3(-120.16, 6327.2, 31.58) },
            { id = '4', door = vector3(-111.06, 6322.73, 35.5) },
            { id = '5', door = vector3(-114.34, 6326.08, 35.5) },
            { id = '6', door = vector3(-120.23, 6327.27, 35.5) },
            { id = '7', door = vector3(-103.45, 6330.73, 31.58) },
            { id = '8', door = vector3(-106.71, 6333.93, 31.58) },
            { id = '9', door = vector3(-107.58, 6339.78, 31.58) },
            { id = '11', door = vector3(-99.01, 6348.49, 31.58) },
            { id = '12', door = vector3(-93.52, 6353.97, 31.58) },
            { id = '13', door = vector3(-90.22, 6357.23, 31.58) },
            { id = '14', door = vector3(-84.87, 6362.6, 31.58) },
            { id = '15', door = vector3(-103.42, 6330.65, 35.5) },
            { id = '16', door = vector3(-106.74, 6333.96, 35.5) },
            { id = '17', door = vector3(-107.52, 6339.82, 35.5) },
            { id = '18', door = vector3(-102.25, 6345.25, 35.5) },
            { id = '19', door = vector3(-98.93, 6348.43, 35.5) },
            { id = '20', door = vector3(-93.54, 6353.95, 35.5) },
            { id = '21', door = vector3(-90.2, 6357.16, 35.5) },
            { id = '22', door = vector3(-84.83, 6362.67, 35.5) },
        },
        parking = {
            vector4(-100.84, 6339.27, 30.49, 44.01),
            vector4(-98.22, 6342.0, 30.49, 44.18),
            vector4(-95.55, 6344.58, 30.49, 43.43),
            vector4(-92.92, 6347.16, 30.49, 44.47),
            vector4(-90.33, 6349.89, 30.49, 44.85),
            vector4(-87.41, 6352.4, 30.49, 46.06),
            vector4(-84.48, 6355.16, 30.49, 46.06),
            vector4(-81.79, 6358.05, 30.49, 46.06),
            vector4(-72.34, 6358.36, 30.49, 314.27),
            vector4(-69.69, 6355.42, 30.49, 313.46),
            vector4(-66.73, 6352.75, 30.49, 313.97),
            vector4(-64.01, 6349.93, 30.49, 313.14),
            vector4(-61.33, 6347.22, 30.49, 313.73),
            vector4(-58.59, 6344.58, 30.49, 313.84),
            vector4(-72.03, 6342.08, 30.49, 44.35),
            vector4(-74.67, 6339.12, 30.49, 43.52),
            vector4(-77.23, 6336.39, 30.49, 43.49),
            vector4(-79.86, 6333.63, 30.49, 43.49),
            vector4(-85.37, 6338.87, 30.49, 223.05),
            vector4(-82.88, 6341.74, 30.49, 222.98),
            vector4(-80.18, 6344.5, 30.49, 223.2),
            vector4(-77.42, 6347.11, 30.49, 223.01),
        },
    },
}

#Base de dados

drs_motel.sql
-- DRS Motel — as tabelas também são criadas sozinhas no arranque / tables are also created on start

-- quartos arrendados ou comprados (expires_at = 0: não acaba) / rented or bought rooms (expires_at = 0: never ends)
-- os preços estão no config.lua (price, buyPrice) ou no motel criado in-game / prices live in config.lua or the in-game motel
CREATE TABLE IF NOT EXISTS drs_motel_rooms (
    id INT NOT NULL AUTO_INCREMENT,
    motel VARCHAR(50) NOT NULL,
    room VARCHAR(10) NOT NULL,
    owner VARCHAR(64) NOT NULL,
    owner_name VARCHAR(100) NOT NULL DEFAULT '',
    expires_at INT NOT NULL,
    created_at INT NOT NULL,
    kind VARCHAR(10) NOT NULL DEFAULT 'rent',   -- rent | buy | starter
    paid INT NOT NULL DEFAULT 0,                -- quanto foi pago / amount paid
    PRIMARY KEY (id),
    UNIQUE KEY motel_room (motel, room),
    KEY owner (owner)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- chaves dadas pelo dono / keys given by the owner
CREATE TABLE IF NOT EXISTS drs_motel_keys (
    room_id INT NOT NULL,
    identifier VARCHAR(64) NOT NULL,
    name VARCHAR(100) NOT NULL DEFAULT '',
    PRIMARY KEY (room_id, identifier)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- roupas guardadas no roupeiro / outfits saved in the wardrobe
CREATE TABLE IF NOT EXISTS drs_motel_outfits (
    id INT NOT NULL AUTO_INCREMENT,
    room_id INT NOT NULL,
    name VARCHAR(40) NOT NULL,
    model BIGINT NOT NULL DEFAULT 0,
    data LONGTEXT NOT NULL,
    PRIMARY KEY (id),
    KEY room_id (room_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- veículos estacionados (um por quarto) / parked vehicles (one per room)
CREATE TABLE IF NOT EXISTS drs_motel_parking (
    room_id INT NOT NULL,
    motel VARCHAR(50) NOT NULL,
    spot INT NOT NULL,
    plate VARCHAR(16) NOT NULL,
    props LONGTEXT NOT NULL,
    PRIMARY KEY (room_id),
    UNIQUE KEY motel_spot (motel, spot)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- cofre DRS (Config.Stash = 'builtin') / DRS stash
CREATE TABLE IF NOT EXISTS drs_motel_stash (
    room_id INT NOT NULL,
    items LONGTEXT NOT NULL,
    PRIMARY KEY (room_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- motéis feitos no criador in-game / motels made in the in-game creator
CREATE TABLE IF NOT EXISTS drs_motel_motels (
    id VARCHAR(50) NOT NULL,
    data LONGTEXT NOT NULL,
    PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

#Para programadores

servidor
exports.drs_motel:GetPlayerRooms(identifier) -- { { motel, room, owner, expires } } (expires = 0: sem fim)
exports.drs_motel:GetInsideRoom(source)      -- { motel, room } ou nil

O server/editable.lua e o client/editable.lua não são encriptados: empresa, posse de veículos, garagem, chaves do carro, combustível, cofre e roupeiro próprios.

#Segurança

Tudo é validado no servidor: distância à porta, estar dentro do quarto, acesso (dono, chave ou rusga), dinheiro, itens e limites. A rusga tem de durar o tempo todo no servidor e a campainha só serve uma vez. Se dois jogadores arrendarem o mesmo quarto ao mesmo tempo, a base de dados só aceita um e o outro recebe o dinheiro de volta.

#Resolução de problemas

Não consigo abrir o cofre — o cofre só abre no ponto dele, dentro do quarto. Confirma que tens acesso (dono ou chave).

O jogador novo não recebeu quarto — confirma Config.StarterRoom.enabled = true e que o motel existe (no config.lua ou criado em jogo).

O /motelcriador não abre — falta a permissão: add_ace group.admin drs.motel allow.

A polícia não consegue arrombar — tem de ter um emprego de Config.Raid.jobs e o item police_stormram.