-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathserver.lua
More file actions
176 lines (151 loc) · 5.6 KB
/
Copy pathserver.lua
File metadata and controls
176 lines (151 loc) · 5.6 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
local webHookLink = "INSERT DISCORD WEBHOOK LINK HERE"
----------------------------------------------------------------
-- Framework setup (ESX & QBCore)
----------------------------------------------------------------
local Framework = (GetResourceState('es_extended') ~= 'missing' and 'ESX')
or (GetResourceState('qb-core') ~= 'missing' and 'QBCore')
or 'ESX'
local ESX, QBCore
if Framework == 'ESX' then
ESX = exports['es_extended']:getSharedObject()
elseif Framework == 'QBCore' then
QBCore = exports['qb-core']:GetCoreObject()
end
local payCooldown = {} -- [src] = os.time() of the last successful revive payment
----------------------------------------------------------------
-- Helpers
----------------------------------------------------------------
local function countOnlineMedics()
local count = 0
if Framework == 'ESX' then
for _, job in ipairs(Config.Jobs.jobs) do
local players = ESX.GetExtendedPlayers('job', job)
count = count + (players and #players or 0)
end
elseif Framework == 'QBCore' then
for _, Player in pairs(QBCore.Functions.GetQBPlayers()) do
local jobName = Player.PlayerData.job.name
for _, job in ipairs(Config.Jobs.jobs) do
if job == jobName then
count = count + 1
break
end
end
end
end
return count
end
-- Returns: cash, bank, playerObject (or nil if the player is not loaded)
local function getPlayerMoney(src)
if Framework == 'ESX' then
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer then return nil end
return xPlayer.getAccount('money').money, xPlayer.getAccount('bank').money, xPlayer
elseif Framework == 'QBCore' then
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return nil end
return Player.PlayerData.money['cash'], Player.PlayerData.money['bank'], Player
end
end
local function removePlayerMoney(player, accountKey, amount)
if Framework == 'ESX' then
player.removeAccountMoney(accountKey == 'bank' and 'bank' or 'money', amount)
elseif Framework == 'QBCore' then
player.Functions.RemoveMoney(accountKey == 'bank' and 'bank' or 'cash', amount, 'msk_aimedic')
end
end
local function getPlayerName(src)
if Framework == 'ESX' then
local xPlayer = ESX.GetPlayerFromId(src)
return xPlayer and xPlayer.getName() or ('Player ' .. src)
elseif Framework == 'QBCore' then
local Player = QBCore.Functions.GetPlayer(src)
if Player then
local ci = Player.PlayerData.charinfo
return ('%s %s'):format(ci.firstname, ci.lastname)
end
end
return 'Player ' .. src
end
local function sendDiscordLog(src)
if not Config.DiscordLog then return end
local content = {{
["title"] = "MSK AI Medic",
["description"] = Translation[Config.Locale]['discord_webhook']:format(getPlayerName(src), src),
["color"] = Config.botColor,
["footer"] = {
["text"] = "© MSK Scripts • " .. os.date("%d/%m/%Y %H:%M:%S"),
["icon_url"] = Config.botAvatar
}
}}
PerformHttpRequest(webHookLink, function() end, 'POST', json.encode({
username = Config.botName,
embeds = content,
avatar_url = Config.botAvatar
}), {
['Content-Type'] = 'application/json'
})
end
----------------------------------------------------------------
-- Broadcast online medic count to everyone
----------------------------------------------------------------
CreateThread(function()
while true do
TriggerClientEvent('msk_aimedic:refreshMedics', -1, countOnlineMedics())
Wait(10000)
end
end)
AddEventHandler('playerDropped', function()
payCooldown[source] = nil
end)
----------------------------------------------------------------
-- Callbacks (server-authoritative)
----------------------------------------------------------------
MSK.Callback.Register('msk_aimedic:getOnlineMedics', function(src, cb)
cb(countOnlineMedics())
end)
MSK.Callback.Register('msk_aimedic:canAfford', function(src, cb)
local cash, bank = getPlayerMoney(src)
if not cash then return cb(false) end
cb((cash >= Config.RevivePrice) or (bank >= Config.RevivePrice))
end)
MSK.Callback.Register('msk_aimedic:payRevive', function(src, cb)
-- S2: anti-spam cooldown
local now = os.time()
if payCooldown[src] and (now - payCooldown[src]) < 5 then
return cb(false)
end
-- A real medic must not be online
if countOnlineMedics() > Config.Jobs.amount then
return cb(false)
end
-- R4: server-side funds validation (cash first, then bank)
local cash, bank, player = getPlayerMoney(src)
if not player then return cb(false) end
local accountKey
if cash >= Config.RevivePrice then
accountKey = 'money'
elseif bank >= Config.RevivePrice then
accountKey = 'bank'
else
return cb(false)
end
removePlayerMoney(player, accountKey, Config.RevivePrice)
if Config.Society.enable then
local societyName = (Config.Society.account or ''):gsub('^society_', '')
exports.msk_core:SocietyAddMoney(societyName, Config.RevivePrice)
end
payCooldown[src] = now
sendDiscordLog(src)
cb(true)
end)
----------------------------------------------------------------
-- Version check
----------------------------------------------------------------
if Config.VersionChecker then
exports.msk_core:CheckVersion({
author = 'MSK-Scripts',
name = 'msk_aimedic',
print = true,
})
end