lt-script 1.0.3 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +439 -147
- package/dist/cli/ltc.js +6 -2
- package/dist/cli/utils.d.ts +1 -0
- package/dist/cli/utils.js +21 -0
- package/dist/compiler/codegen/LuaEmitter.js +1 -0
- package/dist/compiler/parser/AST.d.ts +6 -0
- package/dist/compiler/parser/AST.js +1 -0
- package/dist/compiler/parser/Parser.d.ts +2 -0
- package/dist/compiler/parser/Parser.js +77 -7
- package/dist/compiler/semantics/SemanticAnalyzer.d.ts +5 -0
- package/dist/compiler/semantics/SemanticAnalyzer.js +287 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,269 +6,561 @@
|
|
|
6
6
|
<img src="https://img.shields.io/badge/FiveM-Ready-green" alt="FiveM Ready">
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
|
-
**LT** is a modern,
|
|
9
|
+
**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.
|
|
10
|
+
|
|
11
|
+
> **Goodbye boilerplate, hello productivity.**
|
|
12
|
+
> Write clean, type-safe code that compiles to optimized 100% vanilla Lua.
|
|
13
|
+
|
|
14
|
+
---
|
|
10
15
|
|
|
11
16
|
## ✨ Why LT?
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
* **🛡️ Type Safety**: Catch type mismatches and `nil` errors *before* you run the game.
|
|
19
|
+
* **⚡ Modern Syntax**: Use Arrow Functions, Destructuring, Spread syntax, and more.
|
|
20
|
+
* **🎮 FiveM-First**: Built-in keywords like `netevent`, `addcmd`, `thread`, and `wait`.
|
|
21
|
+
* **🔌 Zero Overhead**: Compiles to pure, readable Lua with no runtime dependencies.
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
- **FiveM Sugar**: Built-in `thread`, `wait`, `netevent`, `addcmd`, `export` keywords
|
|
17
|
-
- **Type Safety**: Static type checking catches errors at compile time
|
|
18
|
-
- **Clean Code**: No more boilerplate — just write what you mean
|
|
23
|
+
---
|
|
19
24
|
|
|
20
25
|
## 📦 Installation
|
|
21
26
|
|
|
27
|
+
Prerequisites: [Node.js](https://nodejs.org/) (Version 16+)
|
|
28
|
+
|
|
22
29
|
```bash
|
|
30
|
+
# Global installation (Recommended)
|
|
23
31
|
npm install -g lt-script
|
|
32
|
+
|
|
33
|
+
# OR run directly via npx
|
|
34
|
+
npx lt-script build .
|
|
24
35
|
```
|
|
25
36
|
|
|
37
|
+
---
|
|
38
|
+
|
|
26
39
|
## 🚀 Quick Start
|
|
27
40
|
|
|
28
|
-
Create a
|
|
41
|
+
Create a `client.lt` file:
|
|
29
42
|
|
|
30
43
|
```typescript
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
// Define a type for player data
|
|
45
|
+
interface PlayerData {
|
|
46
|
+
id: number,
|
|
47
|
+
name: string,
|
|
48
|
+
health: number
|
|
49
|
+
}
|
|
34
50
|
|
|
35
|
-
//
|
|
36
|
-
let
|
|
51
|
+
// Variables with types
|
|
52
|
+
let active: boolean = false
|
|
53
|
+
const MAX_HEALTH = 100
|
|
37
54
|
|
|
38
|
-
//
|
|
39
|
-
|
|
55
|
+
// FiveM Command
|
|
56
|
+
addcmd "heal" (source, args)
|
|
57
|
+
let amount = tonumber(args[1]) ?? MAX_HEALTH
|
|
58
|
+
SetEntityHealth(PlayerPedId(), amount)
|
|
59
|
+
print("Healed for ${amount}")
|
|
60
|
+
end
|
|
40
61
|
|
|
41
|
-
//
|
|
62
|
+
// Thread with loop
|
|
42
63
|
thread
|
|
64
|
+
print("System active")
|
|
43
65
|
loop (true)
|
|
44
66
|
wait 1000
|
|
45
|
-
|
|
67
|
+
if LocalPlayer.state?.isDead then
|
|
68
|
+
print("Player is dead!")
|
|
69
|
+
end
|
|
46
70
|
end
|
|
47
71
|
end
|
|
48
|
-
|
|
49
|
-
// Register a command easily
|
|
50
|
-
addcmd "heal" (source, args)
|
|
51
|
-
health = MAX_HEALTH
|
|
52
|
-
print("Player healed!")
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
// Network events without boilerplate
|
|
56
|
-
netevent "player:spawn" (data)
|
|
57
|
-
print("Player spawned: $data")
|
|
58
|
-
end
|
|
59
72
|
```
|
|
60
73
|
|
|
61
|
-
Compile it
|
|
62
|
-
|
|
74
|
+
**Compile it:**
|
|
63
75
|
```bash
|
|
64
76
|
ltc build .
|
|
65
77
|
```
|
|
66
78
|
|
|
67
|
-
|
|
68
|
-
```lua
|
|
69
|
-
local health = 100
|
|
70
|
-
local MAX_HEALTH <const> = 200
|
|
79
|
+
---
|
|
71
80
|
|
|
72
|
-
|
|
81
|
+
## 📘 Language Reference
|
|
73
82
|
|
|
74
|
-
|
|
83
|
+
### 1. Variables & Types
|
|
75
84
|
|
|
76
|
-
|
|
77
|
-
while true do
|
|
78
|
-
Wait(1000)
|
|
79
|
-
print("Tick...")
|
|
80
|
-
end
|
|
81
|
-
end)
|
|
85
|
+
LT supports explicit typing with compile-time validation.
|
|
82
86
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
```typescript
|
|
88
|
+
// Mutable variables
|
|
89
|
+
let score: number = 0
|
|
90
|
+
var playerName: string = "John" // Type inferred if omitted
|
|
91
|
+
|
|
92
|
+
// Constants (Compiles to Lua 5.4 <const>)
|
|
93
|
+
const MAX_PLAYERS = 32
|
|
94
|
+
|
|
95
|
+
// Available primitive types
|
|
96
|
+
let str: string = "hello"
|
|
97
|
+
let num: number = 42
|
|
98
|
+
let flag: boolean = true
|
|
99
|
+
let data: table = { key: "value" }
|
|
100
|
+
let pos: vector3 = <100.0, 200.0, 30.0>
|
|
101
|
+
let callback: function = () => print("hi")
|
|
102
|
+
|
|
103
|
+
// Arrays
|
|
104
|
+
let inventory: string[] = ["Apple", "Water"]
|
|
105
|
+
let numbers: number[] = [1, 2, 3]
|
|
92
106
|
```
|
|
93
107
|
|
|
94
|
-
|
|
108
|
+
### 2. Interfaces & Type Aliases
|
|
95
109
|
|
|
96
|
-
|
|
97
|
-
|---------|-------------|
|
|
98
|
-
| `ltc build <dir>` | Compile all `.lt` files in directory |
|
|
99
|
-
| `ltc watch <dir>` | Watch mode — auto-compile on save |
|
|
110
|
+
Define complex data structures for compile-time validation.
|
|
100
111
|
|
|
101
|
-
## 🎯 Feature Highlights
|
|
102
|
-
|
|
103
|
-
### Variables & Constants
|
|
104
112
|
```typescript
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
113
|
+
// Interface - Object shape definition
|
|
114
|
+
interface VehicleConfig {
|
|
115
|
+
model: string,
|
|
116
|
+
price: number,
|
|
117
|
+
color: string
|
|
118
|
+
}
|
|
109
119
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// Explicit types
|
|
113
|
-
let name: string = "John"
|
|
114
|
-
let age: number = 25
|
|
115
|
-
let active: boolean = true
|
|
120
|
+
// Type Alias - Alternative syntax
|
|
121
|
+
type PlayerPos = { x: number, y: number, z: number }
|
|
116
122
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
// Usage with validation
|
|
124
|
+
const myCar: VehicleConfig = {
|
|
125
|
+
model: "sultan",
|
|
126
|
+
price: 50000,
|
|
127
|
+
color: "red"
|
|
122
128
|
}
|
|
123
129
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
130
|
+
// Arrays of interfaces
|
|
131
|
+
interface StoreConfig {
|
|
132
|
+
id: number,
|
|
133
|
+
position: vector3,
|
|
134
|
+
isOpen: boolean
|
|
135
|
+
}
|
|
128
136
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
137
|
+
const Stores: StoreConfig[] = [
|
|
138
|
+
{ id: 1, position: <100.0, 200.0, 30.0>, isOpen: true },
|
|
139
|
+
{ id: 2, position: <150.0, 250.0, 35.0>, isOpen: false }
|
|
140
|
+
]
|
|
133
141
|
```
|
|
134
142
|
|
|
135
|
-
|
|
143
|
+
> **Note:** Type validation ensures field types match. Assigning `number` to a `vector3` field will cause a compile error.
|
|
144
|
+
|
|
145
|
+
### 3. Functions
|
|
146
|
+
|
|
136
147
|
```typescript
|
|
137
|
-
|
|
138
|
-
|
|
148
|
+
// Standard function with typed parameters
|
|
149
|
+
func Add(a: number, b: number)
|
|
150
|
+
return a + b
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
// Default parameters
|
|
154
|
+
func Greet(name: string, prefix = "Hello")
|
|
155
|
+
print("${prefix}, ${name}!")
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
// Local function (Lua local function)
|
|
159
|
+
local function PrivateHelper()
|
|
160
|
+
return "internal"
|
|
161
|
+
end
|
|
139
162
|
|
|
140
|
-
|
|
141
|
-
let
|
|
163
|
+
// Arrow functions
|
|
164
|
+
let double = (x: number) => x * 2
|
|
165
|
+
let greet = (name) => print("Hello ${name}")
|
|
166
|
+
|
|
167
|
+
// Multi-line arrow
|
|
168
|
+
let process = (data) => {
|
|
169
|
+
let result = data * 2
|
|
170
|
+
return result
|
|
171
|
+
}
|
|
142
172
|
```
|
|
143
173
|
|
|
144
|
-
###
|
|
174
|
+
### 4. Control Flow
|
|
175
|
+
|
|
176
|
+
#### If / Else
|
|
145
177
|
```typescript
|
|
146
|
-
|
|
178
|
+
// Note: 'then' keyword is required after condition
|
|
179
|
+
if health < 20 then
|
|
180
|
+
print("Low health!")
|
|
181
|
+
elseif health < 50 then
|
|
182
|
+
print("Medium health")
|
|
183
|
+
else
|
|
184
|
+
print("Full health")
|
|
185
|
+
end
|
|
147
186
|
```
|
|
148
187
|
|
|
149
|
-
|
|
188
|
+
#### Switch / Case
|
|
150
189
|
```typescript
|
|
151
|
-
let
|
|
152
|
-
|
|
190
|
+
let job = "police"
|
|
191
|
+
|
|
192
|
+
switch job
|
|
193
|
+
case "police", "ambulance"
|
|
194
|
+
print("Government worker")
|
|
195
|
+
case "mechanic"
|
|
196
|
+
print("Service worker")
|
|
197
|
+
default
|
|
198
|
+
print("Civilian")
|
|
199
|
+
end
|
|
153
200
|
```
|
|
154
201
|
|
|
155
|
-
|
|
202
|
+
#### Guard Clauses
|
|
203
|
+
Clean up nested if-statements with early returns.
|
|
204
|
+
|
|
156
205
|
```typescript
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
print("
|
|
206
|
+
func RevivePlayer(player)
|
|
207
|
+
// Returns immediately if player is nil
|
|
208
|
+
guard player return
|
|
209
|
+
|
|
210
|
+
// Returns with custom logic if condition fails
|
|
211
|
+
guard player.isDead else
|
|
212
|
+
print("Player is already alive")
|
|
213
|
+
return
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
// Main logic
|
|
217
|
+
player.revive()
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
// Guard with return value
|
|
221
|
+
func GetPlayer(id)
|
|
222
|
+
let player = GetPlayerById(id)
|
|
223
|
+
guard player return nil
|
|
224
|
+
return player
|
|
164
225
|
end
|
|
165
226
|
```
|
|
166
227
|
|
|
167
|
-
|
|
228
|
+
#### For Loops
|
|
168
229
|
```typescript
|
|
169
|
-
//
|
|
170
|
-
for i
|
|
230
|
+
// Numeric for (start, end)
|
|
231
|
+
for i = 1, 10 do
|
|
171
232
|
print(i)
|
|
172
233
|
end
|
|
173
234
|
|
|
174
|
-
//
|
|
175
|
-
for i
|
|
235
|
+
// Numeric for with step (start, end, step)
|
|
236
|
+
for i = 0, 100, 5 do
|
|
176
237
|
print(i)
|
|
177
238
|
end
|
|
178
239
|
|
|
179
|
-
//
|
|
180
|
-
for i
|
|
240
|
+
// Range for with step
|
|
241
|
+
for i in 1..10 by 2 do
|
|
181
242
|
print(i)
|
|
182
243
|
end
|
|
244
|
+
|
|
245
|
+
// For-in (pairs)
|
|
246
|
+
for key, value in pairs(myTable) do
|
|
247
|
+
print("${key}: ${value}")
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
// For-in (ipairs)
|
|
251
|
+
for index, item in ipairs(myArray) do
|
|
252
|
+
print("${index}: ${item}")
|
|
253
|
+
end
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
#### While Loop
|
|
257
|
+
```typescript
|
|
258
|
+
let count = 0
|
|
259
|
+
while count < 10 do
|
|
260
|
+
print(count)
|
|
261
|
+
count += 1
|
|
262
|
+
end
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### 5. Modern Operators
|
|
266
|
+
|
|
267
|
+
#### Compound Assignment
|
|
268
|
+
```typescript
|
|
269
|
+
let x = 10
|
|
270
|
+
x += 5
|
|
271
|
+
x -= 3
|
|
272
|
+
x *= 2
|
|
273
|
+
x /= 4
|
|
274
|
+
x %= 3
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
#### Null Coalescing (`??`)
|
|
278
|
+
```typescript
|
|
279
|
+
let name = playerName ?? "Unknown"
|
|
280
|
+
let health = GetHealth() ?? 100
|
|
183
281
|
```
|
|
184
282
|
|
|
185
|
-
|
|
283
|
+
#### Optional Chaining (`?.`)
|
|
284
|
+
```typescript
|
|
285
|
+
let state = LocalPlayer.state?.isDead
|
|
286
|
+
let nested = obj?.deep?.value
|
|
287
|
+
let arrItem = arr?[0]
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
#### Ternary Operator
|
|
291
|
+
```typescript
|
|
292
|
+
let status = isDead ? "Dead" : "Alive"
|
|
293
|
+
let label = count > 0 ? "${count} items" : "Empty"
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### 6. Destructuring & Spread
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// Object Destructuring
|
|
300
|
+
let { x, y, z } = GetEntityCoords(ped)
|
|
301
|
+
let { name, health } = playerData
|
|
302
|
+
|
|
303
|
+
// Array Destructuring
|
|
304
|
+
let [first, second] = GetValues()
|
|
305
|
+
|
|
306
|
+
// Object Spread (tables only)
|
|
307
|
+
let base = { a: 1, b: 2 }
|
|
308
|
+
let extended = { ...base, c: 3 }
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### 7. String Interpolation
|
|
312
|
+
|
|
313
|
+
Use `${expression}` inside strings to embed values:
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
let name = "John"
|
|
317
|
+
let age = 25
|
|
318
|
+
|
|
319
|
+
print("Hello, ${name}!")
|
|
320
|
+
print("You are ${age} years old")
|
|
321
|
+
print("Next year you'll be ${age + 1}")
|
|
322
|
+
|
|
323
|
+
// Complex expressions
|
|
324
|
+
let player = { health: 100 }
|
|
325
|
+
print("Health: ${player.health}")
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### 8. Vector Literals
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// Vector3 (FiveM native)
|
|
332
|
+
let pos: vector3 = <100.0, 200.0, 30.0>
|
|
333
|
+
|
|
334
|
+
// Vector2
|
|
335
|
+
let screenPos: vector2 = <0.5, 0.5>
|
|
336
|
+
|
|
337
|
+
// Vector4 (includes heading)
|
|
338
|
+
let spawn: vector4 = <100.0, 200.0, 30.0, 90.0>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## 🎮 FiveM Features
|
|
344
|
+
|
|
345
|
+
### Thread & Loop
|
|
186
346
|
|
|
187
|
-
#### Threads & Wait
|
|
188
347
|
```typescript
|
|
348
|
+
// Create a thread (Citizen.CreateThread)
|
|
189
349
|
thread
|
|
190
|
-
|
|
191
|
-
|
|
350
|
+
print("Thread started")
|
|
351
|
+
|
|
352
|
+
loop (true)
|
|
353
|
+
wait 0 // Run every frame
|
|
354
|
+
|
|
355
|
+
// Game logic here
|
|
356
|
+
let ped = PlayerPedId()
|
|
357
|
+
let health = GetEntityHealth(ped)
|
|
358
|
+
|
|
359
|
+
if health < 50 then
|
|
360
|
+
print("Low health warning!")
|
|
361
|
+
end
|
|
362
|
+
end
|
|
192
363
|
end
|
|
193
364
|
```
|
|
194
365
|
|
|
195
|
-
|
|
366
|
+
### Wait
|
|
367
|
+
|
|
196
368
|
```typescript
|
|
197
|
-
|
|
198
|
-
|
|
369
|
+
// Wait in milliseconds
|
|
370
|
+
wait 1000 // Wait 1 second
|
|
371
|
+
wait 0 // Yield one frame
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Network Events
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
// Register + Handle network event (Client <-> Server)
|
|
378
|
+
netevent "bank:deposit" (amount)
|
|
379
|
+
print("Depositing ${amount}")
|
|
380
|
+
UpdateBankBalance(amount)
|
|
199
381
|
end
|
|
200
382
|
|
|
201
|
-
event
|
|
202
|
-
|
|
383
|
+
// Local event handler
|
|
384
|
+
event "onClientResourceStart" (resName)
|
|
385
|
+
guard resName == GetCurrentResourceName() return
|
|
386
|
+
print("Resource started!")
|
|
203
387
|
end
|
|
204
388
|
```
|
|
205
389
|
|
|
206
|
-
|
|
390
|
+
### Emit Events
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
// Emit to server
|
|
394
|
+
emit "server:event:name" (arg1, arg2)
|
|
395
|
+
|
|
396
|
+
// Explicit emit variants
|
|
397
|
+
emitServer "myevent" (data)
|
|
398
|
+
emitClient "myevent" (targetPlayer, data)
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Commands
|
|
402
|
+
|
|
207
403
|
```typescript
|
|
404
|
+
// Register a command (RegisterCommand wrapper)
|
|
208
405
|
addcmd "teleport" (source, args)
|
|
209
|
-
|
|
406
|
+
let x = tonumber(args[1]) ?? 0
|
|
407
|
+
let y = tonumber(args[2]) ?? 0
|
|
408
|
+
let z = tonumber(args[3]) ?? 0
|
|
409
|
+
|
|
410
|
+
SetEntityCoords(PlayerPedId(), x, y, z)
|
|
411
|
+
print("Teleported to ${x}, ${y}, ${z}")
|
|
210
412
|
end
|
|
211
413
|
```
|
|
212
414
|
|
|
213
|
-
|
|
415
|
+
### Exports
|
|
416
|
+
|
|
214
417
|
```typescript
|
|
215
|
-
|
|
216
|
-
|
|
418
|
+
// Export a function
|
|
419
|
+
export "GetPlayerMoney" ()
|
|
420
|
+
return playerMoney
|
|
217
421
|
end
|
|
218
422
|
```
|
|
219
423
|
|
|
220
|
-
|
|
424
|
+
### Timeout & Interval
|
|
425
|
+
|
|
221
426
|
```typescript
|
|
222
|
-
|
|
223
|
-
|
|
427
|
+
// Run once after delay
|
|
428
|
+
timeout 5000
|
|
429
|
+
print("5 seconds passed!")
|
|
430
|
+
end
|
|
224
431
|
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
print("
|
|
228
|
-
return
|
|
432
|
+
// Run repeatedly
|
|
433
|
+
interval 1000
|
|
434
|
+
print("Every second")
|
|
229
435
|
end
|
|
230
436
|
```
|
|
231
437
|
|
|
232
|
-
|
|
438
|
+
### Try / Catch
|
|
439
|
+
|
|
233
440
|
```typescript
|
|
234
441
|
try
|
|
235
|
-
|
|
442
|
+
RiskyOperation()
|
|
236
443
|
catch err
|
|
237
|
-
print("Error: $err")
|
|
444
|
+
print("Error: ${err}")
|
|
445
|
+
end
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## ⚡ Complete Example: Store Robbery System
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
// 1. Type Definition
|
|
454
|
+
interface StoreConfig {
|
|
455
|
+
id: number,
|
|
456
|
+
position: vector3,
|
|
457
|
+
reward: number,
|
|
458
|
+
isOpen: boolean
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// 2. Configuration
|
|
462
|
+
const Stores: StoreConfig[] = [
|
|
463
|
+
{ id: 1, position: <120.5, -500.2, 30.0>, reward: 5000, isOpen: true },
|
|
464
|
+
{ id: 2, position: <250.0, 300.0, 25.0>, reward: 10000, isOpen: true }
|
|
465
|
+
]
|
|
466
|
+
|
|
467
|
+
let isRobbing = false
|
|
468
|
+
|
|
469
|
+
// 3. Main Game Loop
|
|
470
|
+
thread
|
|
471
|
+
loop (true)
|
|
472
|
+
wait 0
|
|
473
|
+
|
|
474
|
+
if isRobbing then
|
|
475
|
+
break
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
let ped = PlayerPedId()
|
|
479
|
+
let pos = GetEntityCoords(ped)
|
|
480
|
+
|
|
481
|
+
for _, store in ipairs(Stores) do
|
|
482
|
+
if not store.isOpen then
|
|
483
|
+
break
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
let distance = #(pos - store.position)
|
|
487
|
+
if distance < 2.0 then
|
|
488
|
+
ShowHelpText("Press ~INPUT_CONTEXT~ to rob")
|
|
489
|
+
|
|
490
|
+
if IsControlJustPressed(0, 38) then
|
|
491
|
+
StartRobbery(store)
|
|
492
|
+
end
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
// 4. Robbery Function
|
|
499
|
+
func StartRobbery(store: StoreConfig)
|
|
500
|
+
isRobbing = true
|
|
501
|
+
|
|
502
|
+
// Notify server
|
|
503
|
+
emit "robbery:start" (store.id)
|
|
504
|
+
|
|
505
|
+
// Play animation
|
|
506
|
+
TaskPlayAnim(PlayerPedId(), "anim_dict", "anim_name", 8.0, -8.0, -1, 0, 0, false, false, false)
|
|
507
|
+
|
|
508
|
+
wait 5000
|
|
509
|
+
|
|
510
|
+
ClearPedTasks(PlayerPedId())
|
|
511
|
+
isRobbing = false
|
|
512
|
+
|
|
513
|
+
print("Robbery complete! Reward: ${store.reward}")
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
// 5. Server Sync Handler
|
|
517
|
+
netevent "robbery:sync" (storeId, newState)
|
|
518
|
+
let store = Stores.find(s => s.id == storeId)
|
|
519
|
+
guard store return
|
|
520
|
+
|
|
521
|
+
store.isOpen = newState
|
|
522
|
+
let stateStr = newState ? "open" : "closed"
|
|
523
|
+
print("Store ${storeId} is now ${stateStr}")
|
|
238
524
|
end
|
|
239
525
|
```
|
|
240
526
|
|
|
241
|
-
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
## 🛠️ CLI Reference
|
|
530
|
+
|
|
531
|
+
| Command | Usage | Description |
|
|
532
|
+
|:--------|:------|:------------|
|
|
533
|
+
| **Build** | `ltc build ./` | Compiles all `.lt` files in the folder to `.lua` |
|
|
534
|
+
| **Watch** | `ltc watch ./` | Watches for file changes and recompiles instantly |
|
|
535
|
+
| **Version** | `ltc -v` | Displays the current compiler version |
|
|
536
|
+
|
|
537
|
+
### Project Structure
|
|
538
|
+
|
|
539
|
+
LT automatically detects `src/` folders:
|
|
242
540
|
|
|
243
541
|
```
|
|
244
542
|
my-resource/
|
|
245
543
|
├── src/
|
|
246
544
|
│ ├── client.lt
|
|
247
545
|
│ └── server.lt
|
|
248
|
-
├── client.lua
|
|
249
|
-
|
|
250
|
-
└── fxmanifest.lua
|
|
546
|
+
├── client.lua ← Generated
|
|
547
|
+
└── server.lua ← Generated
|
|
251
548
|
```
|
|
252
549
|
|
|
253
|
-
|
|
550
|
+
---
|
|
254
551
|
|
|
255
552
|
## 🔧 VS Code Extension
|
|
256
553
|
|
|
257
|
-
Get
|
|
258
|
-
|
|
259
|
-
**[LT Language Extension](https://marketplace.visualstudio.com/items?itemName=laot.lt-language)**
|
|
260
|
-
|
|
261
|
-
- Syntax Highlighting
|
|
262
|
-
- IntelliSense for Variables & Functions
|
|
263
|
-
- **Native FiveM Autocompletion** (GetHashKey, CreateVehicle, etc.)
|
|
264
|
-
- Snippets for common patterns
|
|
265
|
-
|
|
266
|
-
## 📜 License
|
|
554
|
+
Get the official **[LT Language Extension](https://marketplace.visualstudio.com/items?itemName=laot.lt-language)** for the best experience.
|
|
267
555
|
|
|
268
|
-
|
|
556
|
+
**Features:**
|
|
557
|
+
* 🎨 Full Syntax Highlighting
|
|
558
|
+
* 🔍 Intelligent Autocompletion
|
|
559
|
+
* 📦 **FiveM Native Intellisense**
|
|
560
|
+
* ✨ Real-time Error Checking
|
|
269
561
|
|
|
270
562
|
---
|
|
271
563
|
|
|
272
564
|
<p align="center">
|
|
273
|
-
|
|
565
|
+
Made with ❤️ for the FiveM Community by <b>LaotScripts</b>
|
|
274
566
|
</p>
|