# custom commands

Create **unlimited custom commands** for your Discord bot. The `editable/custom_commands.lua` file is **fully open source** and can be freely modified.

***

## 📂 Open Source File

The file `editable/custom_commands.lua` is **not encrypted** and **fully editable**. You can:

* ✅ Create unlimited new commands
* ✅ Modify existing commands
* ✅ Add framework-specific functionality
* ✅ Integrate with other resources
* ✅ Use all FiveM natives and exports

***

## 🎯 Command Structure

Every custom command follows this structure:

```lua
CustomCommands.commandname = function(args, admin)
    -- args = table of arguments from Discord
    -- admin = Discord username who executed command
    
    -- Your code here...
    
    return { 
        success = true,      -- or false
        message = 'Result message for Discord'
    }
end
```

***

## 📝 Creating a New Command

{% stepper %}
{% step %}

### Add Command Function

Open `editable/custom_commands.lua` and add your command:

```lua
CustomCommands.weather = function(args, admin)
    local weatherType = args[1]
    
    if not weatherType then
        return { 
            success = false, 
            message = 'Usage: !weather [type]' 
        }
    end
    
    -- Execute your logic
    TriggerEvent('weathersync:setWeather', weatherType)
    
    -- Log the action
    SendLog('weather', admin, 'Changed weather to ' .. weatherType)
    
    return { 
        success = true, 
        message = '🌤️ Weather changed to **' .. weatherType .. '**' 
    }
end
```

{% endstep %}

{% step %}

### Add Permissions

In `shared/config.lua`:

```lua
Config.CommandPermissions = {
    -- ... existing commands
    ['weather'] = { roles = { 'ROLE_ID_HERE' } },
}
```

{% endstep %}

{% step %}

### Add Logging (Optional)

In `editable/logs.lua`:

```lua
LogsConfig.Commands = {
    -- ... existing commands
    weather = { enabled = true, webhook = '', color = 0x3498DB, title = 'Weather Changed' },
}
```

{% endstep %}

{% step %}

### Add to Help (Optional)

In `editable/help.lua`:

```lua
{
    name = 'Custom',
    commands = {
        { cmd = 'weather', params = '[type]', desc = 'Change weather' },
    }
}
```

{% endstep %}
{% endstepper %}

***

## 🛠️ Built-in Commands (Editable)

These commands come pre-built but are **fully editable**:

### Player Control

| Command        | Description            |
| -------------- | ---------------------- |
| `!heal`        | Heal player to full HP |
| `!revive`      | Revive dead player     |
| `!freeze`      | Freeze player in place |
| `!unfreeze`    | Unfreeze player        |
| `!crashplayer` | Crash player's game    |

### Economy (Framework)

| Command      | Description            |
| ------------ | ---------------------- |
| `!givemoney` | Give money (cash/bank) |
| `!giveitem`  | Give inventory item    |
| `!givecar`   | Spawn vehicle          |

### Jobs (Framework)

| Command     | Description          |
| ----------- | -------------------- |
| `!setjob`   | Set player job       |
| `!setgroup` | Set permission group |

### Teleport

| Command     | Description             |
| ----------- | ----------------------- |
| `!bring`    | Bring player to another |
| `!teleport` | Teleport to coordinates |

### Utilities

| Command       | Description          |
| ------------- | -------------------- |
| `!announce`   | Server announcement  |
| `!ss`         | Take screenshot      |
| `!blackout`   | Toggle lights        |
| `!ping`       | Bot status           |
| `!serverinfo` | Server info          |
| `!player`     | Detailed player info |
| `!help`       | Show all commands    |

***

## 🎮 Framework Detection

The script auto-detects your framework:

```lua
-- Available in custom_commands.lua:
ESX      -- ESX shared object (or nil)
QBCore   -- QB-Core object (or nil)
```

### ESX Example

```lua
CustomCommands.addmoney = function(args, admin)
    local pid = tonumber(args[1])
    local amount = tonumber(args[2]) or 0
    
    if not ESX then
        return { success = false, message = 'ESX not found!' }
    end
    
    local xPlayer = ESX.GetPlayerFromId(pid)
    if xPlayer then
        xPlayer.addMoney(amount)
        return { success = true, message = 'Added $' .. amount }
    end
    
    return { success = false, message = 'Player not found' }
end
```

### QB-Core Example

```lua
CustomCommands.addmoney = function(args, admin)
    local pid = tonumber(args[1])
    local amount = tonumber(args[2]) or 0
    
    if not QBCore then
        return { success = false, message = 'QB-Core not found!' }
    end
    
    local Player = QBCore.Functions.GetPlayer(pid)
    if Player then
        Player.Functions.AddMoney('cash', amount)
        return { success = true, message = 'Added $' .. amount }
    end
    
    return { success = false, message = 'Player not found' }
end
```

***

## 🔌 Using Other Resources

Call exports from other resources:

```lua
CustomCommands.givelicense = function(args, admin)
    local pid = tonumber(args[1])
    local license = args[2]
    
    -- Example: Using another resource's export
    exports['your-license-resource']:giveLicense(pid, license)
    
    return { success = true, message = 'License given!' }
end
```

***

## 📡 Client Events

Trigger client-side events:

```lua
-- Server-side (custom_commands.lua)
CustomCommands.notify = function(args, admin)
    local pid = tonumber(args[1])
    local message = table.concat(args, ' ', 2)
    
    TriggerClientEvent('myresource:showNotification', pid, message)
    
    return { success = true, message = 'Notification sent!' }
end
```

***

## ✅ Helper Functions

Available helper functions:

```lua
-- Check if player is online
local function IsOnline(pid)
    return GetPlayerName(pid) ~= nil
end

-- Get player name (works with frameworks)
local function GetPlayerNameSafe(src)
    if ESX then
        local xPlayer = ESX.GetPlayerFromId(src)
        if xPlayer then return xPlayer.getName() end
    end
    if QBCore then
        local player = QBCore.Functions.GetPlayer(src)
        if player then
            local c = player.PlayerData.charinfo
            return c.firstname .. ' ' .. c.lastname
        end
    end
    return GetPlayerName(src) or 'Unknown'
end

-- Send log to webhook
SendLog(commandName, admin, message)

-- Get translation
L('translation_key', arg1, arg2, ...)
```

***

## 💡 Example Commands

### Revive All Players

```lua
CustomCommands.reviveall = function(args, admin)
    local players = GetPlayers()
    local count = 0
    
    for _, pid in ipairs(players) do
        TriggerClientEvent('sl-bot:revive', tonumber(pid))
        count = count + 1
    end
    
    SendLog('reviveall', admin, 'Revived ' .. count .. ' players')
    return { success = true, message = '💚 Revived **' .. count .. '** players' }
end
```

### Clear Inventory

```lua
CustomCommands.clearinv = function(args, admin)
    local pid = tonumber(args[1])
    
    if not pid or not IsOnline(pid) then
        return { success = false, message = L('player_not_online') }
    end
    
    if GetResourceState('ox_inventory') == 'started' then
        exports.ox_inventory:ClearInventory(pid)
    elseif ESX then
        local xPlayer = ESX.GetPlayerFromId(pid)
        for _, item in pairs(xPlayer.getInventory()) do
            if item.count > 0 then
                xPlayer.removeInventoryItem(item.name, item.count)
            end
        end
    end
    
    local name = GetPlayerNameSafe(pid)
    SendLog('clearinv', admin, 'Cleared inventory for ' .. name)
    return { success = true, message = '🗑️ Cleared inventory for **' .. name .. '**' }
end
```

### Set Time

```lua
CustomCommands.time = function(args, admin)
    local hour = tonumber(args[1]) or 12
    local minute = tonumber(args[2]) or 0
    
    ExecuteCommand('time ' .. hour .. ' ' .. minute)
    
    SendLog('time', admin, 'Set time to ' .. hour .. ':' .. minute)
    return { success = true, message = '🕐 Time set to **' .. hour .. ':' .. string.format('%02d', minute) .. '**' }
end
```

### Get Player Vehicle

```lua
CustomCommands.getveh = function(args, admin)
    local pid = tonumber(args[1])
    
    if not pid or not IsOnline(pid) then
        return { success = false, message = L('player_not_online') }
    end
    
    local ped = GetPlayerPed(pid)
    local vehicle = GetVehiclePedIsIn(ped, false)
    
    if vehicle == 0 then
        return { success = true, message = '❌ Player is not in a vehicle' }
    end
    
    local model = GetEntityModel(vehicle)
    local name = GetDisplayNameFromVehicleModel(model)
    local plate = GetVehicleNumberPlateText(vehicle)
    
    return { 
        success = true, 
        message = '🚗 **' .. GetPlayerNameSafe(pid) .. '** is in:\nVehicle: `' .. name .. '`\nPlate: `' .. plate .. '`' 
    }
end
```

***

## ⚠️ Important Notes

1. **Always validate input** - Check if player ID exists, if arguments are valid
2. **Use SendLog** - Log all administrative actions for accountability
3. **Return proper response** - Always return `{ success, message }`
4. **Test thoroughly** - Test commands before using in production
5. **Don't break escrow** - Only edit files in `editable/` folder
