diff --git a/XP Spreadsheet.ods b/XP Spreadsheet.ods new file mode 100644 index 0000000..34e3817 Binary files /dev/null and b/XP Spreadsheet.ods differ diff --git a/lua/d3stats/cl_hud.lua b/lua/d3stats/cl_hud.lua index 9cf291a..096b67d 100644 --- a/lua/d3stats/cl_hud.lua +++ b/lua/d3stats/cl_hud.lua @@ -6,12 +6,9 @@ end -- HUD on the left top of the screen function d3stats.Overlay_Init() - local screenscale = BetterScreenScale() - d3stats.D3StatsOverlay = vgui.Create( "D3StatsOverlay" ) - d3stats.D3StatsOverlay:SetPos( 0, screenscale * 80 ) + d3stats.D3StatsOverlay:SetPos( d3stats.Overlay_X, d3stats.Overlay_Y ) d3stats.D3StatsOverlay:SetSize( 350, 100 ) - end -- Call this function from cl_targetid.lua in the gamemode. Works for ZS, needs adjustments for other gamemodes. diff --git a/lua/d3stats/cl_init.lua b/lua/d3stats/cl_init.lua index 77ac4f5..324f172 100644 --- a/lua/d3stats/cl_init.lua +++ b/lua/d3stats/cl_init.lua @@ -14,4 +14,3 @@ include( "vgui/overlay.lua" ) hook.Add( "Initialize", "D3Stats_Init", function () d3stats.Overlay_Init() end ) - diff --git a/lua/d3stats/gamemodes/sv_zombiesurvival.lua b/lua/d3stats/gamemodes/sv_zombiesurvival.lua index eaeca4d..4eb8566 100644 --- a/lua/d3stats/gamemodes/sv_zombiesurvival.lua +++ b/lua/d3stats/gamemodes/sv_zombiesurvival.lua @@ -23,4 +23,28 @@ end ) -- Message on levelchange hook.Add( "D3Stats_LevelChanged", "D3Stats_ZS_LevelChanged", function ( ply, oldLevel, Level ) ply:CenterNotify( Color( 0, 255, 255 ), "You ascended to level " .. tostring( Level ) .. " \"" .. d3stats.Levels[Level].Name .. "\"") +end ) + +-- Handle "Use_Hammer" permission. TODO: Only prevent that the person can nail things +hook.Add( "PlayerSwitchWeapon", "D3Stats_ZS_EquipHammer", function( ply, oldWeapon, newWeapon ) + local Class = newWeapon:GetClass() + + if not ply:D3Stats_HasPermission( "Use_Hammer" ) then + if Class == "weapon_zs_hammer" or Class == "weapon_zs_electrohammer" then + ply:CenterNotify( Color( 255, 0, 0 ), string.format( d3stats.Disallow_Hold_Hammer, d3stats.GetPermissionLevel( "Use_Hammer" ) ) ) + return true + end + end +end ) + +-- Handle EndRound events for statistics +hook.Add( "EndRound", "D3Stats_ZS_EndRound", function( team ) + local won = ( TEAM_SURVIVORS == team ) and true or false + + d3stats.Map_End( won ) +end ) + +-- Display map statistic message when the player joined +hook.Add( "PlayerReady", "D3Stats_Map_PlayerReady", function ( ply ) + d3stats.Map_Message( false, ply ) end ) \ No newline at end of file diff --git a/lua/d3stats/init.lua b/lua/d3stats/init.lua index 86ed9cf..b25b20c 100644 --- a/lua/d3stats/init.lua +++ b/lua/d3stats/init.lua @@ -21,6 +21,8 @@ include( "sh_level.lua" ) include( "sh_concommand.lua" ) include( "gamemodes/sv_zombiesurvival.lua" ) +include( "sv_storage.lua" ) +include( "sv_map.lua" ) include( "sv_network.lua" ) hook.Add( "PlayerInitialSpawn", "D3Stats_PlayerSpawn", function ( ply ) @@ -32,6 +34,15 @@ hook.Add( "PlayerInitialSpawn", "D3Stats_PlayerSpawn", function ( ply ) ply:SetNWInt( "D3Stats_Level", ply.D3Stats_Level ) end ) +-- Initialisation +hook.Add( "Initialize", "D3Stats_Init", function () + d3stats.Storage.Initialize() + + resource.AddFile("resource/fonts/ghoulfriaoe.ttf") + resource.AddFile("resource/fonts/hauntaoe.ttf") + resource.AddFile("resource/fonts/nightaoe.ttf") +end ) + local meta = FindMetaTable( "Player" ) if not meta then return end @@ -84,4 +95,4 @@ function meta:D3Stats_HasPermission( Permission ) end return d3stats.LevelCheckPermission( self:D3Stats_GetLevel(), Permission ) -end \ No newline at end of file +end diff --git a/lua/d3stats/sh_level.lua b/lua/d3stats/sh_level.lua index 2e5cade..196c6e4 100644 --- a/lua/d3stats/sh_level.lua +++ b/lua/d3stats/sh_level.lua @@ -2,7 +2,7 @@ function d3stats.CalculateLevel( XP ) local Level = 1 - for key, value in pairs(d3stats.Levels) do + for key, value in pairs( d3stats.Levels ) do if value.XP_needed <= XP then Level = key else @@ -17,7 +17,12 @@ end function d3stats.LevelCheckPermission( Level, Permission ) local Granted = false - for key, value in pairs(d3stats.Levels) do + -- If the permission is not on the list, allow it + if not d3stats.Permissions[Permission] then + return true + end + + for key, value in pairs( d3stats.Levels ) do if key <= Level then if value.Permissions and value.Permissions[Permission] then Granted = value.Permissions[Permission] @@ -30,6 +35,23 @@ function d3stats.LevelCheckPermission( Level, Permission ) return Granted end +-- Returns what level is needed for the given permission +function d3stats.GetPermissionLevel( Permission ) + local Level + + if not d3stats.Permissions[Permission] then + return 1 + end + + for key, value in pairs( d3stats.Levels ) do + if value.Permissions and value.Permissions[Permission] then + return key + end + end + + return nil +end + -- Count the amount of online players who have the permission if SERVER then function d3stats.CountPermissionPlayers( Permission, Team ) @@ -37,7 +59,7 @@ if SERVER then local players = player.GetAll() for key, ply in pairs( players ) do - if Team == nil or pl:Team() == Team then + if Team == nil or ply:Team() == Team then if d3stats.LevelCheckPermission( ply:D3Stats_GetLevel(), Permission ) == true then Counter = Counter + 1 end diff --git a/lua/d3stats/sh_settings.lua b/lua/d3stats/sh_settings.lua index d9dedcb..7899faa 100644 --- a/lua/d3stats/sh_settings.lua +++ b/lua/d3stats/sh_settings.lua @@ -5,47 +5,48 @@ Settings and level definitions are stored in here ]] -- Permissions --- AllowIfLessThan: If the amount of players who have the permission is lower than this number, allow it anyways --- Team: Reduces count to the specified team. In ZS: TEAM_SURVIVOR = 4 +-- Everything not in this list will be allowed by default +-- AllowIfLessThan: If the amount of players who have the permission is lower than this number, allow it anyway +-- Team: Reduces count to the specified team. In ZS: TEAM_SURVIVOR = 4, d3stats.Permissions = { - ["Buy_Hammer"] = { AllowIfLessThan = 2, Team = 4 }, - ["Use_Hammer"] = { AllowIfLessThan = 2, Team = 4 }, + ["Buy_Hammer"] = { AllowIfLessThan = 4, Team = 4 }, + ["Use_Hammer"] = { AllowIfLessThan = 4, Team = 4 }, } -- Levels, please sort by XP d3stats.Levels = { - { XP_needed = 0, Name = "Kleiner" }, - { XP_needed = 500, Name = "Lesser Kleiner" }, - { XP_needed = 1000, Name = "Dayfly" }, - { XP_needed = 2000, Name = "Apprentice", Permissions = { ["Buy_Hammer"] = true, ["Use_Hammer"] = true } }, - { XP_needed = 3000, Name = "Adventurer" }, - { XP_needed = 4000, Name = "Scout" }, - { XP_needed = 5000, Name = "Guardian" }, - { XP_needed = 6000, Name = "Fighter" }, - { XP_needed = 7000, Name = "Brawler" }, - { XP_needed = 8000, Name = "Scrapper" }, - { XP_needed = 9000, Name = "Skirmisher" }, - { XP_needed = 10000, Name = "Battler" }, - { XP_needed = 15000, Name = "Marauder" }, - { XP_needed = 20000, Name = "Slayer" }, - { XP_needed = 25000, Name = "Mercenary" }, - { XP_needed = 30000, Name = "Swordsman" }, - { XP_needed = 35000, Name = "Freelancer" }, - { XP_needed = 40000, Name = "Swashbuckler" }, - { XP_needed = 45000, Name = "Vanquisher" }, - { XP_needed = 50000, Name = "Exemplar" }, - { XP_needed = 60000, Name = "Conqueror" }, - { XP_needed = 70000, Name = "Specialist" }, - { XP_needed = 80000, Name = "Lieutenant" }, - { XP_needed = 90000, Name = "Captain" }, - { XP_needed = 100000, Name = "Major" }, - { XP_needed = 133333, Name = "Colonel" }, - { XP_needed = 166666, Name = "General" }, - { XP_needed = 200000, Name = "Champion" }, - { XP_needed = 250000, Name = "Hero" }, - { XP_needed = 300000, Name = "Legend" }, - { XP_needed = 500000, Name = "Demigod" }, - { XP_needed = 1000000, Name = "God" }, + { XP_needed = 500, Name = "Citizen" }, + { XP_needed = 1370, Name = "Survivor" }, + { XP_needed = 2612, Name = "Rogue" }, + { XP_needed = 4225, Name = "Engineer", Permissions = { ["Buy_Hammer"] = true, ["Use_Hammer"] = true } }, + { XP_needed = 6209, Name = "Scout" }, + { XP_needed = 8564, Name = "Officer" }, + { XP_needed = 11290, Name = "Guardian" }, + { XP_needed = 14387, Name = "Fighter" }, + { XP_needed = 17854, Name = "Brawler" }, + { XP_needed = 21693, Name = "Scrapper" }, + { XP_needed = 25903, Name = "Skirmisher" }, + { XP_needed = 30483, Name = "Battler" }, + { XP_needed = 35435, Name = "Marauder" }, + { XP_needed = 40758, Name = "Slayer" }, + { XP_needed = 46451, Name = "Mercenary" }, + { XP_needed = 52516, Name = "Swordsman" }, + { XP_needed = 58951, Name = "Freelancer" }, + { XP_needed = 65758, Name = "Swashbuckler" }, + { XP_needed = 72935, Name = "Vanquisher" }, + { XP_needed = 80483, Name = "Exemplar" }, + { XP_needed = 88403, Name = "Conqueror" }, + { XP_needed = 96693, Name = "Specialist" }, + { XP_needed = 105354, Name = "Lieutenant" }, + { XP_needed = 114387, Name = "Captain" }, + { XP_needed = 123790, Name = "Major" }, + { XP_needed = 133564, Name = "Colonel" }, + { XP_needed = 143709, Name = "General" }, + { XP_needed = 154225, Name = "Champion" }, + { XP_needed = 165112, Name = "Hero" }, + { XP_needed = 176370, Name = "Legend" }, + { XP_needed = 188000, Name = "Demigod" }, + { XP_needed = 200000, Name = "God" }, } d3stats.PlayerPointsAdded_Limit = 200 -- Ignore all "PlayerPointsAdded" callbacks above this XP value @@ -56,12 +57,39 @@ d3stats.ZombieKilledHuman_Static = 100 -- Amount of XP a zombie gets for killin d3stats.ZombieKilledHuman_Max = 1000 -- Upper XP reward clamp d3stats.ZombieKilledHuman_Min = 0 -- Lower XP reward clamp --- Fonts +-- Messages TODO: Multilanguage +d3stats.Disallow_Hold_Hammer = "You can't use the hammer until you have reached level %i" +d3stats.MapStats_Zero = "We are playing %s." -- Message to players who just joined +d3stats.MapStats = "We are playing %s. Humans won %i of %i times (%.1f%%)" -- Message to players who just joined (With statistics) +d3stats.MapStats_End = "%s has been won %i of %i times (%.1f%%)" -- Message to all players at the end of the round (With statistics) + if CLIENT then - surface.CreateFont( "D3Stats_OverlayFont", { - font = "Typenoksidi", - extended = true, - size = 16, + -- Overlay positions + d3stats.Overlay_X = 0 + d3stats.Overlay_Y = 80 * math.Clamp(ScrH() / 1080, 0.6, 1) -- This needs to be redone + + -- Fonts + surface.CreateFont( "D3Stats_OverlayFont_XP", { + font = "Ghoulish Fright AOE", + extended = false, + size = 22, + weight = 0, + blursize = 0, + scanlines = 0, + antialias = true, + underline = false, + italic = false, + strikeout = false, + symbol = false, + rotary = false, + shadow = false, + additive = false, + outline = false, + } ) + surface.CreateFont( "D3Stats_OverlayFont_Level", { + font = "Haunt AOE", + extended = false, + size = 26, weight = 0, blursize = 0, scanlines = 0, @@ -75,7 +103,8 @@ if CLIENT then additive = false, outline = true, } ) - - d3stats.Font_Overlay = "D3Stats_OverlayFont" - d3stats.Font_TargetID = "D3Stats_OverlayFont" + + d3stats.Font_Overlay_XP = "D3Stats_OverlayFont_XP" + d3stats.Font_Overlay_Level = "D3Stats_OverlayFont_Level" + d3stats.Font_TargetID = "ZSHUDFontTiny" -- Use ZS Font end \ No newline at end of file diff --git a/lua/d3stats/sv_map.lua b/lua/d3stats/sv_map.lua new file mode 100644 index 0000000..3ad8df9 --- /dev/null +++ b/lua/d3stats/sv_map.lua @@ -0,0 +1,33 @@ +function d3stats.Map_Message( roundend, ply ) + local map = game.GetMap() + local count, wins, avg_players = d3stats.Storage.Map_Get( map ) + + local Message + if count > 0 then + if roundend == true then + Message = string.format( d3stats.MapStats_End, map, wins, count, wins / count * 100 ) + else + Message = string.format( d3stats.MapStats, map, wins, count, wins / count * 100 ) + end + else + Message = string.format( d3stats.MapStats_Zero, map ) + end + + if ply then + ply:ChatPrint( Message ) + else + PrintMessage( HUD_PRINTTALK, Message ) + end +end + +function d3stats.Map_End( won ) + local map = game.GetMap() + + d3stats.Storage.Map_AddOutcome( map, won, #player.GetAll() ) + + d3stats.Map_Message( true ) +end + +--d3stats.Map_End( false ) + +--d3stats.Map_Message( false, player.GetByID(1) ) \ No newline at end of file diff --git a/lua/d3stats/sv_storage.lua b/lua/d3stats/sv_storage.lua new file mode 100644 index 0000000..37d9d35 --- /dev/null +++ b/lua/d3stats/sv_storage.lua @@ -0,0 +1,53 @@ +--[[ + +Storage stuff + +]] + +d3stats.Storage = {} + +function d3stats.Storage.Initialize() + -- Storage for map data + if not sql.TableExists( "d3stats_maps") then + local result = sql.Query( "CREATE TABLE d3stats_maps ( name varchar(255) PRIMARY KEY, count INT, wins INT, avg_players REAL )" ) + end +end + +function d3stats.Storage.Map_AddOutcome( name, won, players ) + local count = 1 + local wins = 0 + local avg_players = players + if won == true then wins = 1 end + + local result = sql.QueryRow( "SELECT count, wins, avg_players FROM d3stats_maps WHERE name = '" .. name .. "'" ) + if result then + if result ~= false then + count = count + tonumber( result.count ) + wins = tonumber( result.wins ) + 1 * ( won and 1 or 0 ) + avg_players = ( players + tonumber( result.avg_players ) ) / 2 + else + Print(sql.LastError()) + end + end + + local result = sql.Query( "INSERT OR REPLACE INTO d3stats_maps ( name, count, wins, avg_players ) VALUES ( '" .. name .. "', " .. tostring(count) .. ", " .. tostring(wins) .. ", " .. tostring(avg_players) .. " );" ) +end + +function d3stats.Storage.Map_Get( name ) + local count = 0 + local wins = 0 + local avg_players = 0 + + local result = sql.QueryRow( "SELECT count, wins, avg_players FROM d3stats_maps WHERE name = '" .. name .. "'" ) + if result then + if result ~= false then + count = tonumber( result.count ) + wins = tonumber( result.wins ) + avg_players = tonumber( result.avg_players ) + else + Print(sql.LastError()) + end + end + + return count, wins, avg_players +end \ No newline at end of file diff --git a/lua/d3stats/vgui/overlay.lua b/lua/d3stats/vgui/overlay.lua index ccc5637..efce567 100644 --- a/lua/d3stats/vgui/overlay.lua +++ b/lua/d3stats/vgui/overlay.lua @@ -4,11 +4,21 @@ function PANEL:Init() self.Progress = vgui.Create( "DProgress", self ) self.Progress:SetPos( 10, 10 ) - self.Progress:SetSize( 200, 10 ) + self.Progress:SetSize( 200, 20 ) + + self.Label_XP = vgui.Create( "DLabel", self ) + self.Label_XP:SetTextColor( color_black ) + self.Label_XP:SetFont( d3stats.Font_Overlay_XP ) + self.Label_XP:SetSize( 200, 20 ) + self.Label_XP:SetPos( 10, 10 ) -- Set the position of the label + self.Label_XP:SetContentAlignment( 5 ) + + self.Label_Level = vgui.Create( "DLabel", self ) + self.Label_Level:SetFont( d3stats.Font_Overlay_Level ) + self.Label_Level:SetPos( 10, 35 ) -- Set the position of the label + self.Label_Level:SetSize( 200, 20 ) + self.Label_Level:SetContentAlignment( 5 ) - self.Label = vgui.Create( "DLabel", self ) - self.Label:SetFont(d3stats.Font_Overlay) - self.Label:SetPos( 10, 25 ) -- Set the position of the label self:StatsUpdate( 0, 1 ) --self.Label:SetDark( 1 ) -- Set the colour of the text inside the label to a darker one @@ -22,19 +32,25 @@ function PANEL:Paint( aWide, aTall ) end function PANEL:StatsUpdate( XP, Level ) - local Text + local Text_XP + local Text_Level local Fraction if d3stats.Levels[Level+1] then - Text = "XP: " .. tostring( XP ) .. " / " .. d3stats.Levels[Level+1].XP_needed .. "\nLevel: " .. tostring( Level ) .. " \"" .. d3stats.Levels[Level].Name .. "\"" + Text_XP = "XP: " .. tostring( XP ) .. " / " .. d3stats.Levels[Level+1].XP_needed Fraction = ( XP - d3stats.Levels[Level].XP_needed ) / ( d3stats.Levels[Level+1].XP_needed - d3stats.Levels[Level].XP_needed ) else - Text = "XP: " .. tostring( XP ) .. "\nLevel: " .. tostring( Level ) .. " \"" .. d3stats.Levels[Level].Name .. "\"" + Text_XP = "XP: " .. tostring( XP ) Fraction = 1 end - self.Label:SetText( Text ) -- Set the text of the label - self.Label:SizeToContents() -- Size the label to fit the text in it + Text_Level = "Level: " .. tostring( Level ) .. " \"" .. d3stats.Levels[Level].Name .. "\"" + + self.Label_XP:SetText( Text_XP ) -- Set the text of the label + --self.Label_XP:SizeToContents() -- Size the label to fit the text in it + + self.Label_Level:SetText( Text_Level ) -- Set the text of the label + --self.Label_Level:SizeToContents() -- Size the label to fit the text in it self.Progress:SetFraction( Fraction ) diff --git a/resource/fonts/ghoulfriaoe.ttf b/resource/fonts/ghoulfriaoe.ttf new file mode 100644 index 0000000..73c1f56 Binary files /dev/null and b/resource/fonts/ghoulfriaoe.ttf differ diff --git a/resource/fonts/hauntaoe.ttf b/resource/fonts/hauntaoe.ttf new file mode 100644 index 0000000..7df2011 Binary files /dev/null and b/resource/fonts/hauntaoe.ttf differ diff --git a/resource/fonts/nightaoe.ttf b/resource/fonts/nightaoe.ttf new file mode 100644 index 0000000..02f5a53 Binary files /dev/null and b/resource/fonts/nightaoe.ttf differ