-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.lua
More file actions
412 lines (353 loc) · 14.7 KB
/
server.lua
File metadata and controls
412 lines (353 loc) · 14.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
------------------------------
-- Script wide used variables
------------------------------
-- When the player enters RC mode, we make them invisible and seat them in the car.
-- In their position, we spawn a ped with their skin that will keep facing the car
-- as if they were looking at it while remotely driving it.
-- This global variable is a list that stores the ped for each player.
local g_rcDummy = {}
-- The player can switch the camera between the car they're remote controlling
-- or the dummy ped representing them.
-- This global variable is a list that stores the selection for each player.
local g_isRcCameraOnPlayer = {}
------------------------------
-- Exported functions
------------------------------
-- void enterRcMode(player, vehicle)
-- Puts the player in RC Mode in the vehicle.
function enterRcMode(player, rcVehicle)
-- check all prerequisites for entering rc mode
-- is arg1 an mta element?
if not isElement(player) then
outputDebugString(string.format("RC Mode: enterRcMode expects parameter 1 to be a player, %s given.", type(player)), 2)
return
end
-- is the type of the mta element given as arg1 a player?
if getElementType(player) ~= "player" then
outputDebugString(string.format("RC Mode: enterRcMode expects parameter 1 to be a player, %s given.", getElementType(player)), 2)
return
end
-- is arg2 an mta element?
if not isElement(rcVehicle) then
outputDebugString(string.format("RC Mode: enterRcMode expects parameter 1 to be a vehicle, %s given.", type(rcVehicle)), 2)
return
end
-- is the type of the mta element given as arg2 a vehicle?
if getElementType(rcVehicle) ~= "vehicle" then
outputDebugString(string.format("RC Mode: enterRcMode expects parameter 1 to be a vehicle, %s given.", getElementType(rcVehicle)), 2)
return
end
-- is the player given as arg1 alive?
if isPedDead(player) then
outputDebugString("RC Mode: enterRcMode: the player is dead and cannot control an RC vehicle.", 2)
return
end
-- is the vehicle given as arg2 intact?
if isVehicleBlown(rcVehicle) then
outputDebugString("RC Mode: enterRcMode: The vehicle is blown and cannot be remote controled.", 2)
return
end
-- is the player given as arg1 already in rc mode?
if isPlayerInRcMode(player) then
outputDebugString(string.format("RC Mode: enterRcMode: The player %s already is in RC mode.", getPlayerName(player)), 2)
return
end
-- is the player given as arg1 already in the driver seat of another car or are they in the passenger seat of the vehicle given as arg2?
if getPedOccupiedVehicleSeat(player) == 0 or rcVehicle == getPedOccupiedVehicle(player) then
outputDebugString(string.format("RC Mode: enterRcMode: Player %s cannot remote control the vehicle they are currently driving.", getPlayerName(player)), 2)
return
end
-- is the player given as arg1 in the same interior as the vehicle given in arg2?
if getElementInterior(player) ~= getElementInterior(rcVehicle) then
outputDebugString(string.format("RC Mode: enterRcMode: Player %s and vehicle are not in the same interior.", getPlayerName(player)), 2)
return
end
-- is the player given as arg1 in the same dimension as the vehicle given in arg2?
if getElementDimension(player) ~= getElementDimension(rcVehicle) then
outputDebugString(string.format("RC Mode: enterRcMode: Player %s and vehicle are not in the same dimension.", getPlayerName(player)), 2)
return
end
-- remember all the information on the player
local posX, posY, posZ = getElementPosition(player)
local rotX, rotY, rotZ = getElementRotation(player)
local playerCar = getPedOccupiedVehicle(player)
local seat = getPedOccupiedVehicleSeat(player)
local dimension = getElementDimension(player)
local playerModel = getElementModel(player)
local health = getElementHealth(player)
local armor = getPedArmor(player)
-- remember their map blip's color and remove it
local r, g, b, a
local elements = getAttachedElements(player)
if elements then
for k,v in ipairs(elements) do
if (getElementType(v) == "blip") then
r, g, b, a = getBlipColor(v)
destroyElement(v)
end
end
end
-- hide the player's name tag so it isn't obvious they're sitting in the car
setPlayerNametagShowing(player, false)
-- if someone else is remote controlling the car, end their remote control session or
-- if someone else is in the driver seat, put them in the passenger seat
local driver = getVehicleOccupant(rcVehicle, 0)
local passenger = getVehicleOccupant(rcVehicle, 1)
if driver and not passenger then
if isPlayerInRcMode(driver) then
exitRcMode(driver)
else
warpPedIntoVehicle(driver, rcVehicle, 1)
end
end
-- hide the player and put them in the driver seat
setElementAlpha(player, 0)
giveWeapon(player, 0, 0, true)
-- create a dummy ped and apply the player's information
local rcDummy = createPed(playerModel, posX, posY, posZ)
g_rcDummy[player] = rcDummy
setElementRotation(rcDummy, rotX, rotY, rotZ)
setElementDimension(rcDummy, dimension)
setElementHealth(rcDummy, health)
setPedArmor(rcDummy, armor)
giveWeapon(rcDummy, 40, 0, true)
if r and g and b and a then
createBlipAttachedTo(rcDummy, 0, 2, r, g, b, a)
end
-- if the player that enters rc mode is sitting in the passenger seat of another car,
-- put their dummy in that seat
if isElement(playerCar) then
removePedFromVehicle(player)
warpPedIntoVehicle(rcDummy, playerCar, seat)
end
-- put the invisible player into the vehicle
warpPedIntoVehicle(player, rcVehicle, 0)
-- start a timer that'll update the palyer's health when their dummy gets hurt
observeRcDummy(rcDummy, player)
g_isRcCameraOnPlayer[player] = true
-- store a reference to the rcDummy on the player so that the client can use it to render a nametag on it
setElementData(player, "rcDummy", rcDummy)
end
-- bool isPlayerInRcMode(player)
-- Returns if the player is in RC Mode.
function isPlayerInRcMode(player)
-- is arg1 an mta element?
if not isElement(player) then
outputDebugString(string.format("RC Mode: isPlayerInRcMode expects parameter 1 to be a player, %s given.", type(player)), 2)
return
end
-- is the type of the mta element given as arg1 a player?
if getElementType(player) ~= "player" then
outputDebugString(string.format("RC Mode: isPlayerInRcMode expects parameter 1 to be a player, %s given.", getElementType(player)), 2)
return
end
-- does a dummy ped exist for this player?
return isElement(g_rcDummy[player])
end
-- void exitRcMode(player)
-- Ends RC mode for the player:
-- * make the player visible again
-- * remove them from the car and put them in the position of their dummy
-- * destroy their dummy
-- * remove the map blip from the dummy ped
-- * add a blip for the player back
function exitRcMode(player)
-- is arg1 an mta element?
if not isElement(player) then
outputDebugString(string.format("RC Mode: exitRcMode expects parameter 1 to be a player, %s given.", type(player)), 2)
return
end
-- is the type of the mta element given as arg1 a player?
if getElementType(player) ~= "player" then
outputDebugString(string.format("RC Mode: exitRcMode expects parameter 1 to be a player, %s given.", getElementType(player)), 2)
return
end
-- is the player in rc mode? if not, we don't need to end rc mode for them
if not isPlayerInRcMode(player) then
outputDebugString(string.format("RC Mode: exitRcMode: Player %s is not in RC Mode.", getPlayerName(player)), 2)
return
end
local rcDummy = getPlayerRcDummy(player)
-- remember all information on the dummy ped
local posX, posY, posZ = getElementPosition(rcDummy)
local rotX, rotY, rotZ = getElementRotation(rcDummy)
local playerCar = getPedOccupiedVehicle(rcDummy)
local seat = getPedOccupiedVehicleSeat(rcDummy)
local dimension = getElementDimension(rcDummy)
local health = getElementHealth(rcDummy)
local armor = getPedArmor(rcDummy)
-- remember their map blip's color and remove it
local r, g, b, a
local elements = getAttachedElements(rcDummy)
if elements then
for k,v in ipairs(elements) do
if (getElementType(v) == "blip") then
r, g, b, a = getBlipColor(v)
destroyElement(v)
end
end
end
-- remove the dummy ped
destroyElement(rcDummy)
-- apply the information to the player
removePedFromVehicle(player)
if isElement(playerCar) then
-- manually set the camera target to fix an MTA bug:
-- It appears that the camera is not set back on the player when they're put in a passenger seat
setCameraTarget(player, player)
warpPedIntoVehicle(player, playerCar, seat)
end
setElementRotation(player, rotX, rotY, rotZ)
setElementPosition(player, posX, posY, posZ)
setElementDimension(player, dimension)
setElementHealth(player, health)
setPedArmor(player, armor)
setElementAlpha(player, 255)
setPlayerNametagShowing(player, true)
if r and g and b and a then
createBlipAttachedTo(player, 0, 2, r, g, b, a)
end
-- remove data stored on the dummy ped from global arrays
g_rcDummy[player] = nil
g_isRcCameraOnPlayer[player] = nil
setElementData(player, "rcDummy", nil)
end
-- bool isCameraOnRcDummy(player)
-- Returns true if the camera is on the dummy of the player, returns false if it is on the player itself.
function isCameraOnRcDummy(player)
-- is arg1 an mta element?
if not isElement(player) then
outputDebugString(string.format("RC Mode: isCameraOnRcDummy expects parameter 1 to be a player, %s given.", type(player)), 2)
return
end
-- is the type of the mta element given as arg1 a player?
if getElementType(player) ~= "player" then
outputDebugString(string.format("RC Mode: isCameraOnRcDummy expects parameter 1 to be a player, %s given.", getElementType(player)), 2)
return
end
return g_isRcCameraOnPlayer[player]
end
-- void setCameraOnRcDummy(player, bool)
-- Sets the camera on the dummy if onDummy is true, otherwise sets it on the player.
function setCameraOnRcDummy(player, onDummy)
-- is arg1 an mta element?
if not isElement(player) then
outputDebugString(string.format("RC Mode: setCameraOnRcDummy expects parameter 1 to be a player, %s given.", type(player)), 2)
return
end
-- is the type of the mta element given as arg1 a player?
if getElementType(player) ~= "player" then
outputDebugString(string.format("RC Mode: setCameraOnRcDummy expects parameter 1 to be a player, %s given.", getElementType(player)), 2)
return
end
-- is the player in rc mode? if not, we don't have to switch the camera
if not isPlayerInRcMode(player) then
outputDebugString(string.format("RC Mode: setCameraOnRcDummy: Player %s is not in RC Mode.", getPlayerName(player)), 2)
return
end
-- is arg2 a boolean?
if type(onDummy) ~= "boolean" then
outputDebugString(string.format("RC Mode: setCameraOnRcDummy expects parameter 2 to be a boolean, %s given.", type(onDummy)), 2)
return
end
-- update the camera target and remember the current target
if onDummy then
local rcDummy = getPlayerRcDummy(player)
setCameraTarget(player, rcDummy)
g_isRcCameraOnPlayer[player] = true
outputDebugString("g_isRcCameraOnPlayer["..getPlayerName(player).."] = true")
else
setCameraTarget(player, player)
g_isRcCameraOnPlayer[player] = false
outputDebugString("g_isRcCameraOnPlayer["..getPlayerName(player).."] = false")
end
end
-- ped getPlayerRcDummy(player)
-- Returns the ped that is used as RC dummy for the player.
function getPlayerRcDummy(player)
-- is arg1 an mta element?
if not isElement(player) then
outputDebugString(string.format("RC Mode: getPlayerRcDummy expects parameter 1 to be a player, %s given.", type(player)), 2)
return
end
-- is the type of the mta element given as arg1 a player?
if getElementType(player) ~= "player" then
outputDebugString(string.format("RC Mode: getPlayerRcDummy expects parameter 1 to be a player, %s given.", getElementType(player)), 2)
return
end
-- is the player in rc mode? If not then we don't have a dummy to return
if not isPlayerInRcMode(player) then
outputDebugString(string.format("RC Mode: Player %s is not in RC Mode.", getPlayerName(player)), 2)
return
end
return g_rcDummy[player]
end
------------------------------
-- Internal functions
------------------------------
-- Update the health of a player if their dummy gets hurt.
function observeRcDummy(rcDummy, assignedPlayer)
-- exit the "loop" if either the player or dummy are gone
if not isElement(rcDummy) or not isElement(assignedPlayer) then
return
end
-- outputDebugString("dummyHealth = "..getElementHealth(rcDummy))
-- outputDebugString("playerHealth = "..getElementHealth(assignedPlayer))
setElementHealth(assignedPlayer, getElementHealth(rcDummy))
setPedArmor(assignedPlayer, getPedArmor(rcDummy))
setTimer(observeRcDummy, 1000, 1, rcDummy, assignedPlayer)
end
-- If the player is being made to leave the car (i.e. from a different resource) while remote controlling a car
-- abort this, as they're not really driving the car
function abortExitingVehicle(player)
if isPlayerInRcMode(player) and not wasEventCancelled() then
exitRcMode(player)
cancelEvent(true, "rcmode.preventPlayerExitingVehicleOnEnd")
end
end
addEventHandler("onVehicleStartExit", getRootElement(), abortExitingVehicle)
-- If the setting to allow stealing a car from someone that's currently remote controlling it is enabled
-- and another player attempts to get into a car that's being remote controlled stop the remote control session.
function checkIfToAbortRcMode(enteringPlayer, seat, jacked)
-- is arg1 an mta element?
if not isElement(jacked) then
return
end
-- is the player in rc mode or is the setting configured that players in rc mode can't have their car stolen?
if not isPlayerInRcMode(jacked) or get("*RcMode.preventRcPlayerFromGettingJacked") then
return
end
exitRcMode(jacked)
end
addEventHandler("onVehicleStartEnter", getRootElement(), checkIfToAbortRcMode)
-- If the invisible player driving the car has been killed, respawn them where their dummy ped is.
function preventRcPlayerFromDieing()
-- is the player in rc mode?
if not isPlayerInRcMode(source) then
return
end
local posX, posY, posZ = getElementPosition(getPlayerRcDummy(source))
spawnPlayer(source, posX, posY, posZ)
-- setElementHealth(source, getElementHealth(getPlayerRcDummy(source)))
exitRcMode(source)
end
addEventHandler("onPlayerWasted", getRootElement(), preventRcPlayerFromDieing)
-- When the player quits the game, only destroy their dummy (don't try to put them in the position of the dummy).
function onlyDestroyRcDummy()
-- is the player in rc mode?
if not isPlayerInRcMode(source) then
return
end
-- destroy the map blip on the dummy ped
local elements = getAttachedElements(getPlayerRcDummy(source))
if elements then
for k,v in ipairs(elements) do
if (getElementType(v) == "blip") then
destroyElement(v)
end
end
end
-- destroy the dummy ped itself
destroyElement(getPlayerRcDummy(source))
end
addEventHandler("onPlayerQuit", getRootElement(), onlyDestroyRcDummy)