# Creating Scripts

Learn how to build scripts that integrate with NOVA Framework.

## Script Structure

```
nova_myscript/
├── fxmanifest.lua          # Resource manifest
├── config.lua              # Script configuration
├── locales.lua             # Translations (PT/EN)
├── client/
│   └── main.lua            # Client-side logic
├── server/
│   └── main.lua            # Server-side logic
├── html/                   # NUI (optional)
│   ├── index.html
│   ├── style.css
│   └── script.js
└── sql/                    # Database schema (optional)
    └── myscript.sql
```

## Step 1: fxmanifest.lua

```lua
fx_version 'cerulean'
game 'gta5'

name 'nova_myscript'
description 'My Custom Script for NOVA'
author 'YourName'
version '1.0.0'

dependencies {
    'nova_core',
}

shared_scripts {
    'config.lua',
    'locales.lua',
}

client_scripts {
    'client/main.lua',
}

server_scripts {
    '@oxmysql/lib/MySQL.lua',
    'server/main.lua',
}

-- Only if you have NUI:
-- ui_page 'html/index.html'
-- files { 'html/index.html', 'html/style.css', 'html/script.js' }
```

## Step 2: Config

```lua
-- config.lua
ScriptConfig = {}
ScriptConfig.SomeSetting = true
ScriptConfig.SomeValue = 42
```

## Step 3: Locales

```lua
-- locales.lua
local Locales = {
    ['pt'] = {
        ['hello'] = 'Olá, %s!',
        ['error'] = 'Ocorreu um erro.',
    },
    ['en'] = {
        ['hello'] = 'Hello, %s!',
        ['error'] = 'An error occurred.',
    },
}

local currentLocale = nil
local function getLocale()
    if not currentLocale then
        local ok, cfg = pcall(function()
            return exports['nova_core']:GetConfig()
        end)
        currentLocale = (ok and cfg and cfg.Locale) or 'pt'
    end
    return currentLocale
end

function L(key, ...)
    local lang = getLocale()
    local str = (Locales[lang] and Locales[lang][key])
        or (Locales['pt'] and Locales['pt'][key])
        or key
    if select('#', ...) > 0 then
        return string.format(str, ...)
    end
    return str
end

function GetAllStrings()
    local lang = getLocale()
    return Locales[lang] or Locales['pt'] or {}
end
```

## Step 4: Server Logic

```lua
-- server/main.lua

-- Register a callback for client requests
Nova.Functions.CreateCallback('myscript:getData', function(source, cb)
    local player = Nova.Functions.GetPlayer(source)
    if not player then
        cb(nil)
        return
    end
    
    cb({
        name = player.fullname,
        money = player:GetMoney(),
    })
end)

-- Listen for events
RegisterNetEvent('myscript:doAction')
AddEventHandler('myscript:doAction', function(data)
    local source = source
    local player = Nova.Functions.GetPlayer(source)
    
    if not player then return end
    
    -- Validate on server side!
    if data.amount < 0 then return end
    
    player:RemoveMoney(data.amount)
    Nova.Functions.Notify(source, L('success'), 'success')
end)
```

## Step 5: Client Logic

```lua
-- client/main.lua

-- Get data from server via callback
exports['nova_core']:TriggerCallback('myscript:getData', function(data)
    if data then
        print('Welcome, ' .. data.name)
    end
end)

-- Send action to server
TriggerServerEvent('myscript:doAction', {
    amount = 100,
})

-- Show notification
exports['nova_notify']:Notify('Hello!', 'success', 5000)
```

## Step 6: NUI (Optional)

### HTML

```html
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="container" style="display:none;">
        <h1 id="i18n-title">Title</h1>
        <button id="close-btn">Close</button>
    </div>
    <script src="script.js"></script>
</body>
</html>
```

### CSS (NOVA Theme)

```css
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: transparent; font-family: 'Segoe UI', sans-serif; }

#container {
    position: fixed;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: 500px;
    background: rgba(15, 15, 25, 0.95);
    border: 1px solid rgba(132, 204, 22, 0.3);
    border-radius: 16px;
    padding: 24px;
    color: #e4e4e7;
    backdrop-filter: blur(20px);
}

h1 { color: #84cc16; }

button {
    background: linear-gradient(135deg, #84cc16, #65a30d);
    border: none;
    padding: 10px 24px;
    border-radius: 8px;
    color: #000;
    font-weight: 600;
    cursor: pointer;
}
```

### JavaScript

```javascript
var locale = {};

window.addEventListener('message', function(event) {
    var d = event.data;
    if (d.action === 'open') {
        locale = d.locale || {};
        document.getElementById('container').style.display = 'block';
        applyLocale();
    } else if (d.action === 'close') {
        document.getElementById('container').style.display = 'none';
    }
});

function applyLocale() {
    var el = document.getElementById('i18n-title');
    if (el && locale['nui_title']) el.textContent = locale['nui_title'];
}

document.getElementById('close-btn').addEventListener('click', function() {
    fetch('https://nova_myscript/close', { method: 'POST' });
});
```

## Best Practices

::: tip

1. **Always validate on server** - Never trust client data
2. **Use callbacks for data fetching** - Not raw events
3. **Follow the NOVA theme** - Dark background, lime green (#84cc16) accents
4. **Support multi-language** - Use the locales pattern
5. **Namespace your events** - Use `scriptname:eventname` format :::
