· 4 years ago · Feb 12, 2021, 10:06 AM
1local marathonPlayers = {}
2local topTimes = {} -- stores winners first times to get top 5 later
3local previousLocation = {}
4local previousSkin = {}
5local eventVehicles = {}
6local marathonCreated
7local marathonStarted
8local payPerParticipant = 25000 -- prize will depend on amount of players participating
9local marathonPrize
10local eventDim = 299
11local marathonSkins = {138, 139, 140, 145, 97, 45, 18, 51, 52}
12local startX, startY, startZ = 1295.03992, -2690.84277, 2.58662
13local startTick
14local TIME_UNTIL_START = 1000 * 60 * 5
15local startTimer
16local isMarathonWon
17local MAX_PLAYERS
18
19-- Setting up the marathon
20
21function marathonCommands(plr, cmd, arg)
22 if (not arg) then
23 exports.CIThelp:dm("Syntax: /marathon <warp> <leave> <time> <count>", plr, 255, 25, 25)
24 return false
25 end
26 if (arg == "warp") then
27 warpPlayerToMarathon(plr)
28 elseif (arg == "leave") then
29 warpPlayerOutOfMarathon(plr)
30 elseif (arg == "panel") then
31 local adminLvl = exports.CITadmin:getPlayerAdminLevel(plr)
32 if (not adminLvl or adminLvl < 2) then
33 return false
34 end
35 triggerClientEvent(plr, "CITmarathon:openGUI", plr, marathonPlayers)
36 elseif (arg == "time") then
37 if (not marathonCreated or marathonStarted) then
38 exports.CIThelp:dm("There is no marathon going on or it has already started", plr, 255, 25, 25)
39 return false
40 end
41 local remainingInSeconds = math.floor(getTimerDetails(startTimer)/1000)
42 exports.CIThelp:dm("Marathon starts in "..remainingInSeconds.." seconds ("..math.floor(remainingInSeconds / 60).." minutes)", plr, 0, 255, 0)
43 elseif (arg == "count") then
44 if (not marathonCreated) then
45 exports.CIThelp:dm("There is no marathon going on", plr, 255, 25, 25)
46 return false
47 end
48 exports.CIThelp:dm("There are currently "..#marathonPlayers.." player(s) participating in the marathon", plr, 0, 255, 0)
49 end
50end
51addCommandHandler("marathon", marathonCommands)
52
53function createMarathon(maxPlayers)
54 if (not client) then
55 return false
56 end
57 local adminLvl = exports.CITadmin:getPlayerAdminLevel(client)
58 if (not adminLvl or adminLvl < 2) then
59 return false
60 end
61 if (marathonStarted or marathonCreated) then
62 exports.CIThelp:dm("There is already a marathon going on", client, 255, 25, 25)
63 return false
64 end
65 for i, v in ipairs(getElementsByType("player")) do
66 exports.CIThelp:dm(getPlayerName(client).." started a marathon, use '/marathon warp' to join!", v, 128, 0, 128)
67 end
68 setElementDimension(client, eventDim)
69 setElementPosition(client, startX, startY, startZ)
70 local x, y, z = getElementPosition(client)
71 previousLocation[client] = {x, y, z}
72 exports.CIThelp:dm("You created a marathon, you have been warped to the start location", client, 0, 255, 0)
73 addEventHandler("onPlayerLogin", root, informOnLogin) -- will be removed once event starts
74 marathonCreated = true
75 startTimer = setTimer(startMarathon, TIME_UNTIL_START, 1)
76end
77addEvent("CITmarathon:createMarathon", true)
78addEventHandler("CITmarathon:createMarathon", root, createMarathon)
79
80function startMarathon()
81 marathonStarted = true
82 removeEventHandler("onPlayerLogin", root, informOnLogin)
83 marathonPrize = #marathonPlayers * payPerParticipant
84 for i, v in ipairs(marathonPlayers) do
85 setElementFrozen(v, false)
86 triggerClientEvent(v, "CITmarathon:clientStartMarathon", v)
87 end
88 for i, v in ipairs(getElementsByType("player")) do
89 exports.CIThelp:dm("Marathon started, there are "..#marathonPlayers.." players competing for the prize of $"..marathonPrize, v, 128, 0, 128)
90 end
91 startTick = getTickCount()
92 addEventHandler("onPlayerWeaponSwitch", root, onWpnSwitch) -- will be removed once event ends
93end
94
95function informOnLogin()
96 exports.CIThelp:dm("There is a marathon going on, use '/marathon warp' to join!", source, 128, 0, 128)
97end
98
99function warpPlayerToMarathon(plr)
100 if (not plr) then
101 return false
102 end
103 if (isPlayerInMarathon(plr)) then
104 exports.CIThelp:dm("You are already in the marathon", plr, 255, 25, 25)
105 return false
106 end
107 if (marathonStarted or not marathonCreated) then
108 exports.CIThelp:dm("There is no marathon or it has already started", plr, 255, 25, 25)
109 return false
110 end
111 if (not exports.CITchecking:playerActionCheck(plr, {{"w", 0}, {"i", 0}, {"d", 0}, {"ld", 5}, {"s", "noveh", "noarrest", "nojailed", "nodead", "nopris", "nobc", "noguest", "nojetpack", "noglued", "nohit"}})) then
112 return false
113 end
114 if (MAX_PLAYERS and #marathonPlayers >= MAX_PLAYERS) then
115 exports.CIThelp:dm("Marathon already reached max players limit", plr, 255, 25, 25)
116 return false
117 end
118 local x, y, z = getElementPosition(plr)
119 previousLocation[plr] = {x, y, z}
120 previousSkin[plr] = getElementModel(plr)
121 setElementDimension(plr, eventDim)
122 setElementPosition(plr, startX, startY, startZ)
123 setElementModel(plr, marathonSkins[math.random(#marathonSkins)])
124 setElementFrozen(plr, true)
125 setPedWeaponSlot(plr, 0)
126 exports.CIThelp:dm("You have been warped to the marathon, use '/marathon leave' to leave", plr, 0, 255, 0)
127 marathonPlayers[#marathonPlayers + 1] = plr
128 triggerClientEvent(plr, "CITmarathon:showHighScores", plr, topTimes)
129
130 addEventHandler("onPlayerWasted", plr, onPlrWasted)
131end
132
133function warpPlayerOutOfMarathon(plr)
134 if (not plr) then
135 return false
136 end
137 if (not isPlayerInMarathon(plr)) then
138 return false
139 end
140 setElementDimension(plr, 0)
141 if (previousLocation[plr]) then
142 local x, y, z = unpack(previousLocation[plr])
143 setElementPosition(plr, x, y, z)
144 exports.CIThelp:dm("You have been returned to your previous position", plr, 0, 255, 0)
145 else
146 killPed(plr)
147 exports.CIThelp:dm("Couldn't find your previous position so you were killed instead", plr, 0, 255, 0)
148 end
149 if (previousSkin[plr]) then
150 setElementModel(plr, previousSkin[plr])
151 end
152 if (isElementFrozen(plr)) then
153 setElementFrozen(plr, false)
154 end
155 if (eventVehicles[plr]) then
156 destroyElement(eventVehicles[plr])
157 end
158 eventVehicles[plr] = nil
159 previousSkin[plr] = nil
160 previousLocation[plr] = nil
161 table.removeValue(marathonPlayers, plr)
162 triggerClientEvent(plr, "CITmarathon:clientOnPlrWasted", plr)
163 removeEventHandler("onPlayerWasted", plr, onPlrWasted)
164end
165
166function kickPlayerFromMarathon(plrName)
167 if (not client or not plrName) then
168 return false
169 end
170 local adminLvl = exports.CITadmin:getPlayerAdminLevel(client)
171 if (not adminLvl or adminLvl < 2) then
172 return false
173 end
174 local plr = getPlayerFromName(plrName)
175 if (not plr) then
176 exports.CIThelp:dm("Couldn't find player", client, 255, 25, 25)
177 return false
178 end
179 if (not isPlayerInMarathon(plr)) then
180 exports.CIThelp:dm("Player isn't in marathon", client, 255, 25, 25)
181 return false
182 end
183 warpPlayerOutOfMarathon(plr)
184 exports.CIThelp:dm("You kicked "..plrName.." from the marathon", client, 255, 25, 25)
185 exports.CIThelp:dm(getPlayerName(client).." kicked you from the marathon", plr, 255, 25, 25)
186
187 exports.CITlogs:logSomething("CITmarathon - "..getPlayerName(client).." kicked "..plrName, "events", client, plr)
188end
189addEvent("CITmarathon:kickPlayer", true)
190addEventHandler("CITmarathon:kickPlayer", root, kickPlayerFromMarathon)
191
192-- Main marathon functions
193
194function serverGiveVehicle(ID)
195 if (not client) then
196 return false
197 end
198 if (ID == 46) then
199 giveWeapon(client, ID, 1, true)
200 return true
201 end
202 local veh = getPedOccupiedVehicle(client)
203 if (veh) then
204 setElementModel(veh, ID)
205 else
206 if (eventVehicles[client]) then
207 destroyElement(eventVehicles[client])
208 eventVehicles[client] = nil
209 end
210 local x, y, z = getElementPosition(client)
211 local rx, ry, rz = getElementRotation(client)
212 eventVehicles[client] = createVehicle(ID, x, y, z, rx, ry, rz)
213 warpPedIntoVehicle(client, eventVehicles[client])
214 end
215end
216addEvent("CITmarathon:givePlayerVehicle", true)
217addEventHandler("CITmarathon:givePlayerVehicle", root, serverGiveVehicle)
218
219function serverDestroyVehicle(veh)
220 if (not client) then
221 return false
222 end
223 if (not eventVehicles[client]) then
224 return false
225 end
226 destroyElement(veh)
227 eventVehicles[client] = nil
228end
229addEvent("CITmarathon:destroyVehicle", true)
230addEventHandler("CITmarathon:destroyVehicle", root, serverDestroyVehicle)
231
232function restrictVehEnter(plr, seat, jacked)
233 if (jacked or seat ~= 0) then
234 cancelEvent()
235 end
236end
237addEventHandler("onVehicleStartEnter", resourceRoot, restrictVehEnter)
238
239function serverFinishMarathon()
240 if (not client) then
241 return false
242 end
243 local finishTime = ((getTickCount() - startTick) / 1000) / 60 -- this will be in minutes
244 if (isMarathonWon) then
245exports.CIThelp:dm("Congratulations, you finished the marathon in "..finishTime.."m", client, 0, 255, 0)
246 return true
247 end
248 isMarathonWon = true
249 local winnerName = getPlayerName(client)
250 exports.CIThelp:dm("Congratulations, you finished 1st place and won the marathon with a prize of $"..marathonPrize, client, 0, 255, 0)
251 exports.CIThelp:dm("You finished the marathon in "..finishTime.."m", client, 0, 255, 0)
252 exports.CITmoney:GPM(client, marathonPrize, "CITmarathon: won marathon", 1)
253 dbExec(db, "INSERT INTO `marathonTopTimes` (plrName, plrTime) VALUES (?, ?)", winnerName, finishTime)
254 topTimes[#topTimes + 1] = {name = winnerName, time = finishTime}
255 if (#topTimes > 1) then
256 table.sort(topTimes, function(a, b) return b.time > a.time end)
257 end
258 for i, v in ipairs(getElementsByType("player")) do
259 exports.CIThelp:dm(winnerName.." has won the marathon, congratulations!", v, 128, 0, 128)
260 end
261 exports.CIThelp:dm(winnerName.." has won the marathon, everyone will be automatically warped out in 60 seconds", marathonPlayers, 0, 255, 0)
262 setTimer(endMarathon, 60000, 1)
263end
264addEvent("CITmarathon:finishMarathon", true)
265addEventHandler("CITmarathon:finishMarathon", root, serverFinishMarathon)
266
267function endMarathon()
268 for i, v in ipairs(marathonPlayers) do
269 warpPlayerOutOfMarathon(v)
270 end
271 isMarathonWon = nil
272 marathonCreated = nil
273 marathonStarted = nil
274 marathonPrize = nil
275 startTick = nil
276 MAX_PLAYERS = nil
277
278 removeEventHandler("onPlayerWeaponSwitch", root, onWpnSwitch)
279end
280
281function onPlrWasted()
282 if (not isPlayerInMarathon(source)) then
283 return false
284 end
285 if (previousSkin[source]) then
286 setElementModel(source, previousSkin[source])
287 end
288 if (eventVehicles[source]) then
289 destroyElement(eventVehicles[source])
290 end
291 eventVehicles[source] = nil
292 previousSkin[source] = nil
293 previousLocation[source] = nil
294
295 table.removeValue(marathonPlayers, source)
296 triggerClientEvent(source, "CITmarathon:clientOnPlrWasted", source)
297
298 removeEventHandler("onPlayerWasted", source, onPlrWasted)
299 removeEventHandler("onPlayerWeaponSwitch", source, onWpnSwitch)
300end
301
302function onWpnSwitch()
303 if (not isPlayerInMarathon(source)) then
304 return false
305 end
306 setPedWeaponSlot(source, 0)
307end
308
309function loadTopTimes(query)
310 local results = dbPoll(query, 0)
311 if (not results or #results < 0) then
312 return false
313 end
314 for _, v in ipairs(results) do
315 topTimes[#topTimes + 1] = {name = v.plrName, time = v.plrTime}
316 end
317 if (#topTimes > 1) then
318 table.sort(topTimes, function(a, b) return b.time > a.time end)
319 end
320end
321
322function onResourceStart()
323 db = dbConnect("sqlite", ":/registry.db")
324 if (not db) then
325 return false
326 end
327 dbExec(db, "CREATE TABLE IF NOT EXISTS `marathonTopTimes` (`plrName` TEXT, `plrTime` REAL)")
328 dbQuery(loadTopTimes, db, "SELECT * FROM `marathonTopTimes`")
329end
330addEventHandler("onResourceStart", resourceRoot, onResourceStart)
331
332-- Utility functions
333
334function isPlayerInMarathon(plr)
335 if (not plr) then
336 return false
337 end
338 local exists = nil
339 for i, v in ipairs(marathonPlayers) do
340 if (v == plr) then
341 exists = true
342 break
343 end
344 end
345 if (exists) then
346 return true
347 end
348 return false
349end
350
351function table.removeValue(tab, val)
352 if (not tab or not val) then
353 return false
354 end
355 if (type(tab) ~= "table") then
356 return false
357 end
358 for i, v in ipairs(tab) do
359 if (v == val) then
360 table.remove(tab, i)
361 return i
362 end
363 end
364 return false
365end