DRS Phone
Telemóvel completo ao estilo iOS: chamadas e videochamadas ao vivo, mensagens, câmara, App Store, redes sociais, Spotify, Wallet, crypto com preços reais e mais de 25 apps.
Telemóvel completo ao estilo iOS para FiveM: chamadas e videochamadas, mensagens, câmara, App Store, redes sociais, música, Spotify, Wallet, crypto com preços reais e muito mais. Funciona com Qbox, QBCore e ESX, e todas as tabelas da base de dados são criadas sozinhas no primeiro arranque.
Dica
Podes experimentar o telemóvel no teu browser na página do produto, antes de comprar.
#Requisitos
| Recurso | Obrigatório | Para quê |
|---|---|---|
oxmysql | Sim | Base de dados |
qbx_core / qb-core / es_extended | Sim (um deles) | Framework (deteção automática) |
pma-voice | Recomendado | Voz nas chamadas e videochamadas |
xsound | Opcional | App Música (YouTube / SoundCloud) |
ox_inventory | Opcional | Item phone (ou Config.Item = nil) |
Servidor com OneSync (a versão gratuita chega).
#Instalação
- Mete a pasta
drs_phoneemresources. Não mudes o nome da pasta: os exports, a permissãodrs.phonee o endereço do Spotify usam-no. - Adiciona ao
server.cfg, por esta ordem:
ensure oxmysql
ensure pma-voice
ensure xsound
ensure drs_phone
# fotos da câmara e da galeria (webhook de um canal Discord)
set drs_phone_webhook "https://discord.com/api/webhooks/..."
# opcional: com um token de bot os links das fotos nunca expiram
set drs_discord_bot_token "TOKEN"- Cria o item
phoneno inventário (ou põeConfig.Item = nilpara não precisar de item):
['phone'] = { label = 'Telemóvel', weight = 190, server = { export = 'drs_phone.use' } },- Arranca o servidor. As tabelas criam-se sozinhas. Se o utilizador da base de dados não puder criar tabelas, importa o SQL à mão:
-- DRS Phone: tabelas da base de dados / database tables
-- O recurso cria-as sozinho no arranque; este ficheiro é só para quem prefere importar à mão.
-- The resource creates them on start; this file is only for importing by hand.
CREATE TABLE IF NOT EXISTS drs_phone_users (
identifier VARCHAR(64) NOT NULL PRIMARY KEY,
number VARCHAR(20) NOT NULL UNIQUE,
settings LONGTEXT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS drs_phone_contacts (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
owner VARCHAR(64) NOT NULL,
name VARCHAR(50) NOT NULL,
number VARCHAR(20) NOT NULL,
favourite TINYINT(1) NOT NULL DEFAULT 0,
INDEX (owner)
);
CREATE TABLE IF NOT EXISTS drs_phone_messages (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
sender VARCHAR(20) NOT NULL,
receiver VARCHAR(20) NOT NULL,
body TEXT NULL,
media INT NULL,
seen TINYINT(1) NOT NULL DEFAULT 0,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX (sender), INDEX (receiver)
);
CREATE TABLE IF NOT EXISTS drs_phone_calls (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
caller VARCHAR(20) NOT NULL,
callee VARCHAR(20) NOT NULL,
answered TINYINT(1) NOT NULL DEFAULT 0,
duration INT NOT NULL DEFAULT 0,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX (caller), INDEX (callee)
);
CREATE TABLE IF NOT EXISTS drs_phone_media (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
channel VARCHAR(32) NULL,
message VARCHAR(32) NULL,
url TEXT NOT NULL,
expires INT NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS drs_phone_gallery (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
owner VARCHAR(64) NOT NULL,
media INT NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX (owner)
);
CREATE TABLE IF NOT EXISTS drs_phone_notes (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
owner VARCHAR(64) NOT NULL,
title VARCHAR(80) NOT NULL,
body TEXT NULL,
updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX (owner)
);
CREATE TABLE IF NOT EXISTS drs_phone_social (
identifier VARCHAR(64) NOT NULL,
app VARCHAR(20) NOT NULL,
username VARCHAR(20) NOT NULL,
display VARCHAR(40) NOT NULL,
bio VARCHAR(160) NULL,
avatar INT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (identifier, app),
UNIQUE KEY app_username (app, username)
);
CREATE TABLE IF NOT EXISTS drs_phone_posts (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
app VARCHAR(20) NOT NULL,
author VARCHAR(64) NOT NULL,
body TEXT NULL,
media INT NULL,
parent INT NULL,
likes INT NOT NULL DEFAULT 0,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX (app, parent), INDEX (author)
);
CREATE TABLE IF NOT EXISTS drs_phone_likes (
post INT NOT NULL,
identifier VARCHAR(64) NOT NULL,
PRIMARY KEY (post, identifier)
);
CREATE TABLE IF NOT EXISTS drs_phone_music (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
owner VARCHAR(64) NOT NULL,
title VARCHAR(120) NOT NULL,
url VARCHAR(255) NOT NULL,
thumb VARCHAR(255) NULL,
INDEX (owner)
);
CREATE TABLE IF NOT EXISTS drs_phone_spotify (
identifier VARCHAR(64) NOT NULL PRIMARY KEY,
access_token TEXT NOT NULL,
refresh_token TEXT NOT NULL,
expires INT NOT NULL
);
CREATE TABLE IF NOT EXISTS drs_phone_scores (
identifier VARCHAR(64) NOT NULL,
game VARCHAR(20) NOT NULL,
name VARCHAR(60) NOT NULL,
score INT NOT NULL,
updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (identifier, game),
INDEX (game, score)
);
CREATE TABLE IF NOT EXISTS drs_phone_mail_accounts (
identifier VARCHAR(64) NOT NULL PRIMARY KEY,
address VARCHAR(80) NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS drs_phone_mails (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
sender VARCHAR(80) NOT NULL,
recipient VARCHAR(80) NOT NULL,
subject VARCHAR(120) NOT NULL,
body TEXT NULL,
media INT NULL,
seen TINYINT(1) NOT NULL DEFAULT 0,
del_sender TINYINT(1) NOT NULL DEFAULT 0,
del_recipient TINYINT(1) NOT NULL DEFAULT 0,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX (recipient), INDEX (sender)
);
CREATE TABLE IF NOT EXISTS drs_phone_listings (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
app VARCHAR(20) NOT NULL,
owner VARCHAR(64) NOT NULL,
name VARCHAR(60) NOT NULL,
number VARCHAR(20) NOT NULL,
title VARCHAR(80) NOT NULL,
body TEXT NULL,
price INT NULL,
media INT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX (app, created), INDEX (owner)
);
CREATE TABLE IF NOT EXISTS drs_phone_spark (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
identifier VARCHAR(64) NOT NULL UNIQUE,
name VARCHAR(40) NOT NULL,
age INT NOT NULL,
bio VARCHAR(300) NULL,
media INT NULL,
active TINYINT(1) NOT NULL DEFAULT 1
);
CREATE TABLE IF NOT EXISTS drs_phone_spark_swipes (
profile INT NOT NULL,
target INT NOT NULL,
liked TINYINT(1) NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (profile, target)
);
CREATE TABLE IF NOT EXISTS drs_phone_dark_users (
identifier VARCHAR(64) NOT NULL PRIMARY KEY,
alias VARCHAR(30) NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS drs_phone_dark_members (
channel VARCHAR(30) NOT NULL,
identifier VARCHAR(64) NOT NULL,
PRIMARY KEY (channel, identifier), INDEX (identifier)
);
CREATE TABLE IF NOT EXISTS drs_phone_dark_messages (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
channel VARCHAR(30) NOT NULL,
alias VARCHAR(30) NOT NULL,
body TEXT NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX (channel, id)
);
CREATE TABLE IF NOT EXISTS drs_phone_crypto_prices (
coin VARCHAR(64) NOT NULL PRIMARY KEY,
price DOUBLE NOT NULL,
history LONGTEXT NULL
);
CREATE TABLE IF NOT EXISTS drs_phone_crypto_wallet (
identifier VARCHAR(64) NOT NULL,
coin VARCHAR(64) NOT NULL,
amount DOUBLE NOT NULL DEFAULT 0,
PRIMARY KEY (identifier, coin)
);
CREATE TABLE IF NOT EXISTS drs_phone_bank_tx (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
owner VARCHAR(64) NOT NULL,
amount INT NOT NULL,
label VARCHAR(100) NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX (owner, id)
);- Na consola aparece o logótipo do DRS Phone com a lista de módulos (
[ OK ]/[ !! ]) e se estás na versão mais recente. Uma linha com[ !! ]diz exatamente o que falta.
#Abrir o telemóvel
- Tecla por defeito F1 (cada jogador pode mudar em Definições → Teclas → FiveM) ou o comando
/telemovel. - Com
Config.Item, só abre com o item no inventário. Morto ou algemado não abre (Config.CanOpen).
#Apps
| App | O que faz |
|---|---|
| Telefone | Teclado, recentes, favoritos e contactos. Chamadas por voz (pma-voice). Números de serviço tocam em todos os que estão em serviço. |
| Vídeo | Videochamadas em direto entre jogadores, a qualquer distância. |
| Mensagens | Conversas com fotos e localização partilhada (toca para marcar no GPS). |
| Câmara / Galeria | Foto e selfie com visor ao vivo; fotos favoritas; usar como fundo; enviar por mensagem. |
| Wallet | Cartão do banco e dinheiro, transferências por número e histórico de transações. |
| App Store | O telemóvel vem só com as apps básicas; as outras instalam-se aqui. |
| Definições | Como num iPhone: Wi-Fi, Bluetooth, notificações por app, sons, AirDrop, aspeto claro/escuro, acessibilidade, armazenamento… |
| Relógio | Relógio mundial, alarmes (hora da cidade), cronómetro e temporizador. |
| Tempo, Mapas, Serviços | Tempo do jogo com previsão, mapa com locais e GPS, números de serviço com quem está de serviço. |
| Crypto | As 30 maiores moedas com preços reais (CoinGecko). |
| Birdy, InstaPic, Trendy, Spark, DarkChat | Redes sociais, encontros e canais anónimos. |
| Pages, Marketplace, Mail | Anúncios, coisas à venda e email nome@drs.pt. |
| Música, Spotify, Jogos | xsound em coluna ou auscultadores, comando do Spotify, 4 jogos com ranking. |
| Garagem, Notas, Calculadora | Carros com GPS até eles, notas e calculadora. |
Extras do sistema: ecrã bloqueado com notificações agrupadas e botões de ação, Central de Controlo (4 páginas, editável), seletor de apps (mantém premida a barra de baixo), modo de edição do ecrã principal (mantém premido um ícone), botões laterais (silêncio, volume, bloquear) e Dynamic Island.
#Videochamadas
O vídeo vai direto de jogador para jogador (WebRTC); o servidor só passa as mensagens de ligação. Durante a chamada a personagem segura o telemóvel e o jogo mostra a câmara do telemóvel do GTA. A voz continua pelo pma-voice.
A maioria dos jogadores liga-se com os servidores STUN públicos que já vêm no config. Jogadores em redes muito fechadas precisam de um servidor TURN; sem ele, a chamada continua só com voz.
Config.VideoCalls = {
enabled = true,
fps = 15,
width = 270, height = 480,
iceServers = {
{ urls = 'stun:stun.l.google.com:19302' },
-- { urls = 'turn:o-teu-servidor:3478', username = 'user', credential = 'pass' },
},
}#Câmara
A câmara abre dentro do telemóvel com o visor ao vivo. As fotos (810×1080, ao alto) vão para o canal do Discord do webhook drs_phone_webhook. Sem drs_discord_bot_token as fotos funcionam, mas o Discord faz expirar os links ao fim de uns dias; com o token o link é renovado sozinho.
#App Store
O telemóvel vem só com as apps de Config.AppStore.base; as outras instalam-se e apagam-se na App Store (ou mantendo premido o ícone). Fica guardado por personagem. enabled = false mostra todas as apps.
#Spotify
Cada servidor precisa da sua própria app do Spotify:
- Em developer.spotify.com → Create app (Web API). Copia o Client ID para
Config.Spotify.clientId(não é preciso Client Secret). - Na app → Settings → Redirect URIs, cola o link que a consola mostra quando o recurso arranca (
https://xxxx.users.cfx.re/drs_phone/spotify/callback). Tem de ficar exatamente igual; o telemóvel também o mostra no ecrã de login. - Em User Management, adiciona o nome e o email Spotify de cada jogador (até 25 em modo de desenvolvimento).
- Controlar a música precisa de Spotify Premium.
Nota
Se o login não ligar, a consola mostra cada passo ([drs_phone] spotify: ...) e o telemóvel diz o motivo: acesso recusado, Redirect URI errado ou conta fora da lista.
#Crypto
Preços reais do CoinGecko, um pedido a cada 5 minutos partilhado por todos os jogadores. Sem stablecoins nem cópias de outras moedas. Se a API falhar, ficam os últimos preços guardados.
Config.Crypto = {
enabled = true,
count = 30, -- quantas moedas
currency = 'eur', -- deve bater com Config.Currency
refresh = 300, -- segundos
fee = 0.015, -- comissão por operação
}Opcional: uma chave "Demo" grátis do CoinGecko no server.cfg → set drs_coingecko_key "CG-...".
#Partilhar contacto
Na Central de Controlo → Partilhar: envia o teu contacto a quem está a menos de Config.Share.distance metros. O outro jogador vê um cartão e escolhe Guardar ou Recusar. Nas Definições → Geral → AirDrop cada jogador escolhe quem lhe pode enviar (ninguém, só contactos, todos).
#Aparelho e versão
Config.Device = {
model = 'DRS Pro Max 17',
storageGB = 1000, -- 1000 = 1 TB
}O servidor verifica sozinho se há versão nova (ao arrancar e a cada 6 horas). Quando há, avisa na consola e o telemóvel mostra um "1" vermelho nas Definições → Geral → Atualização de software.
#Exports
exports.drs_phone:GetNumber(source)
exports.drs_phone:GetSourceByNumber('912345678')
exports.drs_phone:SendMessage('Banco', '912345678', 'O teu cartão está pronto.')
exports.drs_phone:Notify(source, 'Título', 'Texto', 'bank')
exports.drs_phone:SendMail('multas@lspd.gov', 'ana@drs.pt', 'Multa', 'Texto…')
exports.drs_phone:GetMailAddress(source)
exports.drs_phone:IsInCall(source)
exports.drs_phone:EndCall(source)
exports.drs_phone:StopMusic(source)exports.drs_phone:Open()
exports.drs_phone:Close()
exports.drs_phone:IsOpen()
-- Central de Controlo → Casa: liga luzes, portas, garagens… de outros scripts
AddEventHandler('drs_phone:homeControl', function(id, on)
-- id: 'lights' | 'lock' | 'heat' | 'plug' | 'camera' | 'garage'
end)#Permissões
Quem tiver a ACE drs.phone pode apagar qualquer post ou anúncio.
add_ace group.admin drs.phone allow#Configuração completa
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 app do banco / Currency shown in the bank app
Config.Currency = '€'
-- ------------------------------------------------------------------ abrir / open
-- Tecla por defeito (cada jogador pode mudar em Definições > Teclas > FiveM)
-- Default key (each player can change it in Settings > Key Bindings > FiveM)
Config.OpenKey = 'F1'
Config.Command = 'telemovel'
-- Item necessário para usar o telemóvel (nil = não precisa de item)
-- Item needed to use the phone (nil = no item needed)
Config.Item = 'phone'
-- Animação e prop do jogo base (sem streaming) / Base-game animation and prop (nothing to stream)
Config.Prop = 'prop_npc_phone_02'
-- ------------------------------------------------------------------ números / numbers
-- Números de 9 dígitos a começar por um destes prefixos (ex.: 912 345 678)
-- 9-digit numbers starting with one of these prefixes
Config.NumberPrefixes = { '91', '92', '93', '96' }
Config.NumberLength = 9
-- ------------------------------------------------------------------ chamadas / calls
Config.RingSeconds = 30 -- tempo a tocar antes de dar chamada perdida / ring time before a missed call
Config.CallChannelOffset = 5000 -- canais de chamada do pma-voice começam aqui / pma-voice call channels start here
-- Números de serviço: ligar ou mandar mensagem vai para todos os jogadores com estes empregos (em serviço)
-- Service numbers: calling or texting reaches every on-duty player with these jobs
-- icon (app Serviços): sos | police | ambulance | fire | mechanic | taxi | lawyer | news | phone (sem icon = adivinha pelo nome / guessed from the label)
Config.Services = {
['112'] = { label = 'Emergência', jobs = { 'police', 'ambulance' }, icon = 'sos' },
['113'] = { label = 'Mecânico', jobs = { 'mechanic' }, icon = 'mechanic' },
['114'] = { label = 'Táxi', jobs = { 'taxi' }, icon = 'taxi' },
}
-- ------------------------------------------------------------------ videochamadas / video calls
-- O vídeo vai direto de jogador para jogador (WebRTC); o servidor só passa as mensagens de ligação.
-- A maioria liga-se com os servidores STUN públicos. Jogadores em redes muito fechadas precisam de um TURN
-- (há gratuitos/baratos, ex.: metered.ca ou o teu próprio coturn); sem ele a chamada continua só com voz.
-- Video goes straight from player to player (WebRTC); the server only passes the connection messages along.
-- Most players connect through the public STUN servers. Very strict networks need a TURN server; without it the call stays voice-only.
Config.VideoCalls = {
enabled = true,
fps = 15, -- imagens por segundo / frames per second
width = 270, height = 480, -- tamanho do vídeo enviado / size of the video sent
iceServers = {
{ urls = 'stun:stun.l.google.com:19302' },
{ urls = 'stun:stun1.l.google.com:19302' },
-- { urls = 'turn:o-teu-servidor:3478', username = 'user', credential = 'pass' },
},
}
-- ------------------------------------------------------------------ câmara / camera
-- Precisa do recurso screenshot-basic. O upload vai para um webhook do Discord definido no server.cfg:
-- set drs_phone_webhook "https://discord.com/api/webhooks/..."
-- Com um token de bot (o mesmo do drs_banking) as fotos nunca expiram, porque o link é renovado ao abrir:
-- set drs_discord_bot_token "TOKEN"
-- Needs screenshot-basic. Uploads go to a Discord webhook set in server.cfg (see above).
-- With a bot token the photos never expire, because the link is refreshed when opened.
Config.WebhookConvar = 'drs_phone_webhook'
Config.DiscordTokenConvar = 'drs_discord_bot_token'
Config.PhotoQuality = 0.85 -- 0.1 a 1.0 (jpg)
Config.GalleryLimit = 120 -- fotos guardadas por pessoa (as mais antigas saem) / photos kept per person
-- ------------------------------------------------------------------ banco / bank
Config.Bank = {
enabled = true,
maxTransfer = 250000, -- valor máximo por transferência / max per transfer
}
-- Recurso anti-exploit com SafeAddMoney/SafeRemoveMoney (ex.: o anti-cheat do teu servidor). nil = framework direto.
-- Anti-exploit resource exposing SafeAddMoney/SafeRemoveMoney. nil = framework directly.
Config.GuardResource = nil
-- ------------------------------------------------------------------ música / music (precisa do xsound / needs xsound)
Config.Music = {
enabled = true,
allowSpeaker = true, -- modo coluna: quem está perto ouve / speaker mode: people close can hear
distance = 15.0, -- alcance do modo coluna (metros) / speaker range (meters)
maxVolume = 0.6, -- volume máximo do xsound (0.0 a 1.0) / max xsound volume
librarySize = 100, -- músicas guardadas por pessoa / saved songs per person
allowedHosts = { 'youtube.com', 'youtu.be', 'soundcloud.com' },
}
-- ------------------------------------------------------------------ Spotify
-- Cada jogador liga a sua conta; a música toca no Spotify dele (PC ou telemóvel), o telemóvel do jogo é o comando.
-- Precisa de Spotify Premium para controlar. Cria a TUA app em developer.spotify.com e põe o Client ID abaixo:
-- 1. Redirect URIs: cola o link que aparece na consola quando o recurso arranca (tem de ficar exatamente igual)
-- 2. User Management: adiciona as contas dos jogadores (até 25 enquanto a app estiver em modo de desenvolvimento)
-- Each player links their own account; music plays on their own Spotify, the in-game phone is the remote.
-- Needs Spotify Premium. Add the Redirect URI printed in the console, and the players' accounts under User Management.
Config.Spotify = {
enabled = true,
clientId = 'f399d5130d33406e8c33ae10cbbfd14c',
redirectBase = nil, -- nil = endereço cfx.re do servidor (https://xxxx.users.cfx.re) / nil = the server's cfx.re address
}
-- ------------------------------------------------------------------ Mail, Pages, Marketplace, DarkChat
Config.MailDomain = 'drs.pt' -- os endereços ficam nome@drs.pt / addresses become name@drs.pt
Config.MailMaxLength = 4000
Config.ListingDays = 7 -- anúncios (Pages e Marketplace) apagam-se ao fim de X dias / ads expire after X days
Config.ListingMax = 5 -- anúncios ativos por pessoa em cada app / active ads per person per app
Config.DarkChatDays = 7 -- mensagens do DarkChat apagam-se ao fim de X dias / DarkChat messages expire after X days
-- ------------------------------------------------------------------ Garagem / Garage
-- Lê player_vehicles (Qbox/QBCore) ou owned_vehicles (ESX). Reads player_vehicles or owned_vehicles.
Config.Garage = { enabled = true }
-- ------------------------------------------------------------------ Crypto
-- Os preços mudam sozinhos (ao acaso) e compra-se com o dinheiro do banco. Prices move on their own; bought with bank money.
Config.Crypto = {
enabled = true,
-- Preços reais do CoinGecko: as maiores moedas por capitalização (sem stablecoins nem cópias como Wrapped BTC / stETH).
-- Real CoinGecko prices: the biggest coins by market cap (no stablecoins or copies like Wrapped BTC / stETH).
count = 30, -- quantas moedas mostrar / how many coins to show
currency = 'eur', -- moeda dos preços (eur, usd, gbp…) — deve bater com Config.Currency / must match Config.Currency
refresh = 300, -- segundos entre atualizações (mínimo 60) / seconds between updates (min 60)
-- Opcional: chave "Demo" grátis do CoinGecko no server.cfg → set drs_coingecko_key "CG-..."
-- Optional: free CoinGecko "Demo" key in server.cfg
apiKeyConvar = 'drs_coingecko_key',
fee = 0.015, -- comissão por compra/venda (1.5%) / fee per trade
maxTrade = 1000000, -- máximo por operação / max per trade
-- ids do CoinGecko que nunca aparecem (além das stablecoins apanhadas automaticamente)
-- CoinGecko ids that never show (on top of the stablecoins caught automatically)
exclude = { 'tether', 'usd-coin', 'dai', 'tether-gold', 'pax-gold', 'wrapped-bitcoin', 'weth', 'steth', 'wrapped-steth', 'coinbase-wrapped-btc', 'wrapped-eeth', 'binance-bridged-usdt-bnb-smart-chain', 'figure-heloc' },
}
-- ------------------------------------------------------------------ Mapas / Maps
-- Sítios na app Mapas (tocar = GPS) / Places in the Maps app (tap = waypoint)
Config.Places = {
{ label = 'Esquadra Mission Row', category = 'Serviços', x = 428.9, y = -981.3 },
{ label = 'Hospital Pillbox', category = 'Serviços', x = 298.6, y = -584.5 },
{ label = 'Mecânico LS Customs', category = 'Serviços', x = -365.4, y = -131.8 },
{ label = 'Legion Square', category = 'Cidade', x = 195.2, y = -933.9 },
{ label = 'Praia de Vespucci', category = 'Cidade', x = -1223.0, y = -1491.0 },
{ label = 'Aeroporto de LS', category = 'Cidade', x = -1037.0, y = -2737.0 },
{ label = 'Stand Premium Deluxe', category = 'Lojas', x = -56.9, y = -1098.8 },
{ label = 'Loja de roupa (Binco)', category = 'Lojas', x = 72.3, y = -1399.1 },
{ label = 'Sandy Shores', category = 'Norte', x = 1853.0, y = 3689.0 },
{ label = 'Paleto Bay', category = 'Norte', x = -276.0, y = 6230.0 },
}
-- ------------------------------------------------------------------ aparelho / device
-- Nome do modelo e capacidade que aparecem em Definições (Sobre, Armazenamento, Bluetooth)
-- Model name and storage shown in Settings (About, Storage, Bluetooth)
Config.Device = {
model = 'DRS Pro Max 17',
storageGB = 1000, -- 1000 = 1 TB
}
-- ------------------------------------------------------------------ app store
-- O telemóvel vem só com as apps de 'base'; as outras instalam-se na App Store (fica guardado por personagem).
-- enabled = false mostra todas as apps sem precisar de instalar.
-- The phone ships with the 'base' apps only; the rest are installed from the App Store (saved per character).
-- enabled = false shows every app without installing.
Config.AppStore = {
enabled = true,
base = {
'phone', 'messages', 'contacts', 'camera', 'gallery', 'settings', 'appstore',
'notes', 'calculator', 'clock', 'weather', 'maps', 'bank', 'services', 'video',
},
}
-- ------------------------------------------------------------------ partilhar contacto / share contact
-- Botão "Partilhar" na Central de Controlo: envia o teu contacto a quem está perto (o outro tem de aceitar).
-- showNames = false mostra só "Telemóvel perto" em vez do nome da personagem.
-- "Share" button in Control Center: sends your contact to people close by (they have to accept).
Config.Share = {
distance = 3.0,
showNames = true,
}
-- ------------------------------------------------------------------ outros / other
Config.MessageMaxLength = 500
Config.NoteMaxLength = 4000
Config.MaxContacts = 250
Config.Webhook = '' -- log de chamadas e transferências / calls and transfers log
Config.UseOxNotify = false
-- Pode abrir o telemóvel? (cliente) Muda aqui para bloquear algemado, etc.
-- Can the phone open? (client) Change this to block while cuffed, etc.
Config.CanOpen = function()
local ped = PlayerPedId()
if IsEntityDead(ped) or IsPedRagdoll(ped) then return false end
if LocalPlayer.state.isCuffed or LocalPlayer.state.handcuffed then return false end
if GetResourceState('drs_deathscreen') == 'started' then
local ok, s = pcall(function() return exports.drs_deathscreen:GetState() end)
if ok and s and s ~= 'alive' then return false end
end
return true
end#Problemas comuns
| Problema | Solução |
|---|---|
| O telemóvel não abre | Confirma o item phone (ou Config.Item = nil) e que não estás morto/algemado. |
| Fotos não guardam | Falta set drs_phone_webhook no server.cfg (a consola mostra [ !! ] Câmara). |
| Chamadas sem voz | O pma-voice tem de arrancar antes do drs_phone. |
| Videochamada só com voz | O jogador está numa rede muito fechada: acrescenta um servidor TURN em Config.VideoCalls.iceServers. |
| Spotify fica à espera | Confirma o Redirect URI e que a conta está em User Management (ver secção Spotify). |
| Exports não funcionam | A pasta tem de se chamar drs_phone. |