· 8 years ago · May 16, 2018, 09:18 AM
1/****************************************************** TODO: Organize skills? More skillz? ************************************************************/
2// Exp stealing? More points for hurt higher level? License for attack skills? Jump, Run, Immunity, box Defense skills
3
4include("exp_settings.lua")
5include("exp_powerups.lua")
6AddCSLuaFile("autorun/client/exp_hud.lua")
7
8// Let's make the files so we can store the exp
9sql.Query("CREATE TABLE IF NOT EXISTS exp_pdata('steam' TEXT NOT NULL, 'exp' INTEGER NOT NULL, 'curlevel' INTEGER NOT NULL, 'nextlevel' INTEGER NOT NULL, 'levelnum' INTEGER NOT NULL, PRIMARY KEY('steam'));")
10if not file.Exists("exp_store.txt") and EXP_USETXT == 1 then file.Write("exp_store.txt","") end
11
12resource.AddFile("sound/"..EXP_SOUNDPATH) // So everyone gets to hear the fun sound
13
14// Just a quick function to print things into everyone's chat
15local function PrintAll(msg) for _,v in ipairs(player.GetAll()) do v:ChatPrint(msg) end end
16
17local meta = FindMetaTable("Player")
18
19CreateConVar("exp_toggle","1",{FCVAR_SERVER_CAN_EXECUTE})
20
21// Some writing/reading functions for text/SQL
22local function WriteTextData(ply)
23 local lines = string.Explode("\n",file.Read("exp_store.txt"))
24 local towrite = ""
25 for k,v in ipairs(lines) do
26 local values = string.Explode(" ",v)
27 if values[1] != ply:SteamID() then towrite = towrite..v
28 else end
29 end
30 file.Write("exp_store.txt",
31 file.Read("exp_store.txt")..ply:SteamID().." "..ply:GetNWInt("Exp").." "..ply:GetNWInt("CurLevel").." "..ply:GetNWInt("NextLevel").." "..ply:GetNWInt("LevelNum").."\n")
32end
33
34local function LoadTextData(ply)
35 local lines = string.Explode("\n",file.Read("exp_store.txt"))
36 for _,v in ipairs(lines) do
37 local values = string.Explode(" ",v)
38 if values[1] == ply:SteamID() then
39 ply:SetNWInt("Exp",values[2])
40 ply:SetNWInt("CurLevel",values[3])
41 ply:SetNWInt("NextLevel",values[4])
42 ply:SetNWInt("LevelNum",values[5])
43 end
44 end
45end
46
47local function SaveSQLData(ply)
48 local exp = ply:GetNWInt("Exp")
49 local cur = ply:GetNWInt("CurLevel")
50 local new = ply:GetNWInt("NextLevel")
51 local lvl = ply:GetNWInt("LevelNum")
52 sql.Begin()
53 sql.Query("UPDATE exp_pdata SET exp = "..exp.." WHERE steam = "..sql.SQLStr(ply:SteamID())..";")
54 sql.Query("UPDATE exp_pdata SET curlevel = "..cur.." WHERE STEAM = "..sql.SQLStr(ply:SteamID())..";")
55 sql.Query("UPDATE exp_pdata SET nextlevel = "..new.." WHERE STEAM = "..sql.SQLStr(ply:SteamID())..";")
56 sql.Query("UPDATE exp_pdata SET levelnum = "..lvl.." WHERE STEAM = "..sql.SQLStr(ply:SteamID())..";")
57 sql.Commit()
58end
59
60local function LoadSQLData(ply)
61 sql.Begin()
62 ply:SetNWInt("Exp",tonumber(sql.QueryValue("SELECT exp FROM exp_pdata WHERE steam = "..sql.SQLStr(ply:SteamID())..";")))
63 ply:SetNWInt("CurLevel",tonumber(sql.QueryValue("SELECT curlevel FROM exp_pdata WHERE steam = "..sql.SQLStr(ply:SteamID())..";")))
64 ply:SetNWInt("NextLevel",tonumber(sql.QueryValue("SELECT nextlevel FROM exp_pdata WHERE steam = "..sql.SQLStr(ply:SteamID())..";")))
65 ply:SetNWInt("LevelNum",tonumber(sql.QueryValue("SELECT levelnum FROM exp_pdata WHERE steam = "..sql.SQLStr(ply:SteamID())..";")))
66 sql.Commit()
67end
68
69
70
71/****************************************************** GAMEMODE HOOKS AND STUFF ****************************************************************/
72
73// Give experience function
74function GiveEXP(ply,amt)
75 if EXP_STOPATMAX == 1 and ply:GetNWInt("CurLevel") == levelups[table.Count(levelups)] then return end
76 if math.random(1,50-ply:GetNWInt("LevelNum")*4) == 5 then ply:SetNWInt("Exp",ply:GetNWInt("Exp")+amt*EXP_CRIT)
77 //ply:ChatPrint("Critical hit!")
78 else ply:SetNWInt("Exp",ply:GetNWInt("Exp")+amt) end
79 local exp = ply:GetNWInt("Exp")
80 if (table.HasValue(levelups,exp) or exp >= ply:GetNWInt("NextLevel")) and amt > 0 then
81 local leveln = 1
82 for k,v in ipairs(levelups) do if v == ply:GetNWInt("NextLevel") then leveln = k end end
83 ply:SetNWInt("NextLevel",levelups[leveln+1])
84 ply:SetNWInt("CurLevel",levelups[leveln])
85 ply:SetNWInt("LevelNum",leveln)
86 hook.Call("LevelGained",nil,ply,leveln)
87 end
88end
89
90
91
92local function GetSkillName(str)
93 local ret = ""
94 for k,v in ipairs(string.Explode("_",str)) do
95 if k != table.Count(string.Explode("_",str)) then ret = ret ..string.upper(string.Left(v,1))..string.Right(v,string.len(v)-1).. " "
96 else ret = ret ..string.upper(string.Left(v,1))..string.Right(v,string.len(v)-1) end
97 end
98 return ret
99end
100
101// Play some fancy sounds and tell them their prize
102hook.Add("LevelGained","LevelTest",function(ply,leveln)
103 if leveln == table.Count(levelups) then PrintAll(ply:Name().." has reached the maximum level!")
104 else PrintAll(ply:GetName().." has now reached level "..Leveln.."!") end
105 ply:ChatPrint("You have new skills available!")
106 for _,v in ipairs(skills) do if v.Level == leveln then ply:ChatPrint(" - "..GetSkillName(v.Name)) end end
107 ply:SendLua("surface.PlaySound(\""..EXP_SOUNDPATH.."\")")
108end)
109
110
111// Give experience/level up on hit an npc or player
112function AddEXPOnHit( ply, hitgroup, dmginfo )
113 local attacker = dmginfo:GetAttacker()
114 if attacker:IsPlayer() then
115 GiveEXP(attacker,EXP_INC)
116 end
117end
118
119function AddEXPOnDeath(vic,wep,killer)
120 if killer:IsPlayer() then GiveEXP(killer,EXP_INC*EXP_DEATHMUL-EXP_INC) end
121end
122
123// Check if we want to use NPCs or Players as the object of exp
124if EXP_USENPC == 1 then
125 hook.Add("ScaleNPCDamage","NPCExp",AddEXPOnHit)
126 hook.Add("OnNPCKilled","NPCDeath",AddEXPOnDeath)
127elseif EXP_USENPC == 2 then
128 hook.Add("ScaleNPCDamage","NPCExp",AddEXPOnHit)
129 hook.Add("OnNPCKilled","NPCDeath",AddEXPOnDeath)
130 hook.Add("ScalePlayerDamage","PlayerExp",AddEXPOnHit)
131 hook.Add("PlayerDeath","PlayerDeath",AddEXPOnDeath)
132else
133 hook.Add("ScalePlayerDamage","PlayerExp",AddEXPOnHit)
134 hook.Add("PlayerDeath","PlayerDeath",AddEXPOnDeath)
135end
136
137
138// Give experience when they throw things with the gravgun
139hook.Add("GravGunPunt","GravEXP",function(ply,ent) GiveEXP(ply,EXP_INC) end)
140
141
142// Take away experience on death
143hook.Add("PlayerDeath","DownEXP",function(ply,wep,killer)
144 local exp = ply:GetNWInt("Exp")
145 local cur = ply:GetNWInt("CurLevel")
146 local loss = math.Round(exp-exp*EXP_DEATHLOSS)
147 if loss < 0 then ply:SetNWInt("Exp",0)
148 elseif loss < cur then
149 if killer:GetNWInt("CurLevel") < cur and killer:IsPlayer() then
150 ply:SetNWInt("Exp",loss)
151 ply:SetNWInt("NewLevel",cur)
152 ply:SetNWInt("LevelNum",ply:GetNWInt("LevelNum")-1)
153 ply:SetNWInt("CurLevel",levelups[ply:GetNWInt("LevelNum")])
154 killer:ChatPrint("You made "..ply:Name().." lose a level!")
155 else ply:SetNWInt("Exp",cur) end
156 else ply:SetNWInt("Exp",loss) end
157end)
158
159
160// Save the values in the SQL on disconnect
161hook.Add("PlayerDisconnected","UpdateEXP",function(ply) if EXP_USETXT == 1 then WriteTextData(ply) else WriteSQLData(ply) end end)
162
163
164// Load or create the player's values on initial connection
165hook.Add("PlayerInitialSpawn","RegisterEXP",function(ply)
166 if not tonumber(sql.QueryValue("SELECT exp FROM exp_pdata WHERE steam = "..sql.SQLStr(ply:SteamID())..";")) then
167 sql.Query("INSERT INTO exp_pdata VALUES("..sql.SQLStr(ply:SteamID())..",".. 0 ..",".. 0 ..","..Levelups[2]..",".. 1 ..");")
168 ply:SetNWInt("Exp",0)
169 ply:SetNWInt("CurLevel",0)
170 ply:SetNWInt("NextLevel",levelups[2])
171 ply:SetNWInt("LevelNum",1)
172 else LoadSQLData(ply) end
173end)
174
175function meta:UseSkill(skilln)
176 if GetConVarNumber("exp_toggle") == 0 then self:ChatPrint("Skills are not enabled at this time.") return end
177 local skused
178 if type(skilln) == "string" and not tonumber(skilln) then
179 for _,v in pairs(skills) do
180 if v.Name == string.lower(skilln) or string.lower(GetSkillName(v.Name)) == string.lower(skilln) then skused = v end
181 end
182 if not skused then self:ChatPrint("That is not a valid skill name.") return end
183 elseif type(tonumber(skilln)) == "number" then
184 skilln = tonumber(skilln)
185 if table.Count(skills) < skilln then self:ChatPrint("There are only "..table.Count(skills).." possible skills at the moment.") return end
186 skused = skills[skilln]
187 PrintTable(skused)
188 end
189
190 self._SkillWait = self._SkillWait or {}
191 local wait = self._SkillWait[skused.ID] or 0
192 if not self._Allowed[tostring(skused.ID)] then self:ChatPrint("You have not bought this skill yet!") return end
193 if self:GetNWBool("exp_silence") then self:ChatPrint("You have been silenced!") return end
194 //if self:GetNWInt("LevelNum") < skused.Level then self:ChatPrint("You must be level "..skused.Level.." to use this skill!") return end
195 if wait > CurTime() then self:ChatPrint("You must wait ".. math.ceil(wait - CurTime()).. " seconds before using "..GetSkillName(skused.Name).." again.") return end
196
197 skused.Func(self)
198 self._SkillWait[skused.ID] = CurTime() + skused.Wait
199 timer.Simple(skused.Wait,function() self:ChatPrint("Your "..GetSkillName(skused.Name).." skill is now recharged.") end)
200end
201
202function meta:SetTarget(ent)
203 if GetConVarNumber("exp_toggle") == 0 then self:ChatPrint("Targets are not enabled at this time.") return end
204 if not ent:IsPlayer() and ent:GetClass() != "prop_physics" and not ent:IsNPC() then self:ChatPrint("Not a valid target!") return end
205 self._Target = ent
206 umsg.Start("exp_target",self)
207 umsg.Entity(ent)
208 umsg.End()
209 //if ent:IsPlayer() then self:ChatPrint("Targeting "..ent:Name()..".")
210 //else self:ChatPrint("Targeting " .. ent:GetClass()..".") end
211end
212
213function meta:GetTarget() return self._Target or false end
214
215function meta:RemoveTarget()
216 self._Target = false
217 umsg.Start("exp_target",self)
218 umsg.Entity(GetWorldEntity())
219 umsg.End()
220end
221
222hook.Add("Think","RemoveTargets",function()
223 for _,v in ipairs(player.GetAll()) do
224 local tar = v:GetTarget()
225 if !tar then v:RemoveTarget() return end
226 if tar:IsPlayer() then
227 if not tar:Alive() then
228 v:RemoveTarget()
229 end
230 elseif tar:IsNPC() then
231 if tar:Health() <= 0 then
232 v:RemoveTarget()
233 end
234 elseif !tar:IsValid() or !ValidEntity(tar) then
235 v:RemoveTarget()
236 end
237 end
238end)
239
240
241/********************************************************** CONCOMMANDS **********************************************************************/
242
243local chatcommands = {}
244
245
246// Allow admins to change the exp level of players
247concommand.Add("exp_setlevel",function(ply,cmd,args)
248 if ply:IsAdmin() then
249 leveln = tonumber(args[2])
250
251 local tar
252 for _,v in ipairs(player.GetAll()) do if string.match(v:Name(),args[1]) then tar = v end end
253
254 if not tar then ply:ChatPrint("Please use a valid target! (format <player name> <level>") return end
255 if leveln < 1 or leveln > (table.Count(levelups)+1) then ply:ChatPrint("Please select a valid level between 1 - ".. table.Count(levelups) .. ".") return end
256
257 tar:SetNWInt("Exp",levelups[leveln])
258 tar:SetNWInt("CurLevel",levelups[leveln])
259 if leveln == table.Count(levelups) then tar:SetNWInt("NextLevel",levelups[leveln])
260 else tar:SetNWInt("NextLevel",levelups[leveln+1]) end
261 ply:SetNWInt("LevelNum",leveln)
262
263 ply:ChatPrint("You set "..tar:Name().."'s level to "..Leveln..".")
264 else ply:ChatPrint("You must be an admin to use this command.") end
265end)
266table.insert(chatcommands,{"setlevel","exp_setlevel <player name> <level number>","Set a player's experience level",true})
267
268// Set a target
269concommand.Add("exp_target",function(pl,cmd,args)
270 pl:SetTarget(pl:GetEyeTrace().Entity)
271end)
272
273// Remove a target
274concommand.Add("exp_removetarget",function(pl)
275 pl:RemoveTarget()
276end)
277
278// Allow admins to change the exp increment per hit via console
279concommand.Add("exp_setinc",function(ply,cmd,args)
280 if ply:IsAdmin() then
281 local inc = tonumber(args[1])
282 if inc < 1 then ply:ChatPrint("Please use a positive integer above zero.") return end
283 EXP_INC = tonumber(args[1])
284 else ply:ChatPrint("You must be an admin to use this command.") end
285end)
286table.insert(chatcommands,{"setinc","exp_setinc <inc number>","Set how much experience you get per hit",true})
287
288
289// Allow anyone to check their current level
290concommand.Add("exp_curlevel",function(ply,cmd,args)
291 for k,v in ipairs(levelups) do if ply:GetNWInt("CurLevel") == v then ply:ChatPrint("You are on level "..k..".") end end
292end)
293table.insert(chatcommands,{"curlevel","exp_curlevel","Prints your current level",false})
294
295
296// Allow admins to save everyone's data in the SQL
297concommand.Add("exp_savedata",function(ply,cmd,args)
298 if ply:IsAdmin() then
299 sql.Begin()
300 for _,v in pairs(player.GetAll()) do
301 if EXP_USETXT == 1 then WriteTextData(v)
302 else SaveSQLData(v) end
303 end
304 sql.Commit()
305 PrintAll("Your Exp data was saved!")
306 else ply:ChatPrint("You must be an admin to use this command.") end
307end)
308table.insert(chatcommands,{"savedata","exp_savedata","Saves all players' current exp to the database",true})
309
310concommand.Add("exp_skill",function(pl,cmd,args)
311 PrintTable(skills[tonumber(args[1])])
312end)
313
314// Allow admins to load data from the previous save
315concommand.Add("exp_loaddata",function(ply,cmd,args)
316 if ply:IsAdmin() then
317 if ply:GetNWBool("HasLoaded") == false then
318 ply:ChatPrint("WARNING: All players will lose progress made after last save! This loads data from the previous save!")
319 ply:ChatPrint("Use this command again if you are sure you want to do this!")
320 ply:SetNWBool("HasLoaded",true)
321 else
322 for _,v in ipairs(player.GetAll()) do LoadSQLData(v) end
323 PrintAll(ply:Name().." has loaded all players' previous save!")
324 ply:SetNWBool("HasLoaded",false)
325 end
326 timer.Simple(10,function() ply:SetNWBool("HasLoaded",false) end)
327 else ply:ChatPrint("You must be an admin to use this command.") end
328end)
329table.insert(chatcommands,{"loaddata","exp_loaddata","Loads all players' current exp from the database",true})
330
331
332// Just in case the SQL fails, let's check why
333concommand.Add("exp_debug",function(ply,cmd,args) if sql.LastError() then ply:ChatPrint(sql.LastError()) else ply:ChatPrint("No SQL errors!") end end)
334table.insert(chatcommands,{"debug","exp_debug","Print the last known error in the database",false})
335
336
337// Get the data from the last save
338concommand.Add("exp_printsql",function(ply,cmd,args)
339 ply:ChatPrint("Data from previous save...")
340 ply:ChatPrint("Experience: "..tonumber(sql.QueryValue("SELECT exp FROM exp_pdata WHERE steam = "..sql.SQLStr(ply:SteamID())..";")))
341 ply:ChatPrint("Base Level Experience: "..tonumber(sql.QueryValue("SELECT curlevel FROM exp_pdata WHERE steam = "..sql.SQLStr(ply:SteamID())..";")))
342 ply:ChatPrint("Next Level: "..tonumber(sql.QueryValue("SELECT nextlevel FROM exp_pdata WHERE steam = "..sql.SQLStr(ply:SteamID())..";")))
343 ply:ChatPrint("Level Number: "..tonumber(sql.QueryValue("SELECT levelnum FROM exp_pdata WHERE steam = "..sql.SQLStr(ply:SteamID())..";")))
344end)
345table.insert(chatcommands,{"printsql","exp_printsql","Print the exp data from your last save",false})
346
347
348// Get the data from right now
349concommand.Add("exp_printnw",function(ply,cmd,args)
350 ply:ChatPrint("Data at this moment...")
351 ply:ChatPrint("Experience: "..ply:GetNWInt("Exp"))
352 ply:ChatPrint("Base Level Experience: "..ply:GetNWInt("CurLevel"))
353 ply:ChatPrint("Next Level: "..ply:GetNWInt("NextLevel"))
354 ply:ChatPrint("Level Number: "..ply:GetNWInt("LevelNum"))
355end)
356table.insert(chatcommands,{"printnw","exp_printnw","Print all of your current exp data",false})
357
358
359// Get all the possible levels
360concommand.Add("exp_printlevels",function(ply,cmd,args) for k,v in ipairs(levelups) do ply:ChatPrint("Level "..k.." - "..v.." experience") end end)
361table.insert(chatcommands,{"printlevels","exp_printlevels","Print all possible levels",false})
362
363table.insert(chatcommands,{"menu","exp_menu","Bring up skill menu",false})
364
365
366// Use the various skills available
367concommand.Add("exp_useskill",function(ply,cmd,args)
368 local str = ""
369 for k,v in ipairs(args) do if k != table.Count(args) then str = str .. v.. " " else str = str..v end end
370 ply:UseSkill(str)
371end)
372table.insert(chatcommands,{"useskill","exp_useskill <skill number>","Use a skill",false})
373
374
375// Let's get a nice view of all the commands available to us
376concommand.Add("exp_help",function(ply,cmd,args)
377 local function Print(msg) ply:PrintMessage(HUD_PRINTCONSOLE,msg) end
378 Print("+++++++++++++++++ ExpPlus Support +++++++++++++++++++++")
379 Print("\n-- General Help --")
380 Print(" * Chat: To use a chatcommand, precede the command with two asterisks (**). \n The command is always the concommand name without the \"exp_\" prefix. (i.e. \"**printlevels\")")
381 Print(" * Gaining EXP: To get EXP, depending on what your local admin decided, you shoot NPCs or other players.\n Admins, to change this, edit the \"exp_data.lua\" file.")
382 Print(" * Powerups: At every level you get stronger and faster. To know specifically how you're getting better,\n ask your local admin.")
383 Print(" * Skills: Like powerups, new abilities, or skills, become available to you at every level.\n Look at the skill list for more info.")
384 Print("\n-- List of Commands --")
385 for _,v in ipairs(chatcommands) do
386 if v[4] == false then Print(v[2].." - "..v[3])
387 else Print(v[2].." - "..v[3].." - ADMIN ONLY") end
388 end
389 Print("\n-- List of Skills --")
390 table.sort(skills,function(a,b) if a.Level == b.Level then return a.Name < b.Name else return a.Level < b.Level end end)
391 for k,v in ipairs(skills) do
392 if k < 10 then Print("Level "..v.Level..": "..GetSkillName(v.Name).." - "..v.Desc.." (default "..k..")")
393 else Print("Level "..v.Level..": "..GetSkillName(v.Name).." - "..v.Desc) end
394 end
395end)
396table.insert(chatcommands,{"help","exp_help","Show this helpful menu",false})
397
398/******************************************************** CHAT COMMANDS **********************************************************************/
399
400
401// So the chatcommands will work
402hook.Add("PlayerSay","EXP_Chat",function(ply,str,toall)
403 if string.Left(str,2) != "**" then return str end
404 local cmd = string.Explode(" ",string.sub(str,3,string.len(str)))
405 local cmdstr = ""
406 for k,v in ipairs(cmd) do if k != 1 then cmdstr = cmdstr .. " ".. v end end
407 for _,v in ipairs(chatcommands) do
408 if cmd[1] == v[1] then ply:ConCommand("exp_"..v[1].." "..cmdstr) end
409 end
410 return ""
411end)
412
413
414/********** LOLWUT **********
415for _,v in ipairs(player.GetAll()) do
416 hook.Add("Think",v:SteamID().."icon",function()
417 local icon = ents.Create("targeticon")
418 icon:SetPos(v:GetPos())
419 end)
420end */