· 4 years ago · Feb 12, 2021, 12:46 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 iprint(topTimes)
259 for i, v in ipairs(getElementsByType("player")) do
260 exports.CIThelp:dm(winnerName.." has won the marathon, congratulations!", v, 128, 0, 128)
261 end
262 exports.CIThelp:dm(winnerName.." has won the marathon, everyone will be automatically warped out in 60 seconds", marathonPlayers, 0, 255, 0)
263 setTimer(endMarathon, 60000, 1)
264end
265addEvent("CITmarathon:finishMarathon", true)
266addEventHandler("CITmarathon:finishMarathon", root, serverFinishMarathon)
267
268function endMarathon()
269 for i, v in ipairs(marathonPlayers) do
270 warpPlayerOutOfMarathon(v)
271 end
272 isMarathonWon = nil
273 marathonCreated = nil
274 marathonStarted = nil
275 marathonPrize = nil
276 startTick = nil
277 MAX_PLAYERS = nil
278
279 removeEventHandler("onPlayerWeaponSwitch", root, onWpnSwitch)
280end
281
282function onPlrWasted()
283 if (not isPlayerInMarathon(source)) then
284 return false
285 end
286 if (previousSkin[source]) then
287 setElementModel(source, previousSkin[source])
288 end
289 if (eventVehicles[source]) then
290 destroyElement(eventVehicles[source])
291 end
292 eventVehicles[source] = nil
293 previousSkin[source] = nil
294 previousLocation[source] = nil
295
296 table.removeValue(marathonPlayers, source)
297 triggerClientEvent(source, "CITmarathon:clientOnPlrWasted", source)
298 removeEventHandler("onPlayerWasted", source, onPlrWasted)
299 removeEventHandler("onPlayerWeaponSwitch", source, onWpnSwitch)
300end
301
302function onWpnSwitch()
303 setPedWeaponSlot(source, 0)
304end
305
306function loadTopTimes(query)
307 local results = dbPoll(query, 0)
308 if (not results or #results < 0) then
309 return false
310 end
311 for _, v in ipairs(results) do
312 topTimes[#topTimes + 1] = {name = v.plrName, time = v.plrTime}
313 end
314 if (#topTimes > 1) then
315 table.sort(topTimes, function(a, b) return b.time > a.time end)
316 end
317end
318
319function onResourceStart()
320 db = dbConnect("sqlite", ":/registry.db")
321 if (not db) then
322 return false
323 end
324 dbExec(db, "CREATE TABLE IF NOT EXISTS `marathonTopTimes` (`plrName` TEXT, `plrTime` REAL)")
325 dbQuery(loadTopTimes, db, "SELECT * FROM `marathonTopTimes`")
326end
327addEventHandler("onResourceStart", resourceRoot, onResourceStart)
328
329-- Utility functions
330
331function isPlayerInMarathon(plr)
332 if (not plr) then
333 return false
334 end
335 local exists = nil
336 for i, v in ipairs(marathonPlayers) do
337 if (v == plr) then
338 exists = true
339 break
340 end
341 end
342 if (exists) then
343 return true
344 end
345 return false
346end
347
348function table.removeValue(tab, val)
349 if (not tab or not val) then
350 return false
351 end
352 if (type(tab) ~= "table") then
353 return false
354 end
355 for i, v in ipairs(tab) do
356 if (v == val) then
357 table.remove(tab, i)
358 return i
359 end
360 end
361 return false
362end