# Dicas
Source: https://docs.heyyshop.com.br/hints
Fique por dentro de algumas dicas gerais na utilização dos sistemas ou sobre alguns procedimentos recomendados.
Durante a utilização de nossos produtos, alguns procedimentos podem te ajudar a receber um melhor e mais rápido suporte, evitar problemas ou até mesmo trazer uma melhor jogabilidade para seus jogadores.
Segue abaixo uma lista de procedimentos, dicas e outras recomendações que vão te ajudar a manter seu servidor e nossos produtos rodando da melhor forma possível!
# 1. Reportar erros ou bugs
Após uma instalação, atualização ou até mesmo o uso comum dos nossos produtos, você pode se deparar com alguma mensagem de erro em alguns lugares:
* Console do cliente (F8);
* Console do servidor (txAdmin ou mesmo aquele CMD aberto na sua VPS);
* Na própria interface, no canto superior direito.
Algumas mensagens são mais importantes do que outras, mas o procedimento é padrão em todos os casos. Para receber um suporte rápido e eficaz, ao entrar em contato, forneça as seguintes informações:
* Quando o erro aconteceu (se tiver essa informação);
* Como o error aconteceu (se tiver essa informação);
* Os arquivos do script (TODOS ELES, não apenas o que está com erro ou aquele apareceu na mensagem);
* Um print do erro no console do servidor, se houver (não é do F8);
* Um print do erro no console do cliente (F8), se houver;
* Qual a sua base (por exemplo, Creative v5, Network, Extended etc.)
# 2. Servidor de Testes/Desenvolvimento
Recomendamos que você utilize um servidor de testes para a realização da instalação, atualização ou correção de erros nos scripts.
Desencorajamos a realização desses processos em servidores em produção (com jogadores), pois, muitas vezes, será necessário reiniciar os scripts (o que pode atrapalhar a jogabilidade de seus jogadores) ou até mesmo podem ocorrer erros (deixando algum sistema do servidor indisponível ou problemático).
# 3. Realizando atualizações
Após o lançamento do script, é normal que ocorram várias atualizações (nem sempre com a mesma frequência), que melhoram o funcionamento do script, adicionam funções ou, até mesmo, que modificam funções já existentes.
Quando essas atualizações são lançadas, nossos scripts são atualizados automaticamente, sem precisar de nenhuma ação sua. Entretanto, em alguns casos, principalmente quando há a adição de novas configurações ou até mesmo a modificação de alguma já existente, nossa equipe irá anunciar a atualização nos canais de download de cada produto, reenviando o script **COMPLETO** (com **TODOS** os arquivos atualizados) e fornecendo instruções, informando o que foi mudado e quais arquivos deverão ser atualizados manualmente.
Uma observação relevante é que: sempre vamos mencionar o cargo Cliente, para te notificar, quando uma atualização obrigatória ou importante for realizada.
**O que é uma atualização obrigatória?**
É uma atualização que, se não for feita, pode gerar mal funcionamento do produto ou causar erros, por exemplo.
Elas precisam ser feitas o mais rápido possível, para que, quando os arquivos principais do script sejam atualizados pelo atualizador automático e o script/servidor for reiniciado, as modificações que precisam ser realizadas manualmente já tenham sido realizadas por você, garantindo que ele continue funcionando de forma correta.
É importante que, **ANTES DE REALIZAR A ATUALIZAÇÃO**:
* Faça um backup do seu banco de dados;
* Faça um backup dos arquivos atuais do script (que estão rodando e funcionando na sua base);
Para a realização da **ATUALIZAÇÃO**:
* Caso solicite que um terceiro faça-a por você (um programador, sócio ou até um amigo, por exemplo), forneça o passo a passo dado por nossa equipe;
* Siga as instruções a risca (não pule ou ignore qualquer tópico ou passo a passo fornecido);
* Caso tenha alguma dúvida, entre imediatamente em contato conosco através do Discord, isso ajudará a evitar erros e acidentes;
Caso a atualização seja feita da forma incorreta, substituindo os arquivos de configurações ao invés de apenas adicionar/alterar o que foi adicionado/alterado/solicitado, é possível que isso resulte na perda de todas as alterações feitas para o script funcionar corretamente no seu servidor/base. Nesse caso, você precisará solicitar que nossa equipe realize a reinstalação completa do script, caso não haja backup, que seguirá nossos termos de instalação (ou seja, pode te gerar custos).
# Eventos
Source: https://docs.heyyshop.com.br/products/heyy_blipsystem/api/events
Integre nosso produto com outros scripts de seu servidor, deixando tudo muito mais legal e com sua cara.
## Server-side
### blipsystem:registerPlayer
Esse evento pode ser disparado para adicionar um jogador ao sistema de *blipsystem*, ou atualizá-lo, caso já esteja nele.
Esse evento normalmente é utilizado ao entrar em serviço.
**Parâmetros:**
* source: `integer`
* role: `string`
* true caso queira iniciar a contagem de horas, e false caso queira finalizá-la.
* canSeeRoles: `string[]`
* Lista de grupos que o jogador pode exergar no mapa.
* Exemplo: Caso a lista seja **Policia** e **Hospital** o jogador poderá enxergar em seu mapa qualquer pessoa que estiver registrada com ***role*** de **Policia** ou **Hospital**. Qualquer outra pessoa registrada com outro ***role*** não será vista.
* options
* name: `string`
* Nome do blip no mapa.
* sprite: `integer`
* Ícone do blip no mapa. Veja a [lista completa](https://docs.fivem.net/docs/game-references/blips/#blips).
* color: `integer`
* Cor do blip no mapa. Veja a [lista completa](https://docs.fivem.net/docs/game-references/blips/#blip-colors).
* showHeading: `boolean`
* Se o blip exibirá para que lado o jogador está olhando.
* showVehicle: `boolean`
* Se o ícone do blip será influenciado pelo veículo que o jogador está utilizando.
**Exemplo de uso:**
```lua theme={null}
TriggerEvent(
"blipsystem:registerPlayer", source,
"Policia", { "Policia", "Hospital" },
{
name = "Policial",
sprite = 63,
color = 3,
showHeading = true,
showVehicle = true,
}
)
```
### blipsystem:unregisterPlayer
Esse evento pode ser disparado para remover um jogador do sistema de *blipsystem*.
Esse evento normalmente é utilizado ao sair de serviço.
**Parâmetros:**
* source: `integer`
**Exemplo de uso:**
```lua theme={null}
TriggerEvent("blipsystem:unregisterPlayer", source)
```
# Eventos
Source: https://docs.heyyshop.com.br/products/heyy_hospital/api/events
Integre nosso produto com outros scripts de seu servidor, deixando tudo muito mais legal e com sua cara.
## Client-side
### heyy\_hospital:openUI
Ao disparar esse evento o tablet será aberto, caso o jogador tenha permissão para isso.
**Exemplo de uso:**
```lua theme={null}
-- client-side
TriggerEvent("heyy_hospital:openUI")
-- server-side
TriggerClientEvent("heyy_hospital:openUI", source)
```
### heyy\_hospital:onTabletOpen
> Esse evento é exclusivamente de leitura, dispará-lo não fará nenhum evento dentro do script.
Esse evento é disparado toda vez que o tablet é aberto. Um exemplo básico de uso (que é utilizado por nós) é remover arma da mão do jogador para que a animação fique correta, por exemplo.
**Exemplo de uso:**
```lua theme={null}
AddEventHandler("heyy_hospital:onTabletOpen", function()
-- seu código
end)
```
### heyy\_hospital:closeUI
Ao disparar esse evento o tablet é fechado.
**Exemplo de uso:**
```lua theme={null}
-- client-side
TriggerEvent("heyy_hospital:closeUI")
-- server-side
TriggerClientEvent("heyy_hospital:closeUI", source)
```
## Server-side
### heyy\_hospital:setOnDuty
Esse evento pode ser disparado para iniciar ou finalizar a contagem de horas em serviço.
Ele normalmente é utilizado ao entrar/sair de serviço.
**Parâmetros:**
* user\_id: `integer`
* status: `boolean`
* true caso queira iniciar a contagem de horas, e false caso queira finalizá-la.
**Exemplo de uso:**
```lua theme={null}
TriggerEvent("heyy_hospital:setOnDuty", user_id, status)
```
# Exports
Source: https://docs.heyyshop.com.br/products/heyy_hospital/api/exports
Integre nosso produto com outros scripts de seu servidor, deixando tudo muito mais legal e com sua cara.
## Client-side
### isUiOpen
Retorna se a interface está ou não aberta.
**Exemplo de uso:**
```lua theme={null}
local isOpen = exports.heyy_hospital:isUiOpen()
```
## Server-side
### getPlayerData
Retorna a informação `key` do jogador especificado.
**Parâmetros:**
* user\_id: `integer`
* key: `string`
* A informação que você deseja obter
**Retorna:**
* data: `string`
**Exemplo de uso:**
```lua theme={null}
local value = exports.heyy_hospital:getPlayerData(user_id, "exemplo")
```
### setPlayerData
Define o valor da informação `key` para o jogador especificado.
**Parâmetros:**
* user\_id: `integer`
* key: `string`
* A informação que você deseja atualizar
* value: `string`
* O novo valor para essa informação
**Exemplo de uso:**
```lua theme={null}
exports.heyy_hospital:setPlayerData(user_id, "exemplo", "novo_valor")
```
# Statebags
Source: https://docs.heyyshop.com.br/products/heyy_hospital/api/statebags
Integre nosso produto com outros scripts de seu servidor, deixando tudo muito mais legal e com sua cara.
Os *state bags* são utilizados para sincronizar informações entre clientes e o servidor. Para saber mais detalhes e como utilizar, você pode [ler mais sobre os StateBags aqui](https://docs.fivem.net/docs/scripting-manual/networking/state-bags/).
## Resumo
| Statebag | Tipo | Descrição |
| -------- | ------- | ---------------------------------- |
| plaster | boolean | Se o jogador está engessado ou não |
## Lista completa
### plaster
Pode ser utilizado para verificar se o jogador está preso.
**Exemplo de uso:**
```lua theme={null}
-- client-side
if LocalPlayer.state.plaster then
-- seu código
end
-- server-side
if Player(source).state.plaster then
-- seu código
end
```
# Apresentação
Source: https://docs.heyyshop.com.br/products/heyy_hospital/features
Conheça nosso Tablet Policial e as funções que vão diferenciar seu servidor de outros que seus jogadores já jogaram!
Nosso tablet conta com diversas funções para fazer a vida dos policiais do seu servidor mais fácil, além de um roleplay mais imersivo e completo para os outros jogadores.
Veja nosso vídeo demonstrativo!
# Eventos
Source: https://docs.heyyshop.com.br/products/heyy_houses/api/events
Integre nosso produto com outros scripts de seu servidor, deixando tudo muito mais legal e com sua cara.
## Client-side
### heyy\_houses:onTabletOpen
> Esse evento é exclusivamente de leitura, dispará-lo não fará nenhum evento dentro do script.
Esse evento é disparado toda vez que o tablet é aberto. Um exemplo básico de uso (que é utilizado por nós) é remover arma da mão do jogador para que a animação fique correta, por exemplo.
**Exemplo de uso:**
```lua theme={null}
AddEventHandler("heyy_houses:onTabletOpen", function()
-- seu código
end)
```
### heyy\_houses:closeUI
Ao disparar esse evento qualquer interface do script é fechada.
**Exemplo de uso:**
```lua theme={null}
-- client-side
TriggerEvent("heyy_houses:closeUI")
-- server-side
TriggerClientEvent("heyy_houses:closeUI", source)
```
### heyy\_houses:requestChestOpen
> Esse evento é exclusivamente de leitura, dispará-lo não fará nenhum evento dentro do script.
Disparado ao tentar abrir o baú de uma propriedade, após todas as verificações de permissão.
Esse evento normalmente é utilizado para abrir o baú da propriedade. Há um equivalente à ele no server, caso seja mais fácil de realizar a abertura por lá. Consulte `heyy_houses:server:requestChestOpen`
**Parâmetros:**
* data
* name: `string`
* Um nome único vinculado à propriedade. Segue o formato `P-{property_id}`
* display: `string`
* O nome bonito e formatado da propriedade
* coords: `vector3`
* A coordenada do baú
* level: `integer`
* O nível atual do baú
* weight: `integer`
* O peso máximo suportado pelo baú, de acordo com o nível atual
* slots: `integer`
* A quantidade de slots do baú, de acordo com o nível atual
Caso seu script de baú não suporte alterações no número de slots, ou você não queira utilizar, você pode comentar todas as linhas `chestSlots` em `heyy_houses/config/config.lua`, assim não haverá mais nenhuma menção de mais slots quando o jogador for melhorar o baú pela interface.
**Exemplo de uso:**
```lua theme={null}
AddEventHandler("heyy_houses:requestChestOpen", function(data)
-- seu código para abrir o baú, por exemplo
end)
```
## Server-side
### heyy\_houses:server:requestChestOpen
> Esse evento é exclusivamente de leitura, dispará-lo não fará nenhum evento dentro do script.
Disparado ao tentar abrir o baú de uma propriedade, após todas as verificações de permissão.
Esse evento normalmente é utilizado para abrir o baú da propriedade. Há um equivalente à ele no client, caso seja mais fácil de realizar a abertura por lá. Consulte `heyy_houses:requestChestOpen`
**Parâmetros:**
* data
* Consulte `heyy_houses:requestChestOpen`, as informações são as mesmas.
**Exemplo de uso:**
```lua theme={null}
-- É necessário utilizar RegisterNetEvent ao invés de AddEventHandler, já que o evento é disparado pelo client.
RegisterNetEvent("heyy_houses:server:requestChestOpen", function(data)
local src = source
-- seu código para abrir o baú, por exemplo
end)
```
# Exports
Source: https://docs.heyyshop.com.br/products/heyy_houses/api/exports
Integre nosso produto com outros scripts de seu servidor, deixando tudo muito mais legal e com sua cara.
## Client-side
### getNearestProperty
Retorna a propriedade mais próxima do jogador dentro do raio, caso exista.
**Parâmetros:**
* radius: `number`
**Retorna:**
* label: `string?`
* data: `table?`
* É o equivalente à `propertyList[label]`
**Exemplo de uso:**
```lua theme={null}
local label, data = exports.heyy_houses:getNearestProperty(15.0)
```
## Server-side
### getNearestProperty
Retorna a propriedade mais próxima do jogador dentro do raio, caso exista.
**Parâmetros:**
* coords: `vector3`
* radius: `number?`
**Retorna:**
* data: `table`
* label: `string`
* distance: `number`
**Exemplo de uso:**
```lua theme={null}
local ped = GetPlayerPed(source)
local coords = GetEntityCoords(ped)
local data = exports.heyy_houses:getNearestProperty(coords)
```
### registerProperty
Registra uma propriedade para um jogador
**Parâmetros:**
* user\_id: `integer`
* label: `string`
* interior: `string?`
* interiorColor: `string?`
**Retorna:**
* data: `table`
* success: `boolean`
* errorMessage: `string?`
* A mensagem de erro caso `success` seja igual à `false`
**Exemplo de uso:**
```lua theme={null}
local data = exports.heyy_houses:registerProperty(user_id, "Eclipse Tower")
```
### removeProperty
Remove uma propriedade pelo ID, caso exista.
**Parâmetros:**
* property\_id: `integer`
**Exemplo de uso:**
```lua theme={null}
-- Assumindo que o ID da propriedade desejada seja 136
exports.heyy_houses:removeProperty(136)
```
### getUserPropertyPermissions
Retorna as permissões do jogador em uma propriedade específica
**Parâmetros:**
* property\_id: `integer`
* user\_id: `integer`
**Retorna:**
* permissions: `table`
* \[key: `string`]: `boolean`
**Exemplo de uso:**
```lua theme={null}
-- Assumindo que o ID da propriedade desejada seja 136
local permissions = exports.heyy_houses:getUserPropertyPermissions(136, user_id)
```
### isPropertyStealable
Retorna se a propriedade especificada tem coordenadas de roubo válidas e pode ser roubada.
**Parâmetros:**
* label: `string`
**Retorna:**
* canSteal: `boolean`
**Exemplo de uso:**
```lua theme={null}
if exports.heyy_houses:isPropertyStealable("Eclipse Tower") then
-- algo acontece se puder roubar
end
```
### tryStealProperty
Realiza uma tentativa de roubo à propriedade mais próxima. Se for possível de ser roubada, o jogador será instantâneamente teleportado para dentro da propriedade.
**Parâmetros:**
* source: `string`
**Retorna:**
* success: `boolean`
**Exemplo de uso:**
```lua theme={null}
exports.heyy_houses:tryStealProperty(source)
```
### canInvadeProperty
Verifica se uma propriedade pode ser invadida.
As condições para uma propriedade ser invadida são algumas e apenas uma delas precisa ser verdadeira:
* A propriedade está sendo roubada
* A propriedade possui dono
Além dessas condições a função `Functions.canInvadeProperty` definida no `functions.lua` precisa retornar verdadeiro. É nessa função que você pode determinar condições adicionais (por exemplo, verificar se o jogador é um policial ou verificar algo sobre a propriedade). Se essa função não existir, ela é assumida como verdadeira.
Caso não seja possível invadir por alguma das condições explicadas acima, é retornado uma mensagem de erro.
**Parâmetros:**
* user\_id: `integer`
* label: `string`
**Retorna:**
* canInvade: `boolean`
* errorMessage: `string?`
**Exemplo de uso:**
```lua theme={null}
local canInvade = exports.heyy_houses:canInvadeProperty(user_id, label)
```
### invadeProperty
Realiza uma tentativa de invadir a propriedade especificada.
É executado `canInvadeProperty` antes de realmente realizar a invasão, mas é recomendado que você utilize `canInvadeProperty` no seu próprio código.
**Parâmetros:**
* user\_id: `integer`
* label: `string`
* propertyId: `number?`
* Esse parâmetro específico é opcional, ele permite que você especifique o ID da casa que deve ser invadida. Isso é util em propriedades como apartamentos, em que há vários no mesmo blip. Caso não especificado, o jogador poderá escolher qual invadir.
**Retorna:**
* success: `boolean`
* errorMessage: `string?`
**Exemplo de uso:**
```lua theme={null}
local success, errorMessage = exports.heyy_houses:invadeProperty(user_id, label)
```
# Statebags
Source: https://docs.heyyshop.com.br/products/heyy_houses/api/statebags
Integre nosso produto com outros scripts de seu servidor, deixando tudo muito mais legal e com sua cara.
Os *state bags* são utilizados para sincronizar informações entre clientes e o servidor. Para saber mais detalhes e como utilizar, você pode [ler mais sobre os StateBags aqui](https://docs.fivem.net/docs/scripting-manual/networking/state-bags/).
## Resumo
| Statebag | Tipo | Descrição |
| ----------------------- | ------- | ----------------------------------------------------- |
| heyy\_houses:blockEnter | boolean | Bloqueia o jogador de entrar em casas |
| heyy\_houses:blockUI | boolean | Bloqueia o jogador de abrir diversas interfaces |
| insideProperty | table | Retorna dados sobre a propriedade que o jogador está |
| stealingProperty | boolean | Se o jogador está roubando a propriedade atual ou não |
## Lista completa
### heyy\_houses:blockEnter
Pode ser utilizado para bloquear o jogador de entrar em casas.
**Exemplo de uso:**
```lua theme={null}
-- client-side
LocalPlayer.state["heyy_houses:blockEnter"] = true
-- server-side
Player(source).state["heyy_houses:blockEnter"] = true
```
### heyy\_houses:blockUI
Pode ser utilizado para bloquear o jogador de abrir diversas interfaces.
**Exemplo de uso:**
```lua theme={null}
-- client-side
LocalPlayer.state["heyy_houses:blockUI"] = true
-- server-side
Player(source).state["heyy_houses:blockUI"] = true
```
### insideProperty
Pode ser utilizado para ler dados sobre a propriedade que o jogador está.
**Exemplo de uso:**
```lua theme={null}
-- client-side
local data = LocalPlayer.state.insideProperty
-- server-side
local data = Player(source).state.insideProperty
```
### stealingProperty
Pode ser utilizado para saber se o jogador está roubando uma casa ou não. É muito útil se combinado ao [insideProperty](#insideproperty).
**Exemplo de uso:**
```lua theme={null}
-- client-side
if LocalPlayer.state.stealingProperty then
-- seu código
end
-- server-side
if Player(source).state.stealingProperty then
-- seu código
end
```
# Eventos
Source: https://docs.heyyshop.com.br/products/heyy_mdt/api/events
Integre nosso produto com outros scripts de seu servidor, deixando tudo muito mais legal e com sua cara.
## Client-side
### heyy\_mdt:openUI
Ao disparar esse evento o tablet será aberto, caso o jogador tenha permissão para isso.
**Exemplo de uso:**
```lua theme={null}
-- client-side
TriggerEvent("heyy_mdt:openUI")
-- server-side
TriggerClientEvent("heyy_mdt:openUI", source)
```
### heyy\_mdt:onTabletOpen
> Esse evento é exclusivamente de leitura, dispará-lo não fará nenhum evento dentro do script.
Esse evento é disparado toda vez que o tablet é aberto. Um exemplo básico de uso (que é utilizado por nós) é remover arma da mão do jogador para que a animação fique correta, por exemplo.
**Exemplo de uso:**
```lua theme={null}
AddEventHandler("heyy_mdt:onTabletOpen", function()
-- seu código
end)
```
### heyy\_mdt:closeUI
Ao disparar esse evento o tablet é fechado.
**Exemplo de uso:**
```lua theme={null}
-- client-side
TriggerEvent("heyy_mdt:closeUI")
-- server-side
TriggerClientEvent("heyy_mdt:closeUI", source)
```
## Server-side
### heyy\_mdt:setOnDuty
Esse evento pode ser disparado para iniciar ou finalizar a contagem de horas em serviço.
Ele normalmente é utilizado ao entrar/sair de serviço.
**Parâmetros:**
* user\_id: `integer`
* status: `boolean`
* true caso queira iniciar a contagem de horas, e false caso queira finalizá-la.
**Exemplo de uso:**
```lua theme={null}
TriggerEvent("heyy_mdt:setOnDuty", user_id, status)
```
# Exports
Source: https://docs.heyyshop.com.br/products/heyy_mdt/api/exports
Integre nosso produto com outros scripts de seu servidor, deixando tudo muito mais legal e com sua cara.
## Client-side
### isUiOpen
Retorna se a interface está ou não aberta.
**Retorna:**
* isOpen: `boolean`
**Exemplo de uso:**
```lua theme={null}
local isOpen = exports.heyy_mdt:isUiOpen()
```
## Server-side
### isArrested
Retorna se o jogador está preso ou não.
**Parâmetros:**
* user\_id: `integer`
**Retorna:**
* isArrested: `boolean`
**Exemplo de uso:**
```lua theme={null}
local isArrested = exports.heyy_mdt:isArrested(user_id)
```
### getArrestTime
Retornará a quantidade de meses restantes para o jogador, ou zero.
**Parâmetros:**
* user\_id: `integer`
**Retorna:**
* arrestTime: `integer`
**Exemplo de uso:**
```lua theme={null}
local arrestTime = exports.heyy_mdt:getArrestTime(user_id)
```
### arrestPlayer
Envia um jogador à prisão, pelo tempo determinado.
**Parâmetros:**
> Parâmetros marcadas com `?` são opcionais, os que não, são obrigatórios.
* data: `table`
* user\_id: `integer`
* Jogador que deverá ser preso
* officers\_id?: `integer[]`
* Uma lista dos oficiais que prenderam o jogador
* arrestTime: `integer`
* O tempo de prisão que deverá ser aplicado ao jogador
* finesValue?: `integer`
* O valor das multas que deverá ser aplicado ao jogador
* Padrão: `0`
* reason?: `string`
* O motivo da prisão
* save?: `boolean`
* Se essa prisão deverá ser registrada no banco de dados
* Padrão: `false`
* canEscape?: `boolean`
* Se o jogador pode ou não escapar
* Padrão: `true`
* changeClothes?: `boolean?`
* Se a roupa do jogador deve ser alterada para a de prisão
* Padrão: `true`
**Exemplo de uso:**
```lua theme={null}
exports.heyy_mdt:arrestPlayer({
user_id = 1,
save = true,
arrestTime = 30,
finesValue = 30000,
reason = reason,
canEscape = false,
changeClothes = false,
})
```
### getUserDepartment
Retorna o departamento que o jogador está, basicamente irá percorrer `config.departments` e buscar pelo primeiro que o jogador possui a permissão `openTablet`.
**Parâmetros:**
* user\_id: `integer`
**Retorna:**
* departmentIndex: `string?`
* departmentData: `table?`
**Exemplo de uso:**
```lua theme={null}
local departmentIndex, departmentData = exports.heyy_mdt:getUserDepartment(user_id)
```
### isUserInDepartment
Retorna se o jogador está em um departamento específico, ou não.
**Parâmetros:**
* user\_id: `integer`
* departmentIndex: `string`
**Retorna:**
* inDepartment: `boolean`
**Exemplo de uso:**
```lua theme={null}
local inDepartment = exports.heyy_mdt:isUserInDepartment(user_id, "LSPD")
```
### getUserAvatar
Retorna o link do avatar do usuário.
**Parâmetros:**
* user\_id: `integer`
* ignoreFallback: `boolean?`
* Se for `true`, irá retornar nulo caso o jogador não possua um avatar.
**Retorna:**
* avatarUrl: `boolean`
**Exemplo de uso:**
```lua theme={null}
local avatarUrl = exports.heyy_mdt:getUserAvatar(user_id)
```
### setUserAvatar
Define um novo avatar para um usuário.
**Parâmetros:**
* user\_id: `integer`
* avatarUrl: `string`
**Exemplo de uso:**
```lua theme={null}
exports.heyy_mdt:setUserAvatar(user_id, "https://.../")
```
# Statebags
Source: https://docs.heyyshop.com.br/products/heyy_mdt/api/statebags
Integre nosso produto com outros scripts de seu servidor, deixando tudo muito mais legal e com sua cara.
Os *state bags* são utilizados para sincronizar informações entre clientes e o servidor. Para saber mais detalhes e como utilizar, você pode [ler mais sobre os StateBags aqui](https://docs.fivem.net/docs/scripting-manual/networking/state-bags/).
## Resumo
| Statebag | Tipo | Descrição |
| --------- | ------- | ---------------------------------------------- |
| arrested | boolean | Se o jogador está preso ou não |
| cutscene | boolean | Se o jogador está na cutscene de prisão ou não |
| prisonJob | string | O trabalho prisonal o jogador está realizando |
## Lista completa
### arrested
Pode ser utilizado para verificar se o jogador está preso.
**Exemplo de uso:**
```lua theme={null}
-- client-side
if LocalPlayer.state.arrested then
-- seu código
end
-- server-side
if Player(source).state.arrested then
-- seu código
end
```
### cutscene
Pode ser utilizado para saber qual trabalho prisonal foi designado ao jogador.
**Exemplo de uso:**
```lua theme={null}
-- client-side
if LocalPlayer.state.cutscene then
-- seu código
end
-- server-side
if Player(source).state.cutscene then
-- seu código
end
```
### prisonJob
Pode ser utilizado para saber qual trabalho prisonal foi designado ao jogador.
**Exemplo de uso:**
```lua theme={null}
-- client-side
if LocalPlayer.state.prisonJob == "cleaner" then
-- seu código
end
-- server-side
if Player(source).state.prisonJob == "cleaner" then
-- seu código
end
```
### canEscape
Pode ser utilizado para saber se o jogador pode, ou não, fugir da prisão.
**Exemplo de uso:**
```lua theme={null}
-- client-side
if LocalPlayer.state.canEscape then
-- seu código
end
-- server-side
if Player(source).state.canEscape then
-- seu código
end
```
# Apresentação
Source: https://docs.heyyshop.com.br/products/heyy_mdt/features
Conheça nosso Tablet Policial e as funções que vão diferenciar seu servidor de outros que seus jogadores já jogaram!
# Tablet Policial
Nosso tablet policial é um sistema para ajudar os policiais à realizarem suas tarefas mais rapidamente e com uma maior facilidade.
## Funções
Além de ajudar na organização interna. O sistema conta com:
* Mural de avisos
* Aplicação de prisão e multas
* Sistema de boletins de ocorrência
* Sistema de procurado (tanto para veículos quanto pessoas)
* Código penal integrado
* Sistema de fuga do presídio integrado
* Configurações pessoais do oficial (tema escuro/claro e notificações)
* Página de Gerenciamento (adicionar/promover/rebaixar/remover oficiais, além de ver suas horas trabalhadas)
# Campos Personalizados
Source: https://docs.heyyshop.com.br/products/heyy_mdt/get-started/advanced/custom-licenses
Aprenda como configurar campos personalizados dentro do Tablet Policial
Com os campos personalizados você pode exibir praticamente qualquer informação que desejar dentro do Tablet Policial, por exemplo, carteira de motorista, licença de caça ou outras informações que um policial possa querer saber sobre o jogador.
Nessa documentação, iremos utilizar como exemplo **Carteira de Motorista**.
## Exemplo de Campo Personalizado
```lua config.lua theme={null}
["driver"] = {
---@type string O título do campo dentro do tablet
title = "Carteira de Motorista",
---@type string O nome do botão dentro do tablet
actionName = "Alternar status",
---@type string | [string, string]
confirmationMessage = {
"Deseja criar uma carteira de motorista para {name}?",
"Você tem certeza que deseja invalidar a carteira de motorista de {name}?"
},
---@type string | [string, string]
successMessage = {
"A carteira de motorista de {name} foi criada com sucesso!",
"A carteira de motorista de {name} foi invalidada com sucesso!"
},
---@param value any O valor atual do campo. O exato valor retornado pela função `Functions.getDriverLicense`
---@return string displayValue O texto que será mostrado dentro do tablet
parseValue = function(value)
return value and "Sim" or "Não"
end,
---@param value any O valor atual do campo. O exato valor retornado pela função `Functions.getDriverLicense`
---@return boolean visible Se for true, um botão será exibido para editar, se for false, o botão será ocultado.
buttonCondition = function(value)
-- Neste caso, o botão só será exibido caso o usuário tenha a carteira de motorista.
-- Ou seja, seria um botão para revogar.
return value
end,
}
```
### Parâmetros de Configuração do Campo
O identificador `"driver"` é apenas um exemplo e pode ser substituído por qualquer identificador de sua escolha para representar diferentes campos personalizados.
| Parâmetro | Tipo | Descrição |
| --------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | string | Um identificador único para a licença.
No exemplo acima, utilizamos `driver`. |
| `title` | string | Define o título que será exibido no campo dentro do tablet.
No exemplo acima, utilizamos `Carteira de Motorista`. |
| `actionName` | string | Define o texto que será exibido no botão de ação.
No exemplo acima, utilizamos `Alterar status`. |
| `confirmationMessage` | string ou array\[2] de strings | Mensagens de confirmação antes de realizar a ação. Se for um array, a primeira mensagem é para criação e a segunda para invalidação. |
| `successMessage` | string ou array\[2] de strings | Mensagens exibidas após a conclusão bem-sucedida da ação. Se for um array, a primeira mensagem é para criação e a segunda para invalidação. |
| `parseValue` | function | Função que formata o valor para exibição no tablet.
No exemplo acima, retornamos **Sim** para `true` e **Não** para `false`. |
| `buttonCondition` | function | Função que determina se o botão de ação deve ser exibido ou não.
No exemplo acima, mostramos o botão apenas se `value` for `true`. |
## Funções Necessárias
Para o correto funcionamento deste campo de licença, é necessário implementar as seguintes funções nos arquivos indicados.
O nome das funções é o ID com a primeira letra maiúscula. No exemplo, nosso ID é driver, então o nome das funções são `getDriverLicense`,`updateDriverLicense` e `onUpdateDriverLicense`.
### functions.lua
#### `Functions.getDriverLicense(userID)`
Esta função deve verificar se um usuário possui carteira de motorista válida.
```lua functions.lua theme={null}
---@param userID number ID do usuário a ser verificado
---@return any status Retorna o status da carteira de motorista
function Functions.getDriverLicense(userID)
return Functions.getUData(userID, "driverLicense") == "true"
end
```
#### `Functions.updateDriverLicense(userID)`
Esta função deve alternar o status da carteira de motorista de um usuário (criar ou invalidar).
```lua functions.lua theme={null}
---@param userID number ID do usuário cuja carteira será atualizada
---@return boolean success Retorna true se a operação foi bem-sucedida, false caso contrário
function Functions.updateDriverLicense(userID)
local value = Functions.getDriverLicense(userID)
Functions.setUData(userID, "driverLicense", tostring(not value))
return true
end
```
### webhooks.lua
#### `Webhooks.onUpdateDriverLicense(userID, officerID)`
Esta função de webhook é chamada quando um policial altera o status da carteira de motorista de um cidadão. Pode ser utilizada para logging, notificações ou integrações externas.
````lua webhooks.lua [expandable] theme={null}
---@param userID number ID do usuário cuja carteira foi atualizada
---@param officerID number ID do policial que realizou a ação
function Webhooks.onUpdateDriverLicense(userID, officerID)
local officerIdentity = Functions.getUserIdentity(officerID)
local officerName = officerIdentity.name .. " " .. officerIdentity.surname
local targetIdentity = Functions.getUserIdentity(userID)
local targetName = targetIdentity.name .. " " .. targetIdentity.surname
local status = Functions.getDriverLicense(userID)
PerformHttpRequest(webhookURLs.licenses, function(err, text, headers) end, "POST", json.encode({
embeds = {
{
author = {
name = (status and "Carteira de motorista criada" or "Carteira de motorista invalidada"),
icon_url = "https://cdn-icons-png.flaticon.com/512/2689/2689886.png"
},
fields = {
{
name = "Oficial",
value = "```ini\n[" .. officerID .. "] " .. officerName .. "\n```",
},
{
name = "Jogador",
value = "```ini\n[" .. userID .. "] " .. targetName .. "\n```",
inline = true,
},
},
color = (status and 3042892 or 9317187)
}
}
}), {["Content-Type"] = "application/json"})
end
````
## Fluxo de Funcionamento
1. Quando um policial acessa os detalhes de um jogador no tablet, o sistema chama a função ***get*** (por exemplo, `Functions.getDriverLicense(userID)`) para obter o status atual da licença.
2. O valor retornado é formatado pela função `parseValue` para exibição, por lá, você pode retornar o valor que você quiser (no exemplo, "Sim" ou "Não").
3. A função `buttonCondition` determina se o botão de ação deve ser exibido (no exemplo, só é exibido se o cidadão já possui a licença).
4. Quando o policial clica no botão **"Alternar status"**:
* É exibido uma confirmação para o policial;
* Se confirmado, a função de ***update*** (por exemplo, `Functions.updateDriverLicense(userID)`) é chamada;
* Em seguida, o webhook correspondente (por exemplo, `Webhooks.onUpdateDriverLicense(userID, officerID)`) é acionado.
## Criando Diferentes Tipos de Campos
O mesmo padrão de configuração pode ser usado para implementar qualquer campo personalizado, bastando alterar o identificador do campo e as funções correspondentes. Por exemplo:
```lua config.lua theme={null}
["hunting"] = {
title = "Licença de Caça",
actionName = "Alternar status",
confirmationMessage = {
"Deseja conceder uma licença de caça para {name}?",
"Você tem certeza que deseja revogar a licença de caça de {name}?"
},
-- Resto da configuração segue o mesmo padrão...
}
```
Você precisaria então implementar as funções correspondentes:
* `Functions.getHuntingLicense(userID)`
* `Functions.updateHuntingLicense(userID)`
* `Webhooks.onUpdateHuntingLicense(userID, officerID)`
## Notas de Implementação
* Esta configuração utiliza a tag de substituição `{name}` nas mensagens, que deve ser substituída pelo nome do cidadão antes de exibir.
* A lógica implementada em `buttonCondition` pode ser personalizada conforme a necessidade (no exemplo, só permite invalidar licenças existentes).
# Gerenciamento
Source: https://docs.heyyshop.com.br/products/heyy_mdt/get-started/hierarchy
Descubra como configurar a hierarquia dos departamentos e o gerenciamento de oficiais dentro do Tablet Policial.
A página de **Gerenciamento** do Tablet Policial é onde os oficiais conseguem visualizar os membros do seu departamento, contratar novos oficiais, promover, rebaixar e exonerar. Tudo isso é controlado pelo arquivo `hierarchy.lua`.
Para configurá-lo, abra a pasta do script (`heyy_mdt`), abra a pasta `config` e dentro dela, abra o arquivo `hierarchy.lua`.
Logo no topo do arquivo, você deve se deparar com algo parecido com isso:
```lua heyy_mdt/config/hierarchy.lua theme={null}
hierarchy = {
["Police"] = true,
["Sheriff"] = true
}
```
Essa tabela é a lista de **grupos gerenciáveis** pelo tablet. Cada chave é o nome de um grupo da sua base, escrito exatamente como ele está lá, e cada grupo listado aqui vira um **departamento selecionável** dentro da página de gerenciamento.
Você pode adicionar quantos grupos quiser. É isso que permite que um mesmo tablet gerencie a **Police** e o **Sheriff** (por exemplo) de forma separada, cada um com sua própria lista de oficiais e suas próprias patentes.
Um oficial só enxerga um departamento nessa lista se ele **fizer parte daquele grupo**. Ou seja, quem só possui o grupo `Police` nunca verá o `Sheriff` no seletor, mesmo que ambos estejam configurados aqui.
## Entendendo as posições
Antes de qualquer coisa, é importante entender como o script enxerga a hierarquia de um grupo.
A hierarquia **não é definida no tablet** — ela é lida diretamente da sua base, através da função `Functions.getGroupHierarchy` (explicada mais abaixo). Ela retorna a lista de patentes do grupo, onde:
* A posição **1** é sempre a **mais alta** (o comandante, por exemplo).
* A **última** posição (o tamanho da lista) é sempre a **mais baixa** (o recruta, por exemplo).
Suponha que o grupo `Police` da sua base tenha a seguinte hierarquia:
| Posição | Patente |
| ------- | ---------- |
| 1 | Comandante |
| 2 | Capitão |
| 3 | Sargento |
| 4 | Soldado |
| 5 | Recruta |
Neste caso, um oficial na posição **2** (Capitão) é **superior** a um oficial na posição **4** (Soldado). Quanto **menor** o número, **maior** a patente.
É por isso que uma promoção **diminui** o número da posição do oficial, e um rebaixamento **aumenta**.
## Permissão de acesso
Diferente da lista de grupos, quem pode **abrir** a página de gerenciamento e realizar ações é definido no `config.lua`, dentro do seu departamento, pela permissão `manageOfficers`:
```lua heyy_mdt/config/config.lua theme={null}
departments = {
["LSPD"] = {
permissions = {
-- Permissão para verificar informações de outros policiais (é possível inserir múltiplas permissões)
manageOfficers = { "Police@2" },
}
},
}
```
Quem não possuir essa permissão não verá o botão de gerenciamento na barra de navegação do tablet, e qualquer tentativa de contratar, promover, rebaixar ou exonerar será recusada pelo servidor.
Ter a permissão `manageOfficers` **não** libera todas as ações sobre todos os oficiais. O tablet ainda aplica as regras de hierarquia descritas mais abaixo — você nunca conseguirá agir sobre alguém de patente igual ou superior à sua.
## Funções
Abaixo da tabela `hierarchy`, o arquivo contém as funções que conectam o tablet à sua base. Elas já vêm configuradas para bases vRP padrão, mas **podem precisar de ajustes** dependendo da base que você utiliza.
Assim como no `functions.lua`, aqui você só precisa alterar as chamadas internas (`vRP.DataGroups`, `vRP.SetPermission`, etc.) para as funções equivalentes da sua base. **Não altere o nome nem os parâmetros das funções.**
### getAllUsersInGroup
```lua theme={null}
function Functions.getAllUsersInGroup(group)
local results = vRP.DataGroups(group)
local users = {}
for k, _ in pairs(results) do
table.insert(users, parseInt(k))
end
return users
end
```
Deve retornar uma **lista com os IDs** de todos os jogadores que fazem parte do grupo informado. É essa função que preenche a lista de oficiais na página de gerenciamento.
### getGroupHierarchy
```lua theme={null}
function Functions.getGroupHierarchy(group)
return Groups[group].Hierarchy
end
```
Deve retornar a **lista de patentes** do grupo, em ordem — da mais alta (índice 1) para a mais baixa. É a partir dela que o tablet descobre o nome de cada patente e qual é a menor posição existente.
### getUserHierarchy
```lua theme={null}
function Functions.getUserHierarchy(user_id, group)
local results = vRP.DataGroups(group)
return results[tostring(user_id)]
end
```
Deve retornar a **posição** (número) que aquele jogador ocupa dentro do grupo, ou `nil` caso ele não faça parte dele.
Se esta função retornar `nil` para um oficial que **está** no grupo, ele será ignorado na listagem e um aviso aparecerá no console do servidor. Quase sempre isso indica que `getAllUsersInGroup` e `getUserHierarchy` estão lendo fontes de dados diferentes — as duas precisam enxergar exatamente os mesmos membros.
### promoteUser e demoteUser
```lua theme={null}
function Functions.promoteUser(user_id, group, author_source)
local position = Functions.getUserHierarchy(user_id, group)
if position <= 1 then
return false -- Error
end
vRP.SetPermission(user_id, group, (position - 1))
return true
end
```
Responsáveis por mover o oficial na hierarquia. Como a posição **1** é a mais alta, promover significa **subtrair** 1 da posição atual, e rebaixar significa **somar** 1.
Ambas devem retornar `true` em caso de sucesso. Você também pode retornar `false` seguido de uma mensagem, que será exibida como notificação para quem realizou a ação:
```lua theme={null}
return false, "Este oficial não pode ser promovido no momento!"
```
### addUser e removeUser
```lua theme={null}
function Functions.addUser(user_id, group, author_source)
local hierarchy = Functions.getGroupHierarchy(group)
vRP.SetPermission(user_id, group, #hierarchy)
return true -- Success
end
function Functions.removeUser(user_id, group, author_source)
vRP.RemovePermission(user_id, group)
return true -- Success
end
```
Responsáveis por contratar e exonerar. Repare que todo novo oficial é contratado na **última posição** da hierarquia (`#hierarchy`), ou seja, sempre na patente mais baixa do grupo.
## Como o gerenciamento funciona
Com o arquivo configurado, o funcionamento dentro do tablet acontece assim:
Ao abrir a página de gerenciamento, o tablet monta a lista de departamentos disponíveis com todos os grupos da tabela `hierarchy` dos quais o oficial faz parte.
Selecionado o departamento, o tablet busca todos os membros do grupo e exibe, para cada um: nome, patente, posição e status (**offline**, **online** ou **em serviço**), além da última vez que ele bateu o ponto.
Os botões de promover, rebaixar e exonerar são liberados individualmente, de acordo com as regras da tabela abaixo.
### Regras das ações
Mesmo tendo a permissão `manageOfficers`, o tablet ainda aplica regras de hierarquia para cada ação. Considere **você** como quem está realizando a ação e **alvo** como o oficial selecionado:
| Ação | Quando fica disponível |
| ------------ | ------------------------------------------------------------------------------ |
| **Promover** | Sua posição é superior à do alvo e o alvo ainda **não** está na posição 1 |
| **Rebaixar** | Sua posição é superior à do alvo e o alvo ainda **não** está na última posição |
| **Exonerar** | Sua posição é superior à do alvo |
Nenhuma ação pode ser realizada sobre **si mesmo**, e nenhum oficial consegue agir sobre alguém de **patente igual ou superior** à sua. Isso é validado no servidor, e não apenas na interface.
### Contratação
A contratação funciona de forma um pouco diferente das demais ações, porque envolve o jogador que está sendo contratado:
1. O oficial informa o ID do jogador que deseja contratar.
2. O jogador **precisa estar na cidade**. Caso contrário, a ação é cancelada com a mensagem *"O alvo não está na cidade!"*.
3. Uma confirmação é enviada para o jogador, que tem **15 segundos** para aceitar.
4. Aceitando, ele é adicionado ao grupo na patente mais baixa e um webhook de contratação é disparado.
Caso você não queira que oficiais consigam contratar pelo tablet, basta definir `disableAddButton = true` dentro de `config.extras`, no arquivo `config.lua`.
### Webhooks
Todas as ações de gerenciamento disparam webhooks, permitindo que você acompanhe pelo Discord quem contratou, promoveu, rebaixou ou exonerou cada oficial. Você pode configurá-los no arquivo `webhooks.lua`, como explicado na página de [Webhooks](/products/heyy_mdt/get-started/webhooks).
## Cache
Para evitar consultas desnecessárias à sua base, o tablet mantém em cache a hierarquia dos oficiais e a lista de membros de cada grupo. Esse cache é limpo automaticamente sempre que uma ação é feita **pelo tablet**.
Porém, se você promover, rebaixar ou exonerar um jogador por **fora do tablet** (por um comando administrativo ou outro script, por exemplo), o tablet pode continuar exibindo a informação antiga por alguns minutos. Nesses casos, utilize os exports abaixo para limpar o cache manualmente:
```lua theme={null}
-- Limpa a posição em cache de um oficial específico
exports["heyy_mdt"]:clearUserHierarchyCache(user_id, "Police")
-- Limpa a lista de membros em cache de um grupo inteiro
exports["heyy_mdt"]:clearAllUsersInGroupCache("Police")
```
# Código penal
Source: https://docs.heyyshop.com.br/products/heyy_mdt/get-started/infractions
Descubra como configurar o código penal e multas dentro do Tablet Policial.
Para configurar os artigos no Tablet Policial, abra a pasta do script (`heyy_mdt`), abra a pasta `config` e dentro dela, abra o arquivo `infractions.lua`.
Você deve se reparar com algo parecido com isso:
```lua heyy_mdt/config/infractions.lua theme={null}
infractionsConfig = {
maxFineReduction = 50, -- (em porcentagem) Máxima redução do valor da multa que poderá ser selecionada no tablet
maxArrestReduction = 50, -- (em porcentagem) Máxima redução do tempo de prisão que poderá ser selecionada no tablet
maxFinesValue = 200000, -- Valor máximo da multa
maxArrestTime = 300, -- Pena máxima
bailToOfficer = false, -- Se, ao pagar a fiança, o valor pago será (ou não) destinado ao oficial que realizou a prisão
bailPercentage = 50.0, -- Porcentagem da fiança que será destinada ao oficial que realizou a prisão (utilizado apenas se a opção acima estiver definida como TRUE)
bailRemoveFine = true, -- TRUE = PRISÃO + MULTAS ignoradas / FALSE = Apenas PRISÃO ignorada
list = {
{
name = "Artigo 101 - Exemplo de artigo (c/ fiança)", -- nome do artigo que será exibido no tablet
fine = 1000, -- valor da multa
arrest = 10, -- quantidade de meses
bail = 2000, -- valor da fiança (defina como "false" se quiser desativar a opção de fiança para algum artigo)
},
{
name = "Artigo 102 - Exemplo de artigo 2 (s/ fiança)", -- nome do artigo que será exibido no tablet
fine = 0, -- valor da multa
arrest = 15, -- quantidade de meses
},
{
name = "Artigo 103 - Exemplo de artigo 3", -- nome do artigo que será exibido no tablet
fine = 1500, -- valor da multa
arrest = 0, -- quantidade de meses
},
}
}
```
Nesse arquivo, você consegue modificar múltiplas opções relacionadas à parte penal do Tablet Policial.
* **maxFineReduction** - é um valor em porcentagem (0-100) que define o máximo de redução de multas pela interface do script.
* **maxArrestReduction** - é um valor em porcentagem (0-100) que define o máximo de redução de pena pela interface do script.
* **maxFinesValue** - valor máximo em multas, a soma das multas será capada nesse valor máximo quando muitos artigos forem selecionados.
* **maxArrestTime** - tempo máximo de prisão, a soma máxima do tempo será capada nesse valor máximo quando muitos artigos forem selecionados.
* **bailToOfficer** - quando definido como `true`, caso o jogador sendo preso pague a fiança, o oficial que está prendendo receberá o valor em sua conta bancária. Caso não queira isso, defina como `false`.
* **bailPercentage** - é um valor em porcentagem (0-100), quantos porcento do valor pago pelo jogador sendo preso será dado para o policial. Só é usado caso `bailToOfficer`seja `true`.
* **bailRemoveFine** - quando definido como `true`, caso o jogador sendo preso pague a fiança, o valor em multas também será anulado.
## Lista de artigos
Para configurar novos artigos, você só precisa adicionar adicionar ele à lista. Há 2 tipos de artigos no tablet: os que aparecem na tela de **prisão** e os que aparecem na tela de **multas**.
### Prisão
Um artigo para prisão seguirá essa estrutura.
* **name** - nome do artigo dentro da interface
* **arrest** - tempo de prisão
* **fine** - valor em multa
* **bail** (opcional) - valor da fiança desse artigo. Caso não especificado, ou quando `false` o artigo será considerado inafiançável.
#### Funcionamento do sistema de fiança
O sistema de fiança funciona da seguinte forma: caso um jogador seja preso por um artigo que possui `bail` definido no arquivo de configuração e a caixa de seleção (checkbox) seja marcada na interface do script pelo policial no momento da prisão, o prisioneiro poderá confirmar se ele quer pagar a fiança ou não.
Caso o prisioneiro aceite e tenha saldo suficiente, qualquer artigo que tiver fiança será anulado. Caso todos os artigos selecionados possuam fiança, o jogador não será preso. Porém, caso algum artigo selecionado não tenha fiança, o jogador será preso por esse tempo restante.
Suponha que os artigos selecionados sejam:
* **Artigo A** - fiança \$5.000 - 15 meses
* **Artigo B** - fiança \$6.000 - 10 meses
* **Artigo C** - sem fiança - 5 meses
Jogador paga \$11.000, artigos **A** e **B** são anulados e o jogador é preso por apenas 5 meses, pelo artigo **C**.
### Multa
Caso você queira um artigo que apareça na tela de multar jogador, você deverá seguir essa estrutura:
* **name** - nome do artigo dentro da interface
* **arrest** - precisa ser igual a 0 (zero)
* **fine** - valor em multa
# Instalação
Source: https://docs.heyyshop.com.br/products/heyy_mdt/get-started/install
Obtenha informações, divididas em um passo a passo, sobre como instalar e configurar seu Tablet Policial.
# Passos p/ Instalação
A instalação do sistema é bem simples, e pode ser dividida em alguns passos simples explicados abaixo!
O primeiro passo é, óbviamente, baixar o arquivo do script. Você pode baixá-lo por [esse canal](https://discord.com/channels/1109838027410383042/1143683959151136949), em [nosso Discord](https://heyyshop.com.br/discord), que é visível apenas para usuários com o cargo **Cliente**.
O segundo passo é definir sua licença. Para isso, você deve abrir o arquivo `license.lua` e alterar `SUA_LICENÇA` para sua licença. Você pode copiar sua licença por [este site](https://heyyshop.com.br/dashboard), e caso você não tenha uma licença, você pode adquirir uma em [nosso Discord](https://heyyshop.com.br/discord)!
O terceiro passo é abrir o arquivo `functions.lua` e alterar as funções pré-configuradas para as funções que sua base usa, ou seja, alterar os nomes das funções para o nome das funções de sua `vrp`.
Por exemplo, em algumas bases a função que pega todos os usuários com uma permissão é `vRP.getUsersByPermission` (bases vRPex comuns), em bases Creative v3, essa função se chama `vRP.numPermission`.
Aqui estão alguns arquivos já configurados para algumas bases:
Os arquivos listados aqui podem não estar atualizados, então é importante que você verifique se as funções estão corretas.
É importante destacar que os arquivos acima nem sempre vão funcionar de imediato em sua base, na maioria das vezes, é necessário alguma modificação. Caso sua base não esteja listada aqui, você pode pedir ajuda em nosso [Discord](https://heyyshop.com.br/discord)!
O próximo passo é alterar o arquivo de configuração, que é o `config.lua`. É nesse arquivo que você consegue controlar quem tem acesso a determinada função, alterar comandos, alterar coordenadas e até mesmo ativar/desativar determinadas funções do script.
# Logs
Source: https://docs.heyyshop.com.br/products/heyy_mdt/get-started/webhooks
Obtenha informações, separadas em um passo a passo, sobre como configurar os Logs de seu Tablet Policial.
**Nenhum conhecimento** sobre **programação** é necessário para configurar os logs corretamente, basta seguir o passo a passo abaixo atentamente.
Os logs são uma ferramenta muito útil para conseguir manter controle sobre o que acontece dentro de seu servidor. Para configurá-los, basta seguir o passo a passo abaixo.
## Criando um Webhook
Abra seu servidor do Discord, escolha um canal e clique no ícone de engrenagem para acessar as configurações do canal.
Clique na aba `Integrações` e em seguida clique em `Criar Webhook`.
Escolha um nome e uma imagem para o webhook e clique em `Salvar`.
Copie o link do webhook e salve-o em algum lugar, pois ele será necessário para configurar os logs.
> Você pode criar quantos webhooks quiser, e utilizar quantos canais desejar, isso é útil para organizar os logs por tipos de ações (prisões, multas, boletins e etc).
## Configurando os Logs
Você pode encontrar o arquivo de configuração `webhooks.lua` na pasta `config` dentro do script.
Abra a pasta `config` dentro do script.
Abra o arquivo `webhooks.lua`.
Para adicionar o link do webhook que você criou e copiou anteriormente, basta colá-lo entre as aspas, dessa maneira:
```lua heyy_mdt/config/webhooks.lua theme={null}
--- URL para onde as imagens dos jogadores serão enviadas (discord/fivemanage são suportados)
--- Você pode utilizar o Discord para salvar as fotos (imagens expiram / somem)
--- Ou você pode utilizar o FiveManage para salvar as fotos (imagens não expiram)
--- Você pode obter seu https://fivemanage.com/dashboard > Developers > Tokens
config.avatar.photoWebhook = "https://discord.com/api/webhooks/..."
-- config.avatar.photoWebhook = "https://api.fivemanage.com/api/image?apiKey=SUA_API_KEY"
Webhooks = {}
local webhookURLs = {
warnings = "https://discord.com/api/webhooks/...", -- Avisos no mural
incidents = "", -- Boletins de ocorrência
arrests = "", -- Prisões
fines = "", -- Multas
history = "", -- Limpeza de ficha
escapes = "", -- Fugas da prisão
wanted = "", -- Procurados (jogadores e veículos)
gunLicenses = "", -- Porte de armas
hierarchy = "", -- Alterações na hierarquia (adicionar, promover, rebaixar e remover)
licenses = "", -- Licenças personalizadas (cart. motorista, porte de caça e afins)
}
```
> Caso você não queira utilizar algum dos webhooks, basta deixar o link vazio.
A primeira linha do arquivo (`config.avatar.photoWebhook`) **não** é um log — ela define onde as fotos dos jogadores serão hospedadas, e é explicada na seção [Webhook de fotos](#webhook-de-fotos).
Após adicionar os links dos webhooks, salve o arquivo e reinicie o script e pronto: os logs que você configurou já estarão funcionando corretamente, daí é só configurar os outros webhooks da mesma maneira.
## O que cada log registra
Abaixo está o detalhamento de tudo o que é enviado para cada um dos webhooks:
| Webhook | Ações registradas |
| --------------- | ---------------------------------------------------------------------------------------- |
| **warnings** | Avisos adicionados e apagados do mural |
| **incidents** | Boletins de ocorrência criados, editados, arquivados, desarquivados e deletados |
| **arrests** | Prisões realizadas (com oficiais envolvidos, artigos, tempo de prisão e valor em multas) |
| **fines** | Multas aplicadas (com oficiais envolvidos, infrações e valor total) |
| **history** | Limpezas de ficha |
| **escapes** | Fugas da prisão e jogadores liberados pela administração |
| **wanted** | Jogadores e veículos adicionados ou removidos da lista de procurados |
| **gunLicenses** | Portes de arma registrados e revogados |
| **hierarchy** | Contratações, promoções, rebaixamentos e exonerações |
| **licenses** | Campos personalizados (carteira de motorista, porte de caça e afins) |
O webhook de **hierarchy** registra todas as ações feitas pela página de gerenciamento do tablet, como explicado em [Gerenciamento](/products/heyy_mdt/get-started/hierarchy). Ações feitas por fora do tablet (por comandos administrativos, por exemplo) **não** aparecem nesse log.
O webhook de **licenses** só é utilizado caso você tenha configurado [Campos Personalizados](/products/heyy_mdt/get-started/advanced/custom-licenses). Se você não utiliza esse recurso, pode deixá-lo vazio.
## Webhook de fotos
Além dos logs, o Tablet Policial precisa de um lugar para **hospedar as fotos dos jogadores** que aparecem no tablet e nos logs de prisão. Isso é configurado na primeira linha do mesmo arquivo `webhooks.lua`:
```lua heyy_mdt/config/webhooks.lua theme={null}
config.avatar.photoWebhook = "https://discord.com/api/webhooks/..."
-- config.avatar.photoWebhook = "https://api.fivemanage.com/api/image?apiKey=SUA_API_KEY"
```
Você pode utilizar duas opções:
* **Discord** - basta criar um webhook normalmente, seguindo o mesmo passo a passo do início desta página, e colar o link. É a opção mais simples, porém as imagens do Discord **expiram** com o tempo, fazendo com que as fotos antigas sumam do tablet.
* **FiveManage** - as imagens **não expiram**, sendo a opção mais indicada para quem quer manter o histórico de fotos funcionando a longo prazo.
Diferente dos logs, este campo **não pode ficar vazio**. Sem ele, as fotos dos jogadores não serão salvas e o tablet exibirá a imagem padrão definida em `config.avatar.defaultImage`.
### Utilizando o FiveManage
O FiveManage é um serviço de hospedagem de imagens feito para servidores de FiveM. Como as fotos não expiram, elas continuam aparecendo no tablet e nos logs de prisão mesmo depois de meses.
Acesse o [painel do FiveManage](https://fivemanage.com/dashboard) e crie sua conta.
Dentro do painel, acesse a aba `Developers` e em seguida `Tokens`. Gere um novo token e copie-o.
No `webhooks.lua`, comente a linha do Discord e descomente a linha do FiveManage, substituindo `SUA_API_KEY` pelo token que você copiou:
```lua heyy_mdt/config/webhooks.lua theme={null}
-- config.avatar.photoWebhook = "https://discord.com/api/webhooks/..."
config.avatar.photoWebhook = "https://api.fivemanage.com/api/image?apiKey=SUA_API_KEY"
```
Repare que apenas a parte `SUA_API_KEY` deve ser substituída — o restante do link precisa permanecer exatamente como está.
Salve o arquivo, reinicie o script e as próximas fotos tiradas já serão hospedadas pelo FiveManage.
Preparamos um tutorial completo, com imagens de cada etapa, explicando a configuração do FiveManage do início ao fim: [Como configurar as fotos com o FiveManage](https://blog.heyyshop.com.br/como-configurar-fotos-fivemanage).
# Apresentação
Source: https://docs.heyyshop.com.br/products/servicex/features
Conheça nosso Bot de Ponto e tenha total controle sobre o quanto seus jogadores estão trabalhando!
# Bot de Ponto
Nosso bot de ponto é um bot que permite que você tenha total controle sobre o quanto seus jogadores estão trabalhando, e o melhor, tudo isso de forma automatizada!
## Como funciona?
Logo ao entrar em serviço no jogo, o bot abre o ponto do jogador no Discord. E ao sair, o bot fecha o ponto do jogador. Simples assim!
## Funções
Para você que gosta de estatísticas e controle, o bot de ponto é perfeito para você! Com ele você pode:
* Criar quantos grupos quiser (polícia, hospital, mecânica, restaurantes, ilegal ou qualquer outro)
* Ter início/fechamento de ponto automático ao entrar/sair de serviço no jogo
* Verificar estatísticas dos jogadores (horas trabalhadas)
* Ter um ranking de jogadores com maior quantidade de horas trabalhadas (por grupo)
* Compatível com quantos servidores do Discord você possuir (um para cada grupo ou um único para todos os grupos)
# Instalação
Source: https://docs.heyyshop.com.br/products/servicex/get-started/install
Obtenha informações, divididas em um passo a passo, sobre como instalar e configurar nosso Bot de Ponto (ServiceX).
# Passos p/ Instalação
A instalação do ServiceX é bem simples, e pode ser dividida em alguns passos simples explicados abaixo!
O primeiro passo é, óbviamente, baixar o arquivo do script (que auxiliará o bot de dentro do jogo). Você pode baixá-lo por [esse canal](https://canary.discord.com/channels/1109838027410383042/1166138784308535426), em [nosso Discord](https://discord.gg/2TuJwmnBWW), que é visível apenas para usuários com o cargo **Cliente**.
O segundo passo é definir sua licença. Para isso, você deve abrir o arquivo `license.lua` e alterar `SUA_LICENÇA` para sua licença. Você pode copiar sua licença por [este site](https://heyyshop.com.br/dashboard), e caso você não tenha uma licença, você pode adquirir uma em [nosso Discord](https://discord.gg/2TuJwmnBWW)!
Convide o bot para seu servidor utilizando [esse link](https://canary.discord.com/api/oauth2/authorize?client_id=1057764184802201680\&permissions=8\&scope=applications.commands%20bot) e ative-o utilizando o comando `/ativar` e colocando sua licença, é importante que a licença seja a mesma definida no script do passo anterior.
Primeiramente, para o bot funcionar, precisamos de um canal de ponto ou vários deles. Para criar o primeiro canal, utilize o comando `/criar` e selecione o canal desejado.
Após selecionar o canal, algumas perguntas vão ser feitas. Você deve responder elas da seguinte forma:
* A pergunta `Nome da setagem` deve ser respondida com o nome da setagem, que é o nome do grupo que vai ser utilizado dentro do jogo (através do evento) para abrir/fechar o ponto. Exemplo: `Policia`.
* A pergunta `Nome de exibição` é o nome que vai ser exibido no Discord, quando o bot enviar uma mensagem. Exemplo: `Los Santos Police`.
Um **conhecimento básico** de **desenvolvimento** é suficiente para realizar essa etapa.
Nesse passo, é necessário integrar o evento do script no seu servidor, no script responsável por entrar/sair de serviço dentro do jogo. Você deve adicionar o seguinte evento:
```lua server.lua theme={null}
TriggerEvent("servicex:service:toggle", user_id, group, true/false)
```
> * `user_id` é o ID do usuário que está entrando/saindo de serviço.
> * `group` é o grupo do usuário que está entrando/saindo de serviço. Deve ter o mesmo nome de um grupo/setagem definido anteriormente pelo comando `/criar` (para fechar o ponto esse parâmetro pode ser nulo).
> * Utilize `true` para iniciar o ponto e `false` para fechar o ponto.
O último passo, é vincular os jogadores. Para isso você deve utilizar o comando `/vincular` e selecionar o jogador desejado e inserir o ID desse jogador dentro do jogo.
Não só os administradores conseguem executar esse comando, os usuários que estão nos cargos definidos como **Supervisores** no comando `/criar` também conseguem, então você pode solicitar à eles que vinculem os jogadores 😄
# Termos de Uso
Source: https://docs.heyyshop.com.br/terms
Fique por dentro de nossos termos para aquisição, utilização de nossos serviços e prestação de suporte.
Deixamos claro que, ao adquirir ou utilizar nossos produtos, você automaticamente concorda com os termos descritos nesta página.
Ao adquirir ou utilizar qualquer produto pertencente à nossa plataforma, **HeyyShop**, você concorda automaticamente e compromete-se a seguir os termos descritos abaixo.
A utilização dos serviços da **HeyyShop** está diretamente sujeita às condições apresentadas, e qualquer violação destas resultará na **perda** dos direitos de utilização, licenças de produtos e/ou suporte.
Nestes termos, o termo "nós", "nosso(a)" refere-se especificamente à **HeyyShop**. A palavra "serviços" neste documento refere-se aos serviços, sites e outros produtos fornecidos pela **HeyyShop**. O termo "você" refere-se ao usuário ou à entidade que está acessando nossos serviços. Se estiver acessando em nome de uma entidade, como seu empregador, você declara ter autoridade para vincular essa entidade a estes termos, e "você" referir-se-á a essa entidade.
# Condições de Aquisição
1. Poderão ser aplicadas taxas, dependendo do método de pagamento escolhido.
2. Você não pode ter associação com grupos, servidores ou comunidades envolvidos em vazamento de produtos.
3. É estritamente proibida a revenda de produtos, em qualquer circunstância.
4. Produtos mensais possuem duração de 30 dias, independente do mês.
5. Alguns produtos podem estar anunciados em lojas de terceiros. Nessas lojas, os produtos se encontrarão com valores diferentes dos anunciados em [**nosso Discord**](https://heyyshop.com.br/discord).
6. Você aceita que todos os produtos são autenticados e **"obfuscado"** (ou seja, de código fechado sem a possibilidade de modificação), sendo proibida qualquer modificação, exceto configuração.
7. Tendo uma licença de um produto vitalício, você consegue adquirir uma licença adicional desse mesmo produto com 40% de desconto sobre o valor integral dele (o valor original, sem nenhum desconto de promoção aplicado).
8. Licenças adicionais ficam vinculdas à licença principal (primeira licença adquirida daquele produto) e não podem ser transferidas. Caso a licença principal seja transferida, a licença adicional também será transferida para a mesma conta.
9. Cada licença só pode ser transferida para uma outra conta do Discord uma única vez. Caso solicite a transferência novamente após isso, ela será imediatamente recusada.
10. Nossa equipe se reserva no direito de recusar a transferência de uma licença caso haja a suspeita de revenda.
# Política de Reembolso
Nós nos esforçamos para oferecer a melhor experiência aos nossos clientes. Portanto, nossa política de reembolso e direito de arrependimento é a seguinte:
1. Reembolso por Incompatibilidade e Erros: Estamos dispostos a fornecer reembolso para um produto caso sejam apresentadas **PROVAS** de:
* Incompatibilidade com o seu servidor.
* Erros/bugs que não tenham sido corrigidos pela nossa equipe de desenvolvimento.
2. Direito de Arrependimento: Como previsto pelo artigo 49 do CDC (Código de Defesa do Consumidor), você tem o direito de solicitar um reembolso por qualquer motivo, desde que o faça dentro de um período de **7 DIAS** após a aquisição. Nesse caso, o reembolso será concedido desde que a solicitação cumpra nossas políticas e termos.
## Condições Adicionais
* Não serão reembolsados os pagamentos por serviços já prestados por nossa equipe.
* Não serão reembolsados produtos pagos mensalmente (assinatura/plano mensal).
* Solicitações de reembolso sem motivo válido podem resultar na **perda** da **licença** e/ou do **suporte**.
Reconhecemos que o direito de arrependimento é um aspecto importante da sua experiência como cliente, e estamos comprometidos em atender a esses pedidos dentro do período especificado. Porém, é importante observar que o direito de arrependimento não se aplica a produtos que tenham sido usados indevidamente ou que estejam em desacordo com nossos termos e condições de uso.
# Condições de Uso
Ao utilizar nossos produtos, você concorda e compromete-se a seguir as seguintes condições:
1. Não é permitida a alteração de arquivos "obfuscados" ou relacionados à autenticação sem autorização.
2. Você não pode realizar, nem tentar realizar, ataques de negação de serviço em nossos servidores (autenticação, *website* e outros).
3. Não é permitido contornar, nem tentar contornar, nosso sistema de autenticação sem autorização direta.
4. A revenda de nossos produtos/sistemas não é autorizada.
5. É estritamente proibido usar **UMA** única licença em **DOIS** servidores distintos, mesmo que hospedados no mesmo endereço de IP.
**O que é considerado um arquivo "obfuscado"?**
Arquivos de autenticação, arquivos que não sejam **CLARAMENTE** legíveis e editáveis.
Esses arquivos normalmente estão na pasta **src** do produto, mas isso não é uma regra. Caso tenha dúvidas, entre em contato com nossa equipe de suporte.
# Suporte ao Cliente
Para receber suporte da nossa equipe, você concorda que:
1. Pedidos/requisições de suporte devem ser feitos por meio de tickets, não através de mensagens privadas.
2. Você não pode desrespeitar nenhum membro da nossa equipe.
3. Não deve violar nenhuma das condições mencionadas anteriormente.
4. Não deve mencionar membros da equipe ou atendentes da loja, a menos que seja solicitado.
* Todos somos **pessoas** e não **automações**! Isso ***não afetará*** a rapidez ou prioridade do atendimento em relação a outros clientes.
* Caso isso ocorra, seu ticket ou você poderá ser colocado em espera/"castigo" por um período definido por nossa equipe de suporte. O "castigo" se refere à função do Discord responsável por impedir que um determinado membro envie mensagens durante um período de tempo especificado.
5. Deve ser o titular da licença ou ter uma autorização direta do titular para receber suporte.
6. Se **COMPROMETE** a ajudar nossa equipe previamente, até mesmo fazendo com que seu atendimento seja mais rápido e eficiente, enviando-nos os arquivos do produto na qual você está enfrentando dificuldades.
7. Garantimos nosso suporte apenas dentro dos horários de atendimento/funcionamento, que são:
**Horários de Atendimento**
* **Segunda à Sexta-feira:** `13:30` às `18:00`
* **Final de Semana e Feriados:** `Fechado`
Esses horários são baseados no horário de Brasília (GMT-3) e podem ser alterados sem aviso prévio. Não garantimos **NENHUMA** resposta fora desses horários.
8. Garantimos nosso suporte gratuito para correção de erros/bugs para produtos que estejam dentro do prazo de suporte, que é de **90 dias** após a aquisição.
9. Garantimos a instalação de nossos produtos gratuitamente para solicitações realizadas até **7 dias** após a data da compra. Após esse período, ou em caso de reinstalação, será cobrada uma taxa de **R\$ 30,00** por produto a ser instalado.
10. Nosso serviço de instalação é limitado apenas à produtos da loja, podemos realizar a instalação de produtos de terceiros como consultoria. Custos a serem combinados com nossos atendentes.
11. Em caso de horários agendados, há uma tolerância de no **máximo 15 minutos**, para o início do atendimento, após o horário marcado para o atendimento ser iniciado. O horário de finalização do atendimento não será alterado, ou seja, em casos de atrasos a duração do atendimento poderá ser reduzida. Atendimentos que ultrapassarem esses 15 minutos de tolerância serão cancelados.
12. Todos os produtos ficam registrados em seu usuário do Discord. A segurança de sua conta é uma responsabilidade exclusivamente sua, portanto, não nos responsabilizamos por contas perdidas ou hackeadas.
13. A responsabilidade de realização de backup dos arquivos do seu servidor, do seu banco de dados e outros arquivos é do cliente. Somos humanos, erros podem acontecer durante os atendimentos e é importante que você possua um backup no caso disso ocorrer.
# Termos de Serviço
Ao adquirir ou utilizar nossos produtos, você reconhece que:
1. Reservamo-nos o direito de fazer alterações nestes termos, sem aviso prévio.
2. Não garantimos disponibilidade contínua dos nossos serviços 24 horas por dia.
3. Não somos responsáveis por qualquer vazamento de nossos produtos.
4. Podemos suspender licenças com base em suspeitas, como vazamentos.
5. Se estiver envolvido em qualquer vazamento de produto, suas licenças podem ser revogadas e o suporte pode ser negado.
6. Nem todos as funções de um produto podem ser compatíveis com sua base/seu servidor. Nossa equipe sempre tentará ao máximo entregar todas as funções funcionais, mas podem haver casos que isso não seja possível. Esse não é um motivo válido para nossa Política de Reembolso!
# Boas-vindas
Source: https://docs.heyyshop.com.br/welcome
Conheça a HeyyShop, uma loja focada em Scripts para FiveM, com foco em inovação, qualidade e performance.
A **HeyyShop** é uma loja de scripts focados no GTA Roleplay, dentro da plataforma FiveM.
Trabalhamos arduamente para trazer sistemas cada vez mais inovadores, com a maior qualidade e diferentes de tudo o que você já viu! Tudo isso com a melhor performance possível.
Nosso objetivo é trazer conforto e tranquilidade para os donos de servidores, além de **qualidade**, **desempenho** e **visuais** incríveis!
Adquira já seu script conosco e garanta o diferencial para seu servidor!