# LT Language

<p align="center">
  <img src="https://img.shields.io/npm/v/lt-script?color=blue&label=npm" alt="npm version">
  <img src="https://img.shields.io/github/license/laot7490/lt-script" alt="license">
  <img src="https://img.shields.io/badge/FiveM-Ready-green" alt="FiveM Ready">
</p>

**LT** is a modern, statically-typed superset of Lua designed specifically for **FiveM development**. It combines the elegance of TypeScript with the performance of Lua, adding FiveM-specific syntactic sugar to make your scripts robust, readable, and faster to write.

> **Goodbye boilerplate, hello productivity.**  
> Write clean, type-safe code that compiles to optimized 100% vanilla Lua.

---

## ✨ Why LT?

*   **🛡️ Type Safety**: Catch type mismatches and `nil` errors *before* you run the game.
*   **⚡ Modern Syntax**: Use Arrow Functions, Destructuring, Spread syntax, and more.
*   **🎮 FiveM-First**: Built-in keywords like `netevent`, `addcmd`, `thread`, and `wait`.
*   **🔌 Zero Overhead**: Compiles to pure, readable Lua with no runtime dependencies.

---

## 📦 Installation

Prerequisites: [Node.js](https://nodejs.org/) (Version 16+)

```bash
# Global installation (Recommended)
npm install -g lt-script

# OR run directly via npx
npx lt-script build .
```

---

## 🚀 Quick Start

Create a `client.lt` file:

```typescript
// Define a type for player data
interface PlayerData {
    id: number,
    name: string,
    health: number
}

// Variables with types
let active: boolean = false
const MAX_HEALTH = 100

// FiveM Command
addcmd "heal" (source, args)
    let amount = tonumber(args[1]) ?? MAX_HEALTH
    SetEntityHealth(PlayerPedId(), amount)
    print("Healed for ${amount}")
end

// Thread with loop
thread
    print("System active")
    loop (true)
        wait 1000
        if LocalPlayer.state?.isDead then
            print("Player is dead!")
        end
    end
end
```

**Compile it:**
```bash
ltc build .
```

---

## 📘 Language Reference

### 1. Variables & Types

LT supports explicit typing with compile-time validation.

```typescript
// Mutable variables
let score: number = 0
var playerName: string = "John"     // Type inferred if omitted

// Constants (Compiles to Lua 5.4 <const>)
const MAX_PLAYERS = 32

// Available primitive types
let str: string = "hello"
let num: number = 42
let flag: boolean = true
let data: table = { key: "value" }
let pos: vector3 = <100.0, 200.0, 30.0>
let callback: function = () => print("hi")

// Arrays
let inventory: string[] = ["Apple", "Water"]
let numbers: number[] = [1, 2, 3]
```

### 2. Interfaces & Type Aliases

Define complex data structures for compile-time validation.

```typescript
// Interface - Object shape definition
interface VehicleConfig {
    model: string,
    price: number,
    color: string
}

// Type Alias - Alternative syntax
type PlayerPos = { x: number, y: number, z: number }

// Usage with validation
const myCar: VehicleConfig = {
    model: "sultan",
    price: 50000,
    color: "red"
}

// Arrays of interfaces
interface StoreConfig {
    id: number,
    position: vector3,
    isOpen: boolean
}

const Stores: StoreConfig[] = [
    { id: 1, position: <100.0, 200.0, 30.0>, isOpen: true },
    { id: 2, position: <150.0, 250.0, 35.0>, isOpen: false }
]
```

> **Note:** Type validation ensures field types match. Assigning `number` to a `vector3` field will cause a compile error.

### 3. Functions

```typescript
// Standard function with typed parameters
func Add(a: number, b: number)
    return a + b
end

// Default parameters
func Greet(name: string, prefix = "Hello")
    print("${prefix}, ${name}!")
end

// Local function (Lua local function)
local function PrivateHelper()
    return "internal"
end

// Arrow functions
let double = (x: number) => x * 2
let greet = (name) => print("Hello ${name}")

// Multi-line arrow
let process = (data) => {
    let result = data * 2
    return result
}
```

### 4. Control Flow

#### If / Else
```typescript
// Note: 'then' keyword is required after condition
if health < 20 then
    print("Low health!")
elseif health < 50 then
    print("Medium health")
else
    print("Full health")
end
```

#### Switch / Case
```typescript
let job = "police"

switch job
    case "police", "ambulance"
        print("Government worker")
    case "mechanic"
        print("Service worker")
    default
        print("Civilian")
end
```

#### Guard Clauses
Clean up nested if-statements with early returns.

```typescript
func RevivePlayer(player)
    // Returns immediately if player is nil
    guard player return
    
    // Returns with custom logic if condition fails
    guard player.isDead else
        print("Player is already alive")
        return
    end

    // Main logic
    player.revive()
end

// Guard with return value
func GetPlayer(id)
    let player = GetPlayerById(id)
    guard player return nil
    return player
end
```

#### For Loops
```typescript
// Numeric for (start, end)
for i = 1, 10 do
    print(i)
end

// Numeric for with step (start, end, step)
for i = 0, 100, 5 do
    print(i)
end

// Range for with step
for i in 1..10 by 2 do
    print(i)
end

// For-in (pairs)
for key, value in pairs(myTable) do
    print("${key}: ${value}")
end

// For-in (ipairs)
for index, item in ipairs(myArray) do
    print("${index}: ${item}")
end
```

#### While Loop
```typescript
let count = 0
while count < 10 do
    print(count)
    count += 1
end
```

### 5. Modern Operators

#### Compound Assignment
```typescript
let x = 10
x += 5
x -= 3
x *= 2
x /= 4
x %= 3
```

#### Null Coalescing (`??`)
```typescript
let name = playerName ?? "Unknown"
let health = GetHealth() ?? 100
```

#### Optional Chaining (`?.`)
```typescript
let state = LocalPlayer.state?.isDead
let nested = obj?.deep?.value
let arrItem = arr?[0]
```

#### Ternary Operator
```typescript
let status = isDead ? "Dead" : "Alive"
let label = count > 0 ? "${count} items" : "Empty"
```

### 6. Destructuring & Spread

```typescript
// Object Destructuring
let { x, y, z } = GetEntityCoords(ped)
let { name, health } = playerData

// Array Destructuring
let [first, second] = GetValues()

// Object Spread (tables only)
let base = { a: 1, b: 2 }
let extended = { ...base, c: 3 }
```

### 7. String Interpolation

Use `${expression}` inside strings to embed values:

```typescript
let name = "John"
let age = 25

print("Hello, ${name}!")
print("You are ${age} years old")
print("Next year you'll be ${age + 1}")

// Complex expressions
let player = { health: 100 }
print("Health: ${player.health}")
```

### 8. Vector Literals

```typescript
// Vector3 (FiveM native)
let pos: vector3 = <100.0, 200.0, 30.0>

// Vector2
let screenPos: vector2 = <0.5, 0.5>

// Vector4 (includes heading)
let spawn: vector4 = <100.0, 200.0, 30.0, 90.0>
```

---

## 🎮 FiveM Features

### Thread & Loop

```typescript
// Create a thread (Citizen.CreateThread)
thread
    print("Thread started")
    
    loop (true)
        wait 0  // Run every frame
        
        // Game logic here
        let ped = PlayerPedId()
        let health = GetEntityHealth(ped)
        
        if health < 50 then
            print("Low health warning!")
        end
    end
end
```

### Wait

```typescript
// Wait in milliseconds
wait 1000           // Wait 1 second
wait 0              // Yield one frame
```

### Network Events

```typescript
// Register + Handle network event (Client <-> Server)
netevent "bank:deposit" (amount)
    print("Depositing ${amount}")
    UpdateBankBalance(amount)
end

// Local event handler
event "onClientResourceStart" (resName)
    guard resName == GetCurrentResourceName() return
    print("Resource started!")
end
```

### Emit Events

```typescript
// Emit to server
emit "server:event:name" (arg1, arg2)

// Explicit emit variants
emitServer "myevent" (data)
emitClient "myevent" (targetPlayer, data)
```

### Commands

```typescript
// Register a command (RegisterCommand wrapper)
addcmd "teleport" (source, args)
    let x = tonumber(args[1]) ?? 0
    let y = tonumber(args[2]) ?? 0
    let z = tonumber(args[3]) ?? 0
    
    SetEntityCoords(PlayerPedId(), x, y, z)
    print("Teleported to ${x}, ${y}, ${z}")
end
```

### Exports

```typescript
// Export a function
export "GetPlayerMoney" ()
    return playerMoney
end
```

### Timeout & Interval

```typescript
// Run once after delay
timeout 5000
    print("5 seconds passed!")
end

// Run repeatedly
interval 1000
    print("Every second")
end
```

### Try / Catch

```typescript
try
    RiskyOperation()
catch err
    print("Error: ${err}")
end
```

---

## ⚡ Complete Example: Store Robbery System

```typescript
// 1. Type Definition
interface StoreConfig {
    id: number,
    position: vector3,
    reward: number,
    isOpen: boolean
}

// 2. Configuration
const Stores: StoreConfig[] = [
    { id: 1, position: <120.5, -500.2, 30.0>, reward: 5000, isOpen: true },
    { id: 2, position: <250.0, 300.0, 25.0>, reward: 10000, isOpen: true }
]

let isRobbing = false

// 3. Main Game Loop
thread
    loop (true)
        wait 0
        
        if isRobbing then
            break
        end
        
        let ped = PlayerPedId()
        let pos = GetEntityCoords(ped)
        
        for _, store in ipairs(Stores) do
            if not store.isOpen then
                break
            end
            
            let distance = #(pos - store.position)
            if distance < 2.0 then
                ShowHelpText("Press ~INPUT_CONTEXT~ to rob")
                
                if IsControlJustPressed(0, 38) then
                    StartRobbery(store)
                end
            end
        end
    end
end

// 4. Robbery Function
func StartRobbery(store: StoreConfig)
    isRobbing = true
    
    // Notify server
    emit "robbery:start" (store.id)
    
    // Play animation
    TaskPlayAnim(PlayerPedId(), "anim_dict", "anim_name", 8.0, -8.0, -1, 0, 0, false, false, false)
    
    wait 5000
    
    ClearPedTasks(PlayerPedId())
    isRobbing = false
    
    print("Robbery complete! Reward: ${store.reward}")
end

// 5. Server Sync Handler
netevent "robbery:sync" (storeId, newState)
    let store = Stores.find(s => s.id == storeId)
    guard store return
    
    store.isOpen = newState
    let stateStr = newState ? "open" : "closed"
    print("Store ${storeId} is now ${stateStr}")
end
```

---

## 🛠️ CLI Reference

| Command | Usage | Description |
|:--------|:------|:------------|
| **Build** | `ltc build ./` | Compiles all `.lt` files in the folder to `.lua` |
| **Watch** | `ltc watch ./` | Watches for file changes and recompiles instantly |
| **Version** | `ltc -v` | Displays the current compiler version |

### Project Structure

LT automatically detects `src/` folders:

```
my-resource/
├── src/
│   ├── client.lt
│   └── server.lt
├── client.lua      ← Generated
└── server.lua      ← Generated
```

---

## 🔧 VS Code Extension

Get the official **[LT Language Extension](https://marketplace.visualstudio.com/items?itemName=laot.lt-language)** for the best experience.

**Features:**
*   🎨 Full Syntax Highlighting
*   🔍 Intelligent Autocompletion
*   📦 **FiveM Native Intellisense**
*   ✨ Real-time Error Checking

---

<p align="center">
    Made with ❤️ for the FiveM Community by <b>LaotScripts</b>
</p>
