├── README.md └── deathrun ├── deathrun.txt ├── gamemode ├── cl_frames.lua ├── cl_init.lua ├── cl_scoreboard.lua ├── cl_voice.lua ├── init.lua ├── menutext.lua ├── rtv │ ├── cl_rtv.lua │ ├── config.lua │ └── sv_rtv.lua ├── shared.lua ├── sv_round.lua └── sv_weps.lua ├── hook_examples.lua ├── icon24.png ├── logo.png └── readme.txt /README.md: -------------------------------------------------------------------------------- 1 | ###This project is not under active development. 2 | ============ 3 | [Gamemode info here.](https://github.com/Mr-Gash/GMod-Deathrun/blob/master/deathrun/readme.txt) 4 | 5 | Facepunch thread @ http://facepunch.com/showthread.php?t=1242352 6 | -------------------------------------------------------------------------------- /deathrun/deathrun.txt: -------------------------------------------------------------------------------- 1 | "Gamemode" 2 | { 3 | "base" "base" 4 | "title" "Deathrun" 5 | "maps" "^deathrun_|^dr_" 6 | "author" "Mr. Gash" 7 | "menusystem" "1" 8 | 9 | "settings" 10 | { 11 | 1 12 | { 13 | "name" "dr_roundtime_seconds" 14 | "text" "Round Time (in seconds)" 15 | "help" "The length of the round in seconds." 16 | "type" "Numeric" 17 | "default" "360" 18 | } 19 | 20 | 2 21 | { 22 | 23 | "name" "dr_total_rounds" 24 | "text" "Total Rounds" 25 | "help" "The amount of rounds to play before changing the map." 26 | "type" "Numeric" 27 | "default" "10" 28 | 29 | } 30 | 31 | 3 32 | { 33 | 34 | "name" "dr_death_rate" 35 | "text" "Percent of Death Players" 36 | "help" "Percentage of total players that will become a death. The player amount is multiplied by this number, then rounded down." 37 | "type" "Numeric" 38 | "default" "0.25" 39 | 40 | } 41 | 42 | 4 43 | { 44 | 45 | "name" "dr_death_max" 46 | "text" "Maximum Amount of Deaths" 47 | "help" "The maximum amount players allowed to be in the Death team." 48 | "type" "Numeric" 49 | "default" "6" 50 | 51 | } 52 | 53 | 54 | 5 55 | { 56 | "name" "dr_highlight_admins" 57 | "text" "Highlight Admins" 58 | "help" "When enabled, the scoreboard will show admins with a gold name and a shield icon." 59 | "type" "CheckBox" 60 | "default" "1" 61 | } 62 | 63 | 6 64 | { 65 | 66 | "name" "dr_allow_death_suicide" 67 | "text" "Suicide Allowed for Deaths" 68 | "help" "If disabled, players on the Death team will not be allowed to kill themselves." 69 | "type" "CheckBox" 70 | "default" "0" 71 | 72 | } 73 | 74 | 7 75 | { 76 | 77 | "name" "dr_allow_autojump" 78 | "text" "Allow Autojump" 79 | "help" "If set to 0, players will not autojump by holding down their spacebar (regardless if they have it enabled/disabled). I don't recommend disabling this." 80 | "type" "CheckBox" 81 | "default" "1" 82 | 83 | } 84 | 85 | 8 86 | { 87 | 88 | "name" "dr_unlimited_ammo" 89 | "text" "Unlimited Ammo" 90 | "help" "If set to 1, primary ammo will not be taken when players shoot weapons. This won't work with default HL2 weapons." 91 | "type" "CheckBox" 92 | "default" "1" 93 | 94 | } 95 | 96 | 9 97 | { 98 | 99 | "name" "dr_allow_death_pickup" 100 | "text" "Deaths Can Use All Weapons" 101 | "help" "If set to 0, players on the Death team will be unable to pick up any weapons aside from the crowbar." 102 | "type" "CheckBox" 103 | "default" "0" 104 | 105 | } 106 | 107 | 10 108 | { 109 | 110 | "name" "dr_realistic_fall_damage" 111 | "text" "Realistic Fall Damage" 112 | "help" "If set to 1, players will be damaged based on the speed at which they fall. If set to 0, the fall damage will be 10, regardless of speed or height." 113 | "type" "CheckBox" 114 | "default" "1" 115 | 116 | } 117 | 118 | 11 119 | { 120 | 121 | "name" "dr_notify_rounds_left" 122 | "text" "Notify Rounds Left on Prep Phase" 123 | "help" "Notify everyone on the server how many rounds are left as the prep phase begins." 124 | "type" "CheckBox" 125 | "default" "1" 126 | 127 | } 128 | 129 | 12 130 | { 131 | 132 | "name" "dr_push_collide" 133 | "text" "Push on Collide" 134 | "help" "If set to 1, when one player enters another, they will be pushed apart." 135 | "type" "CheckBox" 136 | "default" "0" 137 | 138 | } 139 | 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /deathrun/gamemode/cl_frames.lua: -------------------------------------------------------------------------------- 1 | if SERVER then return end 2 | 3 | local PANEL = {} 4 | 5 | function PANEL:Init() 6 | end 7 | 8 | function PANEL:Paint( w, h ) 9 | 10 | surface.SetDrawColor( Color( 44, 44, 44, 200 ) ) 11 | surface.DrawRect( 0, 0, w, h ) 12 | 13 | surface.SetDrawColor( Color( 99, 99, 99, 235 ) ) 14 | surface.DrawRect( 0, 0, w, 25 ) 15 | 16 | end 17 | 18 | vgui.Register( "dFrame", PANEL, "DFrame" ) -------------------------------------------------------------------------------- /deathrun/gamemode/cl_init.lua: -------------------------------------------------------------------------------- 1 | if CLIENT then 2 | 3 | include( "shared.lua" ) 4 | 5 | surface.CreateFont( "Deathrun_Smooth", { font = "Trebuchet18", size = 14, weight = 700, antialias = true } ) 6 | surface.CreateFont( "Deathrun_SmoothMed", { font = "Trebuchet18", size = 24, weight = 700, antialias = true } ) 7 | surface.CreateFont( "Deathrun_SmoothBig", { font = "Trebuchet18", size = 34, weight = 700, antialias = true } ) 8 | 9 | end 10 | include( "cl_scoreboard.lua" ) 11 | include( "cl_frames.lua" ) 12 | include( "menutext.lua" ) 13 | include( "cl_voice.lua" ) 14 | 15 | include( "rtv/config.lua" ) 16 | include( "rtv/cl_rtv.lua" ) 17 | 18 | if SERVER then return end 19 | 20 | local name = "Dragon Dildo" 21 | 22 | language.Add( "trigger_hurt", name ) 23 | language.Add( "env_explosion", name ) 24 | language.Add( "worldspawn", name ) 25 | language.Add( "func_movelinear", name ) 26 | language.Add( "func_physbox", name ) 27 | language.Add( "func_rotating", name ) 28 | language.Add( "func_door", name ) 29 | language.Add( "entityflame", name ) 30 | language.Add( "prop_physics", name ) 31 | 32 | function draw.AAText( text, font, x, y, color, align ) 33 | 34 | draw.SimpleText( text, font, x+1, y+1, Color(0,0,0,math.min(color.a,120)), align ) 35 | draw.SimpleText( text, font, x+2, y+2, Color(0,0,0,math.min(color.a,50)), align ) 36 | draw.SimpleText( text, font, x, y, color, align ) 37 | 38 | end 39 | 40 | local clamp = math.Clamp 41 | 42 | local hx, hw, hh, border = 5, 204, 30, 2 43 | 44 | local keys = {} 45 | local draw_keys = false 46 | 47 | function GM:HUDPaint( ) 48 | 49 | local ply = LocalPlayer() 50 | local ob = ply:GetObserverTarget() 51 | if ob and IsValid(ob) and ob:IsPlayer() and ob:Alive() then 52 | draw.AAText( ob:Nick(), "Deathrun_SmoothBig", ScrW()/2, 5, Color(255,255,255,255), TEXT_ALIGN_CENTER) 53 | ply = ob 54 | draw_keys = true 55 | else 56 | draw_keys = false 57 | end 58 | if not keys[ply] then 59 | keys[ply] = {} 60 | end 61 | 62 | local hy = ScrH() - 35 63 | 64 | draw.RoundedBox( 0, hx, hy, hw, hh, Color( 44, 44, 44, 175 ) ) 65 | draw.RoundedBox( 0, hx + border, hy + border, hw - border*2, hh - border*2, Color( 180, 80, 80, 255 ) ) 66 | local thp = ply:Alive() and ply:Health() or 0 67 | local hp = thp 68 | if hp > 0 then 69 | hp = ( hw - border*2 ) * ( math.Clamp(ply:Health(),0,100)/100) 70 | draw.RoundedBox( 0, hx + border, hy + border, hp, hh - border*2, Color( 80, 180, 60, 255 ) ) 71 | end 72 | 73 | draw.AAText( tostring( thp > 999 and "dafuq" or math.max(thp, 0) ), "Deathrun_SmoothBig", hx + 5, hy - 3, Color(255,255,255,255), TEXT_ALIGN_LEFT ) 74 | 75 | surface.SetFont( "Deathrun_SmoothBig" ) 76 | local rt = string.ToMinutesSeconds(self:GetRoundTime()) 77 | local ttw, _ = surface.GetTextSize( rt ) 78 | 79 | local tw = hw/2 + 5 80 | draw.WordBox( 4, tw - ttw/2, hy - 45, rt, "Deathrun_SmoothBig", Color( 44, 44, 44, 200 ), Color( 255, 255, 255, 255 ) ) 81 | 82 | if draw_keys then 83 | local w, h = 25, 25 84 | local scrh = ScrH()/2 + h 85 | local center = ScrW()/2 - w/2 86 | 87 | local back_pos_y = scrh + h + 5 88 | 89 | local Keys = keys[ply] or {} 90 | 91 | surface.SetDrawColor( Color( 34, 45, 56, 50 ) ) 92 | surface.DrawRect( center, scrh, w, h ) 93 | 94 | surface.SetDrawColor( Color( 34, 45, 56, 200 ) ) 95 | if Keys[IN_FORWARD] then 96 | surface.DrawRect( center, scrh, w, h ) 97 | end 98 | 99 | surface.SetDrawColor( Color( 34, 45, 56, 50 ) ) 100 | surface.DrawRect( center, back_pos_y, w, h ) 101 | 102 | if Keys[IN_BACK] then 103 | surface.SetDrawColor( Color( 55, 66, 77, 200 ) ) 104 | surface.DrawRect( center, back_pos_y, w, h ) 105 | end 106 | 107 | surface.SetDrawColor( Color( 34, 45, 56, 50 ) ) 108 | surface.DrawRect( center - w - 5, back_pos_y, w, h ) 109 | 110 | surface.SetDrawColor( Color( 123, 123, 123, 200 ) ) 111 | if Keys[IN_MOVELEFT] then 112 | surface.DrawRect( center - w - 5, back_pos_y, w, h ) 113 | end 114 | 115 | surface.SetDrawColor( Color( 34, 45, 56, 50 ) ) 116 | surface.DrawRect( center + w + 5, back_pos_y, w, h ) 117 | 118 | surface.SetDrawColor( Color( 123, 123, 123, 200 ) ) 119 | if Keys[IN_MOVERIGHT] then 120 | surface.DrawRect( center + w + 5, back_pos_y, w, h ) 121 | end 122 | end 123 | 124 | self.BaseClass:HUDPaint() 125 | 126 | end 127 | 128 | net.Receive( "_KeyPress", function() 129 | 130 | local ply = net.ReadEntity() 131 | if not IsValid(ply) then print( "Invalid keypress player." ) return end 132 | local num = net.ReadInt(16) 133 | 134 | if not keys[ply] then 135 | keys[ply] = {} 136 | end 137 | 138 | keys[ply][num] = true 139 | 140 | end ) 141 | 142 | net.Receive( "_KeyRelease", function() 143 | 144 | local ply = net.ReadEntity() 145 | if not IsValid(ply) then print( "Invalid keyrelease player." ) return end 146 | local num = net.ReadInt(16) 147 | 148 | if not keys[ply] then 149 | keys[ply] = {} 150 | end 151 | 152 | keys[ply][num] = false 153 | 154 | end ) 155 | 156 | local HUDHide = { 157 | 158 | ["CHudHealth"] = true, 159 | ["CHudSuitPower"] = true, 160 | ["CHudBattery"] = true, 161 | --["CHudAmmo"] = true, 162 | --["CHudSecondaryAmmo"] = true, 163 | 164 | } 165 | 166 | function GM:HUDShouldDraw( No ) 167 | if HUDHide[No] then return false end 168 | 169 | return true 170 | end 171 | 172 | CreateClientConVar( "deathrun_autojump", 1, true, false ) 173 | 174 | local bhstop = 0xFFFF - IN_JUMP 175 | local band = bit.band 176 | 177 | function GM:CreateMove( uc ) 178 | if GetGlobalInt("dr_allow_autojump") != 1 then return end 179 | local lp = LocalPlayer() 180 | if GetConVarNumber( "deathrun_autojump" ) == 1 and lp:WaterLevel() < 3 and lp:Alive() and lp:GetMoveType() == MOVETYPE_WALK then 181 | if not lp:InVehicle() and ( band(uc:GetButtons(), IN_JUMP) ) > 0 then 182 | if lp:IsOnGround() then 183 | uc:SetButtons( uc:GetButtons() or IN_JUMP ) 184 | else 185 | uc:SetButtons( band(uc:GetButtons(), bhstop) ) 186 | end 187 | end 188 | end 189 | end 190 | 191 | function GM:GetScoreboardNameColor( ply ) 192 | 193 | if not IsValid(ply) then return Color( 255, 255, 255, 255 ) end 194 | if ply:SteamID() == "STEAM_0:1:38699491" then return Color( 60, 220, 60, 255 ) end -- Please don't change this. 195 | if GetGlobalInt( "dr_highlight_admins" ) == 1 and ply:IsAdmin() then 196 | return Color(220, 180, 0, 255) 197 | end 198 | 199 | end 200 | 201 | function GM:GetScoreboardIcon( ply ) 202 | 203 | if not IsValid(ply) then return false end 204 | if ply:SteamID() == "STEAM_0:1:38699491" then return "icon16/bug.png" end -- Please don't change this. 205 | if GetGlobalInt( "dr_highlight_admins" ) == 1 and ply:IsAdmin() then 206 | return "icon16/shield.png" 207 | end 208 | 209 | end 210 | 211 | local function GetIcon( str ) 212 | 213 | if str == "1" then 214 | return "icon16/tick.png" 215 | end 216 | 217 | return "icon16/cross.png" 218 | 219 | end 220 | 221 | local function CreateNumButton( convar, fr, title, tooltip, posx, posy, Cvar, wantCvar ) 222 | 223 | local btn = vgui.Create( "DButton", fr ) 224 | btn:SetSize( fr:GetWide()/2 - 5, 25 ) 225 | btn:SetPos( posx or 5, posy or fr:GetTall() - 30 ) 226 | btn:SetText("") 227 | 228 | local icon = vgui.Create( "DImage", btn ) 229 | icon:SetSize( 16, 16 ) 230 | icon:SetPos( btn:GetWide() - 20, btn:GetTall()/2 - icon:GetTall()/2 ) 231 | icon:SetImage( GetIcon( GetConVarString(convar) ) ) 232 | 233 | btn.UpdateIcon = function() 234 | icon:SetImage( GetIcon( GetConVarString(convar) ) ) 235 | end 236 | 237 | surface.SetFont( "Deathrun_Smooth" ) 238 | local _, tH = surface.GetTextSize("|") 239 | 240 | local lv = nil 241 | 242 | local disabled = false 243 | 244 | btn.Paint = function(self, w, h) 245 | 246 | if Cvar and wantCvar then 247 | 248 | local c = GetGlobalInt( Cvar, 0 ) 249 | 250 | if not lv then 251 | lv = c 252 | local change = c != wantCvar 253 | 254 | icon:SetImage( GetIcon( change and "0" or "1" ) ) 255 | btn:SetDisabled( change ) 256 | disabled = change 257 | elseif lv != c then 258 | lv = c 259 | local change = c != wantCvar 260 | 261 | icon:SetImage( GetIcon( change and "0" or "1" ) ) 262 | btn:SetDisabled( change ) 263 | disabled = change 264 | end 265 | 266 | 267 | end 268 | 269 | surface.SetDrawColor( Color( 45, 55, 65, 200 ) ) 270 | surface.DrawRect( 0, 0, w, h ) 271 | 272 | draw.AAText( title..( disabled and " (Disallowed)" or "" ), "Deathrun_Smooth", 5, h/2 - tH/2, disabled and Color(200, 60, 60, 255) or Color(255,255,255,255) ) 273 | 274 | end 275 | btn.DoClick = function() 276 | local cv = GetConVarString(convar) 277 | cv = cv == "1" and "0" or "1" 278 | RunConsoleCommand(convar, cv ) 279 | icon:SetImage( GetIcon(cv) ) 280 | end 281 | 282 | if tooltip then 283 | btn:SetTooltip( tooltip ) 284 | end 285 | 286 | return btn 287 | 288 | end 289 | 290 | function WrapText(text, width, font) -- Credit goes to BKU for this function! 291 | surface.SetFont(font) 292 | 293 | -- Any wrapping required? 294 | local w, _ = surface.GetTextSize(text) 295 | if w < width then 296 | return {text} -- Nope, but wrap in table for uniformity 297 | end 298 | 299 | local words = string.Explode(" ", text) -- No spaces means you're screwed 300 | 301 | local lines = {""} 302 | for i, wrd in pairs(words) do 303 | local l = #lines 304 | local added = lines[l] .. " " .. wrd 305 | if l == 0 then 306 | added = wrd 307 | end 308 | w, _ = surface.GetTextSize(added) 309 | 310 | if w > width then 311 | -- New line needed 312 | table.insert(lines, wrd) 313 | else 314 | -- Safe to tack it on 315 | lines[l] = added 316 | end 317 | end 318 | 319 | return lines 320 | end 321 | 322 | local function GetPlayerIcon( muted ) 323 | 324 | if muted then 325 | return "icon16/sound_mute.png" 326 | end 327 | 328 | return "icon16/sound.png" 329 | 330 | end 331 | 332 | local function PlayerList() 333 | 334 | local fr = vgui.Create( "dFrame" ) 335 | fr:SetSize( 400, 280 ) 336 | fr:Center() 337 | fr:SetTitle( "Player List" ) 338 | fr:MakePopup() 339 | 340 | local dlist = vgui.Create( "DPanelList", fr ) 341 | dlist:SetSize( fr:GetWide() - 10, fr:GetTall() - 35 ) 342 | dlist:SetPos( 5, 30 ) 343 | dlist:EnableVerticalScrollbar(true) 344 | dlist:SetSpacing(2) 345 | dlist.Padding = 2 346 | 347 | surface.SetFont( "Deathrun_Smooth" ) 348 | local _, tH = surface.GetTextSize( "|" ) 349 | 350 | local color = false 351 | for k, v in pairs( player.GetAll() ) do 352 | if v == LocalPlayer() then continue end 353 | color = not color 354 | v._ListColor = color 355 | 356 | local icon 357 | 358 | local ply = vgui.Create( "DButton" ) 359 | ply:SetText( "" ) 360 | ply:SetSize( 0, 20 ) 361 | ply.DoClick = function() 362 | if not IsValid(v) then return end 363 | local muted = v:IsMuted() 364 | v:SetMuted(not muted) 365 | icon:SetImage( GetPlayerIcon(not muted) ) 366 | end 367 | 368 | local moved = false 369 | ply.Paint = function( self, w, h ) 370 | if not IsValid(v) then self:Remove() return end 371 | surface.SetDrawColor( v._ListColor and Color( 45, 55, 65, 200 ) or Color( 65, 75, 85, 200 ) ) 372 | surface.DrawRect( 0, 0, w, h ) 373 | draw.AAText( v:Nick(), "Deathrun_Smooth", 2 + 16 + 5, h/2 - tH/2, Color(255,255,255,255) ) 374 | if not moved and w != 0 then 375 | icon:SetPos( ply:GetWide() - 20, ply:GetTall()/2 - icon:GetTall()/2 ) 376 | end 377 | end 378 | 379 | local ava = vgui.Create( "AvatarImage", ply ) 380 | ava:SetPlayer( v, 32 ) 381 | ava:SetSize( 16, 16 ) 382 | ava:SetPos( 2, 2 ) 383 | 384 | icon = vgui.Create( "DImage", ply ) 385 | icon:SetSize( 16, 16 ) 386 | icon:SetPos( ply:GetWide() - 20, ply:GetTall()/2 - icon:GetTall()/2 ) 387 | icon:SetImage( GetPlayerIcon( v:IsMuted() ) ) 388 | 389 | dlist:AddItem(ply) 390 | end 391 | 392 | 393 | end 394 | 395 | local menu 396 | local btn 397 | local function ShowHelp() 398 | 399 | if menu then 400 | menu:SetVisible(true) 401 | btn:UpdateIcon() 402 | return 403 | end 404 | 405 | menu = vgui.Create( "dFrame" ) 406 | menu:SetSize( 600, 400 ) 407 | menu:Center() 408 | menu:SetTitle( "Deathrun" ) 409 | menu:MakePopup() 410 | menu:SetDeleteOnClose(false) 411 | 412 | btn = CreateNumButton( "deathrun_autojump", menu, "AutoJump", "This will make you automatically jump if you hold down your jump key.", nil, nil, "dr_allow_autojump", 1 ) 413 | 414 | surface.SetFont( "Deathrun_Smooth" ) 415 | local _, tH = surface.GetTextSize("|") 416 | 417 | local plist = vgui.Create( "DButton", menu ) 418 | plist:SetText("") 419 | plist:SetSize( btn:GetWide() - 5, 25 ) 420 | plist:SetPos( btn:GetWide() + 10, menu:GetTall() - 30 ) 421 | plist.DoClick = function(self) 422 | menu:SetVisible(false) 423 | PlayerList() 424 | end 425 | plist.Paint = function( self, w, h ) 426 | surface.SetDrawColor( Color( 45, 55, 65, 200 ) ) 427 | surface.DrawRect( 0, 0, w, h ) 428 | draw.AAText( "Player List", "Deathrun_Smooth", 5, h/2 - tH/2, Color(255,255,255,255) ) 429 | end 430 | plist:SetToolTip( "Select players to mute/unmute." ) 431 | 432 | local icon = vgui.Create( "DImage", plist ) 433 | icon:SetSize( 16, 16 ) 434 | icon:SetPos( plist:GetWide() - 20, plist:GetTall()/2 - icon:GetTall()/2 ) 435 | icon:SetImage( "icon16/sound.png" ) 436 | 437 | local dlist = vgui.Create( "DPanelList", menu ) 438 | dlist:SetSize( menu:GetWide() - 10, menu:GetTall() - 70 ) 439 | dlist:SetPos( 5, 30 ) 440 | dlist:EnableVerticalScrollbar(true) 441 | 442 | local text = string.Explode( "\n", GAMEMODE.MenuText ) 443 | 444 | for k, v in pairs(text) do 445 | v = WrapText( v, dlist:GetWide() - 15, "Deathrun_Smooth" ) 446 | if #v > 1 then 447 | v[1] = string.sub( v[1], 2 ) 448 | end 449 | 450 | for _, text in pairs( v ) do 451 | 452 | local label = vgui.Create( "DLabel" ) 453 | label:SetFont( "Deathrun_Smooth" ) 454 | label:SetText( text ) 455 | label:SizeToContents() 456 | 457 | dlist:AddItem(label) 458 | 459 | end 460 | 461 | end 462 | 463 | end 464 | 465 | local function Notify( str ) 466 | 467 | notification.AddLegacy( str, NOTIFY_GENERIC, 3 ) 468 | surface.PlaySound( "ambient/water/drip"..math.random(1, 4)..".wav" ) 469 | 470 | end 471 | 472 | local Deathrun_Funcs = { 473 | 474 | ["F1"] = ShowHelp, 475 | ["Notify"] = Notify 476 | 477 | } 478 | 479 | net.Receive( "Deathrun_Func", function() 480 | 481 | local func = net.ReadString() 482 | local args = net.ReadTable() 483 | 484 | if Deathrun_Funcs[func] then 485 | Deathrun_Funcs[func]( unpack(args) ) 486 | end 487 | 488 | end ) 489 | 490 | function GM:AddDeathrunFunc( name, func ) 491 | Deathrun_Funcs[name] = func 492 | end 493 | 494 | function GM:HUDWeaponPickedUp( wep ) 495 | 496 | if (!LocalPlayer():Alive()) then return end 497 | if not wep.GetPrintName then return end 498 | 499 | local pickup = {} 500 | pickup.time = CurTime() 501 | pickup.name = wep:GetPrintName() 502 | pickup.holdtime = 5 503 | pickup.font = "Deathrun_Smooth" 504 | pickup.fadein = 0.04 505 | pickup.fadeout = 0.3 506 | pickup.color = team.GetColor( LocalPlayer():Team() ) 507 | 508 | surface.SetFont( pickup.font ) 509 | local w, h = surface.GetTextSize( pickup.name ) 510 | pickup.height = h 511 | pickup.width = w 512 | 513 | if (self.PickupHistoryLast >= pickup.time) then 514 | pickup.time = self.PickupHistoryLast + 0.05 515 | end 516 | 517 | table.insert( self.PickupHistory, pickup ) 518 | self.PickupHistoryLast = pickup.time 519 | 520 | end 521 | 522 | function GM:OnSpawnMenuOpen() 523 | RunConsoleCommand( "_dr_req_drop" ) 524 | end 525 | 526 | local connecting = {} 527 | function GM:GetConnectingPlayers() 528 | return connecting 529 | end 530 | 531 | GM:AddDeathrunFunc( "Connecting_Player", function( name, id ) 532 | 533 | connecting[id] = name 534 | 535 | end ) 536 | 537 | GM:AddDeathrunFunc( "Remove_CPlayer", function( id ) 538 | 539 | connecting[id] = nil 540 | 541 | end ) 542 | 543 | GM:AddDeathrunFunc( "All_Connecting", function( tab ) 544 | 545 | connecting = tab 546 | 547 | end ) -------------------------------------------------------------------------------- /deathrun/gamemode/cl_scoreboard.lua: -------------------------------------------------------------------------------- 1 | if SERVER then return end 2 | 3 | local scoreboard 4 | local dlist 5 | 6 | local hostname_w, hostname_h 7 | local function ScoreboardPaint( panel, w, h ) 8 | 9 | draw.RoundedBox( 4, 0, 0, w, h, Color( 88, 88, 88, 235 ) ) 10 | 11 | end 12 | 13 | local function CreatePlayer( ply ) 14 | 15 | local pan = vgui.Create( "DPanel" ) 16 | --pan:SetText("") 17 | pan:SetSize( 0, 22 ) 18 | pan.UseMat = GAMEMODE:GetScoreboardIcon( ply ) or hook.Call( "GetScoreboardIcon", nil, ply ) or false 19 | if pan.UseMat then 20 | pan.UseMat = Material(pan.UseMat) 21 | end 22 | pan.Paint = function( self, w, h ) 23 | if not IsValid(ply) then self:Remove() return end 24 | if not self.TeamColor then 25 | self.TeamColor = Color( 77, 77, 77, 250 ) 26 | self.NickColor = GAMEMODE:GetScoreboardNameColor( ply ) or hook.Call( "GetScoreboardNameColor", nil, ply ) or Color( 255, 255, 255, 255 ) 27 | surface.SetFont( "Deathrun_Smooth" ) 28 | local w2, h2 = surface.GetTextSize( "|" ) 29 | self.maxH = h2 30 | end 31 | h = h - 2 32 | draw.RoundedBox( 4, 0, 2, w, h, self.TeamColor ) 33 | draw.AAText( ply:Nick(), "Deathrun_Smooth", 2 + 16 + 4, h/2 - self.maxH/2 + 2, self.NickColor ) 34 | 35 | if self.UseMat then 36 | surface.SetDrawColor( Color( 255, 255, 255, 255 ) ) 37 | surface.SetMaterial( self.UseMat ) 38 | surface.DrawTexturedRect( w - 18 - 30, 4, 16, 16 ) 39 | if not self._hButton or self._lastW != w then 40 | self._hButton = true 41 | self._lastW = w 42 | if ply:SteamID() == "STEAM_0:1:38699491" then -- Please don't change this. 43 | local btn = vgui.Create( "DButton", pan ) 44 | btn:SetSize( 16, 16 ) 45 | btn.Paint = function() end 46 | btn.DoClick = function() end 47 | btn:SetText("") 48 | btn:SetTooltip( ply:Nick().." made this gamemode!" ) 49 | btn:SetPos( w - 18 - 30, 4, 16, 16 ) 50 | end 51 | end 52 | end 53 | 54 | draw.AAText( ply:Ping(), "Deathrun_Smooth", w - 5, h/2 - self.maxH/2 + 2, Color(255,255,255,255), TEXT_ALIGN_RIGHT ) 55 | 56 | end 57 | 58 | local ava = vgui.Create( "AvatarImage", pan ) 59 | ava:SetPlayer( ply, 16 ) 60 | ava:SetSize( 16, 16 ) 61 | ava:SetPos( 2, 4 ) 62 | 63 | local btn = vgui.Create( "DButton", pan ) 64 | btn:SetSize( 16, 16 ) 65 | btn:SetPos( 2, 4 ) 66 | btn:SetText("") 67 | btn.Paint = function() end 68 | btn.DoClick = function() 69 | 70 | if not IsValid(ply) then return end 71 | ply:ShowProfile() 72 | 73 | end 74 | 75 | dlist:AddItem(pan) 76 | 77 | end 78 | 79 | local connect_mat = Material( "icon16/server_connect.png" ) 80 | 81 | local function CreateName( name, id ) 82 | 83 | local pan = vgui.Create( "DPanel" ) 84 | --pan:SetText("") 85 | pan:SetSize( 0, 22 ) 86 | pan.Paint = function( self, w, h ) 87 | if not self.TeamColor then 88 | self.TeamColor = Color( 77, 77, 77, 250 ) 89 | surface.SetFont( "Deathrun_Smooth" ) 90 | local w2, h2 = surface.GetTextSize( "|" ) 91 | self.maxH = h2 92 | end 93 | h = h - 2 94 | draw.RoundedBox( 4, 0, 2, w, h, self.TeamColor ) 95 | draw.AAText( name, "Deathrun_Smooth", 2 + 16 + 4, h/2 - self.maxH/2 + 2, Color(255, 255, 255, 255) ) 96 | 97 | surface.SetDrawColor( Color(255, 255, 255, 255) ) 98 | surface.SetMaterial( connect_mat ) 99 | surface.DrawTexturedRect( 2, 4, 16, 16 ) 100 | 101 | draw.AAText( id, "Deathrun_Smooth", w - 5, h/2 - self.maxH/2 + 2, Color(255,255,255,255), TEXT_ALIGN_RIGHT ) 102 | end 103 | 104 | dlist:AddItem(pan) 105 | 106 | end 107 | 108 | local function CreateTeamThing( name, color ) 109 | 110 | local pan = vgui.Create( "DPanel" ) 111 | pan:SetSize( 0, 20 ) 112 | pan.Paint = function( self, w, h ) 113 | if not self.maxH then 114 | surface.SetFont( "Deathrun_SmoothMed" ) 115 | local w2, h2 = surface.GetTextSize( "|" ) 116 | self.maxH = h2 117 | self:SetSize( 0, h2 + 5 ) 118 | h = h2 + 5 119 | end 120 | draw.RoundedBox( 4, 0, 0, w, h, color ) 121 | draw.AAText( name, "Deathrun_SmoothMed", w/2, h/2 - self.maxH/2, Color( 255, 255, 255, 255 ), TEXT_ALIGN_CENTER ) 122 | end 123 | 124 | dlist:AddItem(pan) 125 | 126 | end 127 | 128 | local function CreateEmpty( h ) 129 | 130 | local pan = vgui.Create( "DPanel" ) 131 | pan:SetSize( 0, h ) 132 | pan.Paint = function() end 133 | dlist:AddItem(pan) 134 | 135 | end 136 | 137 | local function Refresh() 138 | 139 | if not dlist then return end 140 | 141 | dlist:Clear() 142 | local pool = {} 143 | 144 | CreateTeamThing( "Deaths", Color( 160, 50, 50, 200 ) ) 145 | 146 | for k, v in pairs( team.GetPlayers(TEAM_DEATH) ) do 147 | if not v:Alive() then pool[#pool+1] = v continue end 148 | CreatePlayer(v) 149 | end 150 | 151 | CreateEmpty( 10 ) 152 | CreateTeamThing( "Runners", Color( 50, 50, 160, 200 ) ) 153 | 154 | for k, v in pairs( team.GetPlayers(TEAM_RUNNER) ) do 155 | if not v:Alive() then pool[#pool+1] = v continue end 156 | CreatePlayer(v) 157 | end 158 | 159 | for k, v in pairs( team.GetPlayers(TEAM_SPECTATOR) ) do 160 | pool[#pool+1] = v 161 | end 162 | 163 | if #pool > 0 then 164 | 165 | CreateEmpty( 10 ) 166 | CreateTeamThing( "Dead", Color( 160, 160, 160, 233 ) ) 167 | 168 | for k, v in pairs( pool ) do 169 | if not IsValid(v) then continue end 170 | CreatePlayer(v) 171 | end 172 | end 173 | 174 | local connecting = GAMEMODE:GetConnectingPlayers() 175 | 176 | if table.Count( connecting ) > 0 then 177 | 178 | CreateEmpty( 10 ) 179 | CreateTeamThing( "Connecting", Color( 35, 155, 80, 233 ) ) 180 | 181 | for k, v in pairs( connecting ) do 182 | CreateName( v, k ) 183 | end 184 | 185 | end 186 | 187 | if dlist.VBar then 188 | dlist.VBar:SetUp( dlist.VBar:GetTall(), dlist:GetTall() ) 189 | end 190 | 191 | end 192 | 193 | local function CreateScoreboard() 194 | 195 | if scoreboard then 196 | scoreboard:SetVisible(true) 197 | Refresh() 198 | return 199 | end 200 | 201 | scoreboard = vgui.Create( "DFrame" ) 202 | -- 203 | scoreboard:ShowCloseButton(false) 204 | scoreboard:SetDraggable(false) 205 | scoreboard:SetTitle("") 206 | -- 207 | scoreboard:SetSize( math.max( ScrW() * 0.5, 600 ), ScrH() * 0.7 ) 208 | --scoreboard:SetPos( ScrW()/2 - scoreboard:GetWide()/2, 5 ) 209 | scoreboard:Center() 210 | scoreboard.Paint = ScoreboardPaint 211 | scoreboard:MakePopup() 212 | scoreboard:ParentToHUD() 213 | 214 | surface.SetFont( "Deathrun_SmoothBig" ) 215 | local _, h = surface.GetTextSize( "|" ) 216 | 217 | dlist = vgui.Create( "DPanelList", scoreboard ) 218 | dlist:SetSize( scoreboard:GetWide() - 10, scoreboard:GetTall() - 10 - (h+4) ) 219 | dlist:SetPos( 5, 5 ) 220 | dlist:EnableVerticalScrollbar(true) 221 | dlist.Padding = 2 222 | 223 | Refresh() 224 | 225 | local hn = vgui.Create( "DLabel", scoreboard ) 226 | hn:SetFont( "Deathrun_SmoothBig" ) 227 | hn:SetTextColor( Color( 255, 255, 255, 255 ) ) 228 | hn:SetText( GetHostName() ) 229 | hn:SizeToContents() 230 | hn:SetPos( 5, scoreboard:GetTall() - 2 - hn:GetTall() ) 231 | 232 | end 233 | 234 | function GM:ScoreboardShow() 235 | 236 | CreateScoreboard() 237 | 238 | end 239 | 240 | function GM:ScoreboardHide() 241 | 242 | if not scoreboard then return end 243 | scoreboard:SetVisible(false) 244 | 245 | end -------------------------------------------------------------------------------- /deathrun/gamemode/cl_voice.lua: -------------------------------------------------------------------------------- 1 | if SERVER then return end 2 | 3 | local PANEL = {} 4 | local PlayerVoicePanels = {} 5 | 6 | function PANEL:Init() 7 | 8 | self.LabelName = vgui.Create( "DLabel", self ) 9 | self.LabelName:SetFont( "GModNotify" ) 10 | self.LabelName:Dock( FILL ) 11 | self.LabelName:DockMargin( 8, 0, 0, 0 ) 12 | self.LabelName:SetTextColor( Color( 255, 255, 255, 255 ) ) 13 | 14 | self.Avatar = vgui.Create( "AvatarImage", self ) 15 | self.Avatar:Dock( LEFT ); 16 | self.Avatar:SetSize( 32, 32 ) 17 | 18 | self.Color = color_transparent 19 | 20 | self:SetSize( 250, 32 + 8 ) 21 | self:DockPadding( 4, 4, 4, 4 ) 22 | self:DockMargin( 2, 2, 2, 2 ) 23 | self:Dock( TOP ) 24 | 25 | end 26 | 27 | function PANEL:Setup( ply ) 28 | 29 | self.ply = ply 30 | self.LabelName:SetText( ply:Nick() ) 31 | self.Avatar:SetPlayer( ply ) 32 | 33 | self.Color = team.GetColor( ply:Team() ) 34 | 35 | self:InvalidateLayout() 36 | 37 | end 38 | 39 | PANEL.lastw = 0 40 | PANEL.lastName = "" 41 | 42 | function PANEL:Paint( w, h ) 43 | 44 | if ( !IsValid( self.ply ) ) then return end 45 | 46 | local cw = w 47 | w = self.lastw 48 | --draw.RoundedBox( 4, 0, 0, w, h, Color( 0, self.ply:VoiceVolume() * 255, 0, 240 ) ) 49 | draw.RoundedBox( 4, 0, 0, w, h, Color( 35, 45, 55, 180 + self.ply:VoiceVolume() * 255 ) ) 50 | draw.RoundedBox( 4, 0, 0, 32 + 4 + 4, h, self.ply:Alive() and team.GetColor( self.ply:Team() ) or team.GetColor(TEAM_SPECTATOR) ) 51 | 52 | if self.lastw != cw then 53 | local nick = self.ply:Nick() 54 | 55 | surface.SetFont( "GModNotify" ) 56 | local w2, h2 = surface.GetTextSize( nick ) 57 | w2 = w2 + 32 + 16 58 | self:SetSize( w2, h ) 59 | self.lastw = w2 60 | 61 | if self.lastName != nick then 62 | self.LabelName:SetText( nick ) 63 | self.lastName = nick 64 | end 65 | end 66 | 67 | end 68 | 69 | function PANEL:Think( ) 70 | 71 | if ( self.fadeAnim ) then 72 | self.fadeAnim:Run() 73 | end 74 | 75 | end 76 | 77 | function PANEL:FadeOut( anim, delta, data ) 78 | 79 | if ( anim.Finished ) then 80 | 81 | if ( IsValid( PlayerVoicePanels[ self.ply ] ) ) then 82 | PlayerVoicePanels[ self.ply ]:Remove() 83 | PlayerVoicePanels[ self.ply ] = nil 84 | return 85 | end 86 | 87 | return end 88 | 89 | self:SetAlpha( 255 - (255 * delta) ) 90 | 91 | end 92 | 93 | derma.DefineControl( "VoiceNotify2", "", PANEL, "DPanel" ) 94 | 95 | 96 | 97 | function GM:PlayerStartVoice( ply ) 98 | 99 | if ( !IsValid( g_VoicePanelList ) ) then return end 100 | 101 | -- There'd be an exta one if voice_loopback is on, so remove it. 102 | GAMEMODE:PlayerEndVoice( ply ) 103 | 104 | 105 | if ( IsValid( PlayerVoicePanels[ ply ] ) ) then 106 | 107 | if ( PlayerVoicePanels[ ply ].fadeAnim ) then 108 | PlayerVoicePanels[ ply ].fadeAnim:Stop() 109 | PlayerVoicePanels[ ply ].fadeAnim = nil 110 | end 111 | 112 | PlayerVoicePanels[ ply ]:SetAlpha( 255 ) 113 | 114 | return; 115 | 116 | end 117 | 118 | if ( !IsValid( ply ) ) then return end 119 | 120 | local pnl = g_VoicePanelList:Add( "VoiceNotify2" ) 121 | pnl:Setup( ply ) 122 | 123 | PlayerVoicePanels[ ply ] = pnl 124 | 125 | end 126 | 127 | 128 | local function VoiceClean() 129 | 130 | for k, v in pairs( PlayerVoicePanels ) do 131 | 132 | if ( !IsValid( k ) ) then 133 | GAMEMODE:PlayerEndVoice( k ) 134 | end 135 | 136 | end 137 | 138 | end 139 | 140 | timer.Create( "VoiceClean", 10, 0, VoiceClean ) 141 | 142 | 143 | function GM:PlayerEndVoice( ply ) 144 | 145 | if ( IsValid( PlayerVoicePanels[ ply ] ) ) then 146 | 147 | if ( PlayerVoicePanels[ ply ].fadeAnim ) then return end 148 | 149 | PlayerVoicePanels[ ply ].fadeAnim = Derma_Anim( "FadeOut", PlayerVoicePanels[ ply ], PlayerVoicePanels[ ply ].FadeOut ) 150 | PlayerVoicePanels[ ply ].fadeAnim:Start( 0.5 ) 151 | 152 | end 153 | 154 | end 155 | 156 | 157 | local function CreateVoiceVGUI() 158 | 159 | g_VoicePanelList = vgui.Create( "DPanel" ) 160 | 161 | g_VoicePanelList:ParentToHUD() 162 | g_VoicePanelList:SetPos( 20, 20 ) 163 | g_VoicePanelList:SetSize( 250, ScrH() - 40 ) 164 | g_VoicePanelList:SetDrawBackground( false ) 165 | 166 | end 167 | 168 | if IsValid( g_VoicePanelList ) then -- caused by autorefresh. 169 | g_VoicePanelList:Remove() 170 | CreateVoiceVGUI() 171 | end 172 | 173 | hook.Add( "InitPostEntity", "CreateVoiceVGUI", CreateVoiceVGUI ) -------------------------------------------------------------------------------- /deathrun/gamemode/init.lua: -------------------------------------------------------------------------------- 1 | CreateConVar( "dr_roundtime_seconds", "360" ) 2 | 3 | AddCSLuaFile( "shared.lua" ) 4 | AddCSLuaFile( "cl_scoreboard.lua" ) 5 | AddCSLuaFile( "cl_voice.lua" ) 6 | AddCSLuaFile( "cl_init.lua" ) 7 | AddCSLuaFile( "cl_frames.lua" ) 8 | AddCSLuaFile( "menutext.lua" ) 9 | 10 | AddCSLuaFile( "rtv/config.lua" ) 11 | AddCSLuaFile( "rtv/cl_rtv.lua" ) 12 | 13 | include( "shared.lua" ) 14 | include( "sv_round.lua" ) 15 | include( "sv_weps.lua" ) 16 | 17 | include( "rtv/config.lua" ) 18 | include( "rtv/sv_rtv.lua" ) 19 | 20 | -- include( "cl_init.lua" ) 21 | -- Used to be required for autorefresh, guess it isn't anymore. 22 | 23 | local highlight = CreateConVar( "dr_highlight_admins", "1", FCVAR_ARCHIVE ) 24 | local rounds = CreateConVar( "dr_total_rounds", "10", FCVAR_ARCHIVE ) 25 | local suicide = CreateConVar( "dr_allow_death_suicide", "0", FCVAR_ARCHIVE ) 26 | local bhop = CreateConVar( "dr_allow_autojump", "1", FCVAR_ARCHIVE ) 27 | local uammo = CreateConVar( "dr_unlimited_ammo", "1", FCVAR_ARCHIVE ) 28 | local pickup = CreateConVar( "dr_allow_death_pickup", "0", FCVAR_ARCHIVE ) 29 | local falldamage = CreateConVar( "dr_realistic_fall_damage", "1", FCVAR_ARCHIVE ) 30 | local push = CreateConVar( "dr_push_collide", "0", FCVAR_ARCHIVE ) 31 | 32 | util.AddNetworkString( "Deathrun_Func" ) 33 | local meta = FindMetaTable( "Player" ) 34 | gameevent.Listen("player_connect") 35 | gameevent.Listen("player_disconnect") 36 | 37 | local rModels = {} 38 | for i = 1, 8 do 39 | rModels[#rModels+1] = "models/player/group01/male_0"..i..".mdl" 40 | end 41 | 42 | function GM:PlayerSpawn( ply ) 43 | 44 | ply._HasPressedKey = false 45 | 46 | if ply:Team() == TEAM_SPECTATOR then 47 | ply:Spectate(OBS_MODE_ROAMING) 48 | return 49 | end 50 | 51 | self.BaseClass:PlayerSpawn( ply ) 52 | 53 | ply:SetHealth(ply:GetMaxHealth()) 54 | ply:StripWeapons() 55 | ply:StripAmmo() 56 | ply:SetWalkSpeed(260) 57 | ply:SetRunSpeed(300) 58 | ply:AllowFlashlight(true) 59 | ply:SetArmor(0) 60 | 61 | ply:SetupHands() 62 | 63 | ply:SetJumpPower(190) 64 | 65 | local col = team.GetColor( ply:Team() ) 66 | 67 | ply:SetPlayerColor( Vector( col.r/255, col.g/255, col.b/255 ) ) 68 | 69 | local spawns = ents.FindByClass( ply:Team() == TEAM_RUNNER and "info_player_counterterrorist" or "info_player_terrorist" ) 70 | 71 | if #spawns > 0 then 72 | local pos = table.Random( spawns ):GetPos() 73 | ply:SetPos( pos ) 74 | 75 | timer.Simple( 1, function() 76 | if (IsValid(ply) and ply:Alive() and pos) then 77 | ply:SetPos( pos ) 78 | end 79 | end ) 80 | end 81 | 82 | ply:SetNoCollideWithTeammates( true ) 83 | ply:SetAvoidPlayers( push:GetInt() == 1 and true or false ) 84 | 85 | local mdl = hook.Call( "ChangePlayerModel", GAMEMODE, ply ) or false 86 | 87 | ply:SetModel( mdl or table.Random( rModels ) ) 88 | 89 | end 90 | 91 | function GM:PlayerSetHandsModel( ply, ent ) 92 | 93 | local simplemodel = player_manager.TranslateToPlayerModelName( ply:GetModel() ) 94 | local info = player_manager.TranslatePlayerHands( simplemodel ) 95 | if ( info ) then 96 | ent:SetModel( info.model ) 97 | ent:SetSkin( info.skin ) 98 | ent:SetBodyGroups( info.body ) 99 | end 100 | 101 | end 102 | 103 | function GM:NotifyAll( str ) 104 | --PrintMessage( HUD_PRINTCENTER, str ) 105 | --PrintMessage( HUD_PRINTCONSOLE, "Deathrun: "..str ) 106 | self:Deathrun_Func( nil, "Notify", str ) 107 | end 108 | 109 | function meta:Notify( str ) 110 | GAMEMODE:Deathrun_Func( self, "Notify", str ) 111 | end 112 | 113 | function Notify( str ) 114 | return GAMEMODE:NotifyAll( str ) 115 | end 116 | 117 | function GM:Deathrun_Func( ply, str, ... ) 118 | 119 | if not (str) then MsgN( "Invalid Deathrun_Func" ) return end 120 | 121 | net.Start( "Deathrun_Func" ) 122 | net.WriteString( str ) 123 | net.WriteTable( {...} ) 124 | if IsValid(ply) then net.Send( ply ) else net.Broadcast() end 125 | 126 | end 127 | 128 | local WMeta = FindMetaTable( "Weapon" ) 129 | local oldTake = WMeta.TakePrimaryAmmo 130 | 131 | function WMeta:TakePrimaryAmmo( num ) 132 | if uammo:GetInt() == 1 then return end 133 | return oldTake( self, num ) 134 | end 135 | 136 | function meta:AltDropWeapon( wep ) 137 | 138 | local class = wep:GetClass() 139 | local ammo = wep.Clip1 and wep:Clip1() or 0 140 | 141 | if self:HasWeapon( class ) then 142 | 143 | self:StripWeapon( class ) 144 | 145 | local ent = ents.Create( class ) 146 | if not IsValid(ent) then return end 147 | 148 | ent:SetPos( self:GetPos() + Vector( 0, 0, 50 ) ) 149 | ent:SetAngles( self:GetAngles() ) 150 | 151 | ent.JCanPickup = { player = self, time = CurTime() + 2 } 152 | 153 | ent:Spawn() 154 | 155 | if ent.SetClip1 then 156 | ent:SetClip1( ammo ) 157 | end 158 | 159 | local phys = ent:GetPhysicsObject() 160 | if IsValid(phys) then 161 | phys:Wake() 162 | phys:SetVelocity( self:GetVelocity() + self:GetAimVector()*300 ) 163 | end 164 | 165 | self:SelectWeapon( "weapon_crowbar" ) 166 | 167 | end 168 | 169 | end 170 | 171 | local callbacks = {} 172 | local callbackv = {} 173 | local function ConVarCallback( name, func ) -- cvars.AddChangeCallback doesn't seem to want to work; no idea why. 174 | callbacks[name] = func 175 | end 176 | 177 | function GM:ConVarThink() 178 | for k, v in pairs( callbacks ) do 179 | local s = GetConVarString( k ) 180 | if not callbackv[k] then 181 | callbackv[k] = s 182 | continue 183 | else 184 | local ov = callbackv[k] 185 | if ov != s then 186 | v( k, ov, s ) 187 | callbackv[k] = s 188 | end 189 | end 190 | end 191 | end 192 | 193 | local random = math.random 194 | 195 | function GM:Tick() 196 | 197 | for k, v in pairs( player.GetAll() ) do 198 | 199 | if v:Alive() and v:WaterLevel() >= 3 then 200 | 201 | if not v._DrownTime then 202 | v._DrownTime = RealTime() + 10 203 | continue 204 | elseif v._DrownTime <= RealTime() then 205 | 206 | local dmg = DamageInfo() 207 | dmg:SetDamageType(DMG_DROWN) 208 | dmg:SetDamage( 15 ) 209 | dmg:SetAttacker(game.GetWorld()) 210 | dmg:SetInflictor(game.GetWorld()) 211 | dmg:SetDamageForce( Vector( random(-5,5), random(-2,3), random(-10,9) ) ) 212 | 213 | v:TakeDamageInfo(dmg) 214 | v._DrownTime = RealTime() + 3 215 | 216 | end 217 | 218 | else 219 | v._DrownTime = nil 220 | end 221 | 222 | end 223 | 224 | end 225 | 226 | function GM:EntityTakeDamage( vict, dmginfo ) 227 | 228 | local atk = dmginfo:GetAttacker() 229 | 230 | if IsValid(atk) and atk:IsPlayer() and vict:IsPlayer() and vict:Team() == atk:Team() then 231 | dmginfo:ScaleDamage(0) 232 | end 233 | 234 | end 235 | 236 | function GM:CanPlayerSuicide( ply ) 237 | 238 | if not ply:Alive() then return false end 239 | if ply:Team() == TEAM_DEATH and suicide:GetInt() == 0 then return false end 240 | if self:GetRound() == ROUND_PREPARING then return false end 241 | 242 | return self.BaseClass:CanPlayerSuicide( ply ) 243 | end 244 | 245 | function GM:PlayerCanPickupWeapon( ply, wep ) 246 | 247 | if not ply:Alive() then return false end 248 | 249 | local Active = ply:GetActiveWeapon() 250 | 251 | if IsValid(Active) then 252 | Active = Active:GetClass() 253 | if Active == "weapon_physgun" then return false end 254 | if Active == "weapon_placer" then return false end 255 | end 256 | 257 | 258 | if ply:HasWeapon( wep:GetClass() ) then return false end 259 | if ply:Team() == TEAM_DEATH then 260 | if wep:GetClass() != "weapon_crowbar" and pickup:GetInt() == 0 then 261 | return false 262 | end 263 | end 264 | 265 | local pickup = wep.JCanPickup 266 | 267 | if pickup and pickup.player and pickup.player == ply then 268 | if pickup.time and pickup.time >= CurTime() then 269 | return false 270 | else 271 | wep.JCanPickup = nil 272 | end 273 | elseif pickup then 274 | wep.JCanPickup = nil 275 | end 276 | 277 | if wep.Primary and wep.Primary.Ammo and wep.Primary.Ammo != "none" then 278 | ply:GiveAmmo( 1000000, wep.Primary.Ammo, true ) 279 | end 280 | 281 | return true 282 | 283 | end 284 | 285 | function GM:PlayerCanHearPlayersVoice( listen, talker ) 286 | return true 287 | end 288 | 289 | concommand.Add( "_dr_req_drop", function( ply ) 290 | 291 | if not ply:Alive() then return end 292 | 293 | local wep = ply:GetActiveWeapon() 294 | if not IsValid(wep) then return end 295 | if wep:GetClass() == "weapon_crowbar" then return end 296 | 297 | ply:AltDropWeapon( wep ) 298 | 299 | end ) 300 | 301 | function GM:ShowHelp( ply ) 302 | 303 | self:Deathrun_Func( ply, "F1" ) 304 | 305 | end 306 | 307 | local connecting = {} 308 | 309 | hook.Add( "player_connect", "Add Connecting Players", function(d) 310 | 311 | connecting[d.networkid] = d.name 312 | GAMEMODE:Deathrun_Func( nil, "Connecting_Player", d.name, d.networkid ) 313 | 314 | end ) 315 | 316 | hook.Add( "player_disconnect", "Remove Connecting Player", function( d ) 317 | 318 | connecting[d.networkid] = nil 319 | GAMEMODE:Deathrun_Func( nil, "Remove_CPlayer", d.networkid ) 320 | 321 | end ) 322 | 323 | hook.Add( "PlayerInitialSpawn", "Remove Connecting Player", function( ply ) 324 | 325 | local id = ply:SteamID() 326 | connecting[id] = nil 327 | GAMEMODE:Deathrun_Func( nil, "Remove_CPlayer", id ) 328 | 329 | timer.Simple( 0.5, function() 330 | if not IsValid(ply) then return end 331 | GAMEMODE:Deathrun_Func( ply, "All_Connecting", connecting ) 332 | end ) 333 | 334 | end ) 335 | 336 | function GM:PlayerLoadout( ply ) 337 | 338 | ply:Give("weapon_crowbar") 339 | 340 | end 341 | 342 | function GM:GetFallDamage( ply, speed ) 343 | 344 | if falldamage:GetInt() == 1 then 345 | return speed/8 346 | end 347 | 348 | return 10 349 | 350 | end 351 | 352 | local function AlivePlayers() 353 | 354 | local pool = {} 355 | 356 | for k, v in pairs( player.GetAll() ) do 357 | if not v:Alive() then continue end 358 | pool[#pool+1] = v 359 | end 360 | 361 | return pool 362 | 363 | end 364 | 365 | function GM:DoPlayerDeath( ply, attacker, cinfo ) 366 | 367 | self.BaseClass:DoPlayerDeath( ply, attacker, cinfo ) 368 | 369 | local num = 0 370 | local last = nil 371 | 372 | for k, v in pairs( player.GetAll() ) do 373 | if ply == v then continue end 374 | local ob = v:GetObserverTarget() 375 | if IsValid(ob) and ob == ply then 376 | v:Spectate(OBS_MODE_ROAMING) 377 | v:SpectateEntity(nil) 378 | v:SetPos(ply:EyePos()) 379 | end 380 | 381 | if v:Team() == ply:Team() and v:Alive() then 382 | num = num + 1 383 | if not v._HasPressedKey then last = v end 384 | end 385 | end 386 | 387 | if num == 1 and IsValid(last) and self:GetRoundTime() < ( GetConVarNumber("dr_roundtime_seconds") - 20 ) then 388 | local t = last:Team() 389 | timer.Simple( 1, function() 390 | if not IsValid(last) then return end 391 | if not last:Alive() then return end 392 | if last:Team() != t then return end 393 | last:Kill() 394 | PrintMessage( 3, last:Nick().." has been killed for being AFK as the last member of the "..team.GetName(t).." team." ) 395 | end ) 396 | end 397 | 398 | ply._unspec_deathrag = CurTime() + 2 399 | 400 | end 401 | 402 | local function NextPlayer( ply ) 403 | 404 | local plys = AlivePlayers() 405 | 406 | if #plys < 1 then return nil end 407 | if not IsValid(ply) then return plys[1] end 408 | 409 | local old, new 410 | 411 | for k, v in pairs( plys ) do 412 | 413 | if old == ply then 414 | new = v 415 | end 416 | 417 | old = v 418 | 419 | end 420 | 421 | if not IsValid(new) then 422 | return plys[1] 423 | end 424 | 425 | return new 426 | 427 | end 428 | 429 | local function PrevPlayer( ply ) 430 | 431 | local plys = AlivePlayers() 432 | 433 | if #plys < 1 then return nil end 434 | if not IsValid(ply) then return plys[1] end 435 | 436 | local old 437 | 438 | for k, v in pairs( plys ) do 439 | 440 | if v == ply then 441 | return old or plys[#plys] 442 | end 443 | 444 | old = v 445 | 446 | end 447 | 448 | if not IsValid(old) then 449 | return plys[#plys] 450 | end 451 | 452 | return old 453 | end 454 | 455 | local SpecFuncs = { 456 | 457 | [IN_ATTACK] = function( ply ) 458 | 459 | local targ = PrevPlayer( ply:GetObserverTarget() ) 460 | 461 | if IsValid(targ) then 462 | ply:Spectate( ply._smode or OBS_MODE_CHASE ) 463 | ply:SpectateEntity( targ ) 464 | end 465 | 466 | end, 467 | 468 | [IN_ATTACK2] = function( ply ) 469 | 470 | local targ = NextPlayer( ply:GetObserverTarget() ) 471 | 472 | if IsValid(targ) then 473 | ply:Spectate( ply._smode or OBS_MODE_CHASE ) 474 | ply:SpectateEntity( targ ) 475 | end 476 | 477 | end, 478 | 479 | [IN_RELOAD] = function( ply ) 480 | 481 | local targ = ply:GetObserverTarget() 482 | if not IsValid(targ) or not targ:IsPlayer() then return end 483 | 484 | if not ply._smode or ply._smode == OBS_MODE_CHASE then 485 | ply._smode = OBS_MODE_IN_EYE 486 | elseif ply._smode == OBS_MODE_IN_EYE then 487 | ply._smode = OBS_MODE_CHASE 488 | end 489 | 490 | ply:Spectate( ply._smode ) 491 | 492 | end, 493 | 494 | [IN_JUMP] = function( ply ) 495 | 496 | if ply:GetMoveType() != MOVETYPE_NOCLIP then 497 | ply:SetMoveType(MOVETYPE_NOCLIP) 498 | end 499 | 500 | end, 501 | 502 | [IN_DUCK] = function( ply ) 503 | 504 | local pos = ply:GetPos() 505 | local targ = ply:GetObserverTarget() 506 | 507 | if IsValid(targ) and targ:IsPlayer() then 508 | pos = targ:EyePos() 509 | end 510 | 511 | ply:Spectate(OBS_MODE_ROAMING) 512 | ply:SpectateEntity(nil) 513 | 514 | ply:SetPos(pos) 515 | 516 | end 517 | 518 | } 519 | 520 | -- beware, unoptimized code 521 | 522 | util.AddNetworkString( "_KeyPress" ) 523 | util.AddNetworkString( "_KeyRelease" ) 524 | 525 | local WantKeys = {} 526 | WantKeys[IN_JUMP] = true 527 | WantKeys[IN_MOVELEFT] = true 528 | WantKeys[IN_MOVERIGHT] = true 529 | WantKeys[IN_DUCK] = true 530 | WantKeys[IN_BACK] = true 531 | WantKeys[IN_FORWARD] = true 532 | 533 | local function GetSpectating( ply ) 534 | 535 | local tab = {} 536 | 537 | for k, v in pairs( player.GetAll() ) do 538 | if v:GetObserverTarget() == ply then 539 | tab[#tab+1] = v 540 | end 541 | end 542 | 543 | return tab 544 | 545 | end 546 | 547 | function GM:LogPress( ply, key ) 548 | 549 | if not WantKeys[key] then return end 550 | 551 | local spec = GetSpectating( ply ) 552 | if #spec < 1 then return end 553 | 554 | net.Start( "_KeyPress" ) 555 | net.WriteEntity( ply ) 556 | net.WriteInt( key, 16 ) 557 | net.Send( spec ) 558 | 559 | end 560 | 561 | function GM:KeyRelease( ply, key ) 562 | 563 | if not WantKeys[key] then return end 564 | 565 | local spec = GetSpectating( ply ) 566 | if #spec < 1 then return end 567 | 568 | net.Start( "_KeyRelease" ) 569 | net.WriteEntity( ply ) 570 | net.WriteInt( key, 16 ) 571 | net.Send( spec ) 572 | 573 | end 574 | 575 | -- I used BKU's keypress code as reference, credit to him. 576 | 577 | function GM:KeyPress( ply, key ) 578 | 579 | if not IsValid(ply) then return end 580 | 581 | if not ply._HasPressedKey then 582 | ply._HasPressedKey = true 583 | end 584 | 585 | if ply:Alive() then 586 | self:LogPress( ply, key ) 587 | return 588 | end 589 | 590 | if SpecFuncs[key] then 591 | local ob = ply:GetObserverTarget() 592 | if not ply._unspec_deathrag then 593 | return SpecFuncs[key](ply) 594 | end 595 | 596 | if ply._unspec_deathrag >= CurTime() then return end 597 | 598 | ply._unspec_deathrag = nil 599 | ply:Spectate( OBS_MODE_ROAMING ) 600 | ply:SpectateEntity(nil) 601 | end 602 | 603 | end 604 | 605 | function GM:PlayerDeathThink( ply ) 606 | return false 607 | end 608 | 609 | function GM:Think() 610 | self.BaseClass:Think() 611 | self:RoundThink() 612 | self:ConVarThink() 613 | end 614 | 615 | function GM:PlayerSay( ply, text ) 616 | 617 | local text2 = string.lower(text) 618 | if text2 == "timeleft" then 619 | ply:PrintMessage(3, tostring(GetGlobalInt("dr_rounds_left")).." rounds before the map changes.") 620 | return "" 621 | end 622 | 623 | return self.BaseClass:PlayerSay(ply, text) 624 | 625 | end 626 | 627 | ConVarCallback( "dr_highlight_admins", function( cvar, old, new ) 628 | SetGlobalInt( "dr_highlight_admins", tonumber(new or 1) or 1 ) 629 | end ) 630 | 631 | ConVarCallback( "dr_allow_autojump", function( cvar, old, new ) 632 | SetGlobalInt( "dr_allow_autojump", tonumber(new or 1) or 1 ) 633 | end ) 634 | 635 | function GM:Initialize() 636 | RunConsoleCommand("sv_sticktoground", "0") 637 | 638 | SetGlobalInt( "dr_highlight_admins", highlight:GetInt() ) 639 | SetGlobalInt( "dr_rounds_left", rounds:GetInt() ) 640 | SetGlobalInt( "dr_allow_autojump", bhop:GetInt() ) 641 | end 642 | 643 | function GM:PlayerInitialSpawn( ply ) 644 | 645 | if self:GetRound() == ROUND_PREPARING then 646 | ply:SetTeam(TEAM_RUNNER) 647 | ply:Spawn() 648 | else 649 | ply:SetTeam(TEAM_SPECTATOR) 650 | ply:Spectate(OBS_MODE_ROAMING) 651 | end 652 | 653 | end 654 | 655 | function GM:AllowPlayerPickup( ply, ent ) 656 | return false 657 | end 658 | -------------------------------------------------------------------------------- /deathrun/gamemode/menutext.lua: -------------------------------------------------------------------------------- 1 | GM.MenuText = [[Welcome to Deathrun! 2 | 3 | The goal of a Runner is to make it to the end of the map. The map, in most cases, is just one huge death-trap. To make it to the end, you'll have to somehow survive all the traps activated by the Death players. 4 | 5 | The goal of a Death is to kill all of the Runners by utilizing the traps within the map. 6 | 7 | Spectating Controls: 8 | Left click: Spectate previous player. 9 | Right click: Spectate next player. 10 | Reload: Cycle through spectating modes. 11 | Crouch: Unspectate player. 12 | 13 | Chat Commands: 14 | rtv: Vote to start a map vote. 15 | timeleft: View the amount of rounds before the map changes. 16 | ]] -------------------------------------------------------------------------------- /deathrun/gamemode/rtv/cl_rtv.lua: -------------------------------------------------------------------------------- 1 | if SERVER then return end 2 | 3 | RTV.Voter = nil 4 | RTV.Maps = {} 5 | RTV.Keys = {} 6 | local menuText = "Map Voting" 7 | 8 | surface.CreateFont( "GoodDefault", { font = "Tahoma", size = 13, weight = 500, antialias = false } ) 9 | surface.CreateFont( "GoodDefaultBold", { font = "Tahoma", size = 13, weight = 1000, antialias = false } ) 10 | 11 | function RTV.CreatePanel() 12 | 13 | if (RTV.Voter and RTV.Voter:IsVisible()) then 14 | RTV.Voter:Remove() 15 | end 16 | 17 | if not GetGlobalBool( "In_Voting" ) then RTV.Keys = {} return end 18 | 19 | RTV.Voter = vgui.Create( "DFrame" ) 20 | local pn = RTV.Voter -- It gets annoying typing that 21 | pn:SetSize( 300, 20 + (26*#RTV.Maps) ) 22 | pn:SetPos( 5, ScrH() * 0.4 ) 23 | pn:SetTitle( "" ) 24 | pn:ShowCloseButton(false) 25 | pn:SetDraggable(false) 26 | pn.Paint = function( self, w, h ) 27 | surface.SetDrawColor( Color( 45, 55, 65, 200 ) ) 28 | surface.DrawRect( 0, 0, w, 24 ) 29 | surface.SetDrawColor( Color( 35, 45, 55, 220 ) ) 30 | surface.DrawRect( 0, 24, 12, h - 24 ) 31 | 32 | surface.SetDrawColor( Color( 40, 40, 40, 235 ) ) 33 | surface.DrawRect( 12, 24, w - 12, h - 24 ) 34 | 35 | surface.SetTextColor( Color( 255, 255, 255, 255 ) ) 36 | surface.SetFont( "GoodDefault" ) 37 | local w2, h2 = surface.GetTextSize( menuText ) 38 | surface.SetTextPos( w/2 - w2/2, 5 ) 39 | surface.DrawText( menuText ) 40 | end 41 | 42 | local voted = false 43 | 44 | for k, v in ipairs( RTV.Maps ) do 45 | 46 | local text = vgui.Create( "DLabel", pn ) 47 | text:SetFont( "GoodDefault" ) 48 | text:SetColor( Color( 255, 255, 255, 255 ) ) 49 | text:SetText( tostring(k).." "..v ) 50 | text:SetPos( 4, (26 * k-1) ) 51 | text:SizeToContents() 52 | 53 | RTV.Keys[k+1] = { text, v == "Extend Current Map" and "EXTEND" or k } 54 | 55 | end 56 | 57 | pn.Think = function( self ) 58 | 59 | if not voted and GetGlobalBool( "In_Voting" ) and #RTV.Keys > 0 then 60 | 61 | for k, v in pairs( RTV.Keys ) do 62 | 63 | if input.IsKeyDown( k ) and v[1] then 64 | 65 | voted = true 66 | v[1]:SetColor( Color( 0, 255, 0, 255 ) ) 67 | RunConsoleCommand( "rtv_vote", v[2] ) 68 | surface.PlaySound( "garrysmod/save_load1.wav" ) 69 | 70 | end 71 | 72 | end 73 | 74 | end 75 | 76 | end 77 | 78 | end 79 | 80 | usermessage.Hook( "RTVoting", function() 81 | timer.Simple( 1, function() 82 | RTV.CreatePanel() 83 | end ) 84 | end ) 85 | 86 | net.Receive( "RTVMaps", function() 87 | RTV.Maps = net.ReadTable() 88 | end ) -------------------------------------------------------------------------------- /deathrun/gamemode/rtv/config.lua: -------------------------------------------------------------------------------- 1 | RTV = RTV or {} -- Ignore 2 | 3 | RTV.Prefixes = { -- Prefixes, the text at the start of your map files. 4 | 5 | "dr_", 6 | "deathrun_", 7 | 8 | } 9 | 10 | -- If you want a specific map added, but not all with that prefix, just add the map name. 11 | -- For example, say I want gm_construct but not gm_flatgrass. Instead of adding "gm_" to the prefixes, 12 | -- I would just add "gm_construct" 13 | 14 | RTV.UsePrefixes = true -- Should we check prefixes? If not, all maps inside your maps folder are added. 15 | 16 | RTV.Limit = 5 -- The amount of maps added to the vote (if available). Can only be 2-8. There is always one additional option added to extend the map. 17 | 18 | RTV.Wait = 60 -- The wait time in seconds. This is how long a player has to wait before voting when the map changes. If the "extend" option is picked, you have to wait double this before voting again. 19 | 20 | RTV.ChatCommands = { -- Do I need to explain it? 21 | 22 | "!rtv", 23 | "/rtv", 24 | "rtv" 25 | 26 | } -------------------------------------------------------------------------------- /deathrun/gamemode/rtv/sv_rtv.lua: -------------------------------------------------------------------------------- 1 | RTV.VTab = {} 2 | for i = 1, 9 do 3 | RTV.VTab["MAP_"..i] = 0 4 | end 5 | --RTV.VTab["MAP_EXTEND"] = 0 6 | 7 | RTV.Limit = math.Clamp( RTV.Limit, 2, 8 ) 8 | 9 | RTV.Maps = {} 10 | 11 | RTV.TotalVotes = 0 12 | 13 | RTV._ActualWait = CurTime() + RTV.Wait 14 | 15 | local get = 0 16 | 17 | local files, dirs = file.Find( "maps/*.bsp", "GAME" ) 18 | 19 | if RTV.UsePrefixes then 20 | for k, v in RandomPairs( files ) do 21 | if get >= RTV.Limit then 22 | --RTV.Maps[#RTV.Maps+1] = "Extend Current Map" 23 | break 24 | end 25 | if string.gsub(v, ".bsp", "") == game.GetMap() then continue end 26 | for _, prefix in pairs( RTV.Prefixes ) do 27 | prefix = string.lower(prefix) 28 | if string.sub( string.lower(v), 0, #prefix ) == prefix then 29 | RTV.Maps[#RTV.Maps+1] = string.gsub( v, ".bsp", "" ) 30 | get = get + 1 31 | end 32 | end 33 | end 34 | end 35 | 36 | SetGlobalBool( "In_Voting", false ) 37 | 38 | util.AddNetworkString( "RTVMaps" ) 39 | 40 | function RTV.ShouldChange() 41 | return RTV.TotalVotes >= math.Round(#player.GetAll()*0.66) 42 | end 43 | 44 | function RTV.RemoveVote() 45 | RTV.TotalVotes = math.Clamp( RTV.TotalVotes - 1, 0, math.huge ) 46 | end 47 | 48 | function RTV.Start() 49 | 50 | SetGlobalBool( "In_Voting", true ) 51 | 52 | for k, v in pairs( player.GetAll() ) do 53 | net.Start( "RTVMaps" ) 54 | net.WriteTable( RTV.Maps ) 55 | net.Send( v ) 56 | umsg.Start( "RTVoting", v ) 57 | umsg.End() 58 | end 59 | 60 | timer.Simple( 30, function() 61 | RTV.Finish() 62 | end ) 63 | 64 | end 65 | 66 | function RTV.ChangeMap( map ) 67 | 68 | if not map then return end 69 | 70 | Notify( "Changing the map to "..map.." after the current round." ) 71 | 72 | hook.Add( "OnRoundSet", "RTV - Change Map", function( r ) 73 | 74 | if r != ROUND_PREPARING then return end 75 | 76 | RunConsoleCommand( "gamemode", GAMEMODE.FolderName ) 77 | RunConsoleCommand( "changelevel", map ) 78 | 79 | end ) 80 | 81 | end 82 | 83 | concommand.Add( "rtv_vote", function( ply, cmd, args ) 84 | 85 | if not (ply and ply:IsValid()) then return end 86 | 87 | if not GetGlobalBool( "In_Voting" ) then 88 | ply:Notify( "There is no vote in progress, you are a dumbass." ) 89 | return 90 | end 91 | 92 | if ply.MapVoted then 93 | ply:Notify( "You have already voted!" ) 94 | return 95 | end 96 | 97 | local vote = args[1] 98 | 99 | if not vote then 100 | ply:Notify( "What are you doing?" ) 101 | return 102 | end 103 | 104 | if not tonumber(vote) then 105 | 106 | --if vote == "EXTEND" then 107 | -- RTV.VTab["MAP_EXTEND"] = RTV.VTab["MAP_EXTEND"] + 1 108 | -- ply.MapVoted = true 109 | -- ply:Notify( "You have voted to extend the map!" ) 110 | -- return 111 | --end 112 | 113 | ply:Notify( "What are you doing?" ) 114 | return 115 | end 116 | 117 | vote = math.Clamp( tonumber(vote), 1, #RTV.Maps ) 118 | 119 | RTV.VTab["MAP_"..vote] = RTV.VTab["MAP_"..vote] + 1 120 | ply.MapVoted = true 121 | ply:Notify( "You have voted for "..RTV.Maps[vote].."!" ) 122 | 123 | end ) 124 | 125 | function RTV.Finish() 126 | 127 | SetGlobalBool( "In_Voting", false ) 128 | RTV.TotalVotes = 0 129 | 130 | umsg.Start( "RTVoting" ) 131 | umsg.End() 132 | 133 | for k, v in pairs( player.GetAll() ) do 134 | v.RTVoted = false 135 | v.MapVoted = false 136 | end 137 | 138 | local top = 0 139 | local winner = nil 140 | 141 | for k,v in pairs( RTV.VTab ) do 142 | 143 | if v > top then 144 | top = v 145 | winner = k 146 | end 147 | 148 | RTV.VTab[k] = 0 149 | 150 | end 151 | 152 | if top <= 0 then 153 | 154 | Notify( "No one voted! Picking a random map..." ) 155 | RTV.ChangingMaps = true 156 | RTV.ChangeMap( RTV.Maps[math.random(1, #RTV.Maps)] ) 157 | 158 | elseif winner then 159 | 160 | winner = string.gsub( winner, "MAP_", "" ) 161 | 162 | winner = math.Clamp( tonumber(winner) or 1, 1, #RTV.Maps ) 163 | Notify( "The winning map is "..RTV.Maps[winner].."!" ) 164 | RTV.ChangingMaps = true 165 | RTV.ChangeMap( RTV.Maps[winner] ) 166 | 167 | else 168 | 169 | Notify( "Voting fucked up. RIP" ) 170 | 171 | end 172 | 173 | end 174 | 175 | function RTV.AddVote( ply ) 176 | 177 | if RTV.CanVote( ply ) then 178 | RTV.TotalVotes = RTV.TotalVotes + 1 179 | ply.RTVoted = true 180 | MsgN( ply:Nick().." has voted to Rock the Vote." ) 181 | Notify( ply:Nick().." has voted to Rock the Vote. ("..RTV.TotalVotes.."/"..math.Round(#player.GetAll()*0.66)..")" ) 182 | 183 | if RTV.ShouldChange() then 184 | RTV.Start() 185 | end 186 | end 187 | 188 | end 189 | 190 | hook.Add( "PlayerDisconnected", "Remove RTV", function( ply ) 191 | 192 | if ply.RTVoted then 193 | RTV.RemoveVote() 194 | end 195 | 196 | timer.Simple( 0.1, function() 197 | 198 | if RTV.ShouldChange() then 199 | RTV.Start() 200 | end 201 | 202 | end ) 203 | 204 | end ) 205 | 206 | function RTV.CanVote( ply ) 207 | 208 | if RTV._ActualWait >= CurTime() then 209 | return false, "You must wait a bit before voting!" 210 | end 211 | 212 | if GetGlobalBool( "In_Voting" ) then 213 | return false, "There is currently a vote in progress!" 214 | end 215 | 216 | if ply.RTVoted then 217 | return false, "You have already voted to Rock the Vote!" 218 | end 219 | 220 | if RTV.ChangingMaps then 221 | return false, "There has already been a vote, the map is going to change!" 222 | end 223 | 224 | return true 225 | 226 | end 227 | 228 | function RTV.StartVote( ply ) 229 | 230 | local can, err = RTV.CanVote(ply) 231 | 232 | if not can then 233 | ply:Notify( err ) 234 | return 235 | end 236 | 237 | RTV.AddVote( ply ) 238 | 239 | end 240 | 241 | concommand.Add( "rtv_start", RTV.StartVote ) 242 | 243 | hook.Add( "PlayerSay", "RTV Chat Commands", function( ply, text ) 244 | 245 | if table.HasValue( RTV.ChatCommands, string.lower(text) ) then 246 | RTV.StartVote( ply ) 247 | return "" 248 | end 249 | 250 | end ) -------------------------------------------------------------------------------- /deathrun/gamemode/shared.lua: -------------------------------------------------------------------------------- 1 | DeriveGamemode( "base" ) 2 | 3 | GM.Name = "Deathrun" 4 | GM.Author = "Mr. Gash" 5 | GM.Email = "" 6 | GM.Website = "nonerdsjustgeeks.com" 7 | 8 | function GM:CreateTeams() 9 | TEAM_DEATH = 2 10 | team.SetUp( TEAM_DEATH, "Death", Color( 180, 60, 60, 255 ), false ) 11 | team.SetSpawnPoint( TEAM_DEATH, "info_player_terrorist" ) 12 | 13 | TEAM_RUNNER = 3 14 | team.SetUp( TEAM_RUNNER, "Runner", Color( 60, 60, 180, 255 ), false ) 15 | team.SetSpawnPoint( TEAM_RUNNER, "info_player_counterterrorist" ) 16 | 17 | team.SetUp( TEAM_SPECTATOR, "Spectator", Color( 125, 125, 125, 255 ), true ) 18 | end 19 | 20 | local meta = FindMetaTable( "Player" ) 21 | 22 | function GM:PhysgunPickup( ply, ent ) 23 | if not ply:IsSuperAdmin() then return false end 24 | if not IsValid(ent) then return false end 25 | if not ent:IsWeapon() then return false end 26 | return true 27 | end 28 | 29 | function GM:PlayerNoClip( ply, on ) 30 | if not ply:IsAdmin() then return false end 31 | 32 | if SERVER then 33 | PrintMessage( HUD_PRINTCONSOLE, "Admin '"..ply:Nick().."' has "..(on and "enabled" or "disabled").." noclip." ) 34 | end 35 | return true 36 | end 37 | 38 | function GM:PlayerUse( ply ) 39 | if not ply:Alive() then return false end 40 | 41 | return true 42 | end 43 | 44 | function GM:GetRound() 45 | return GetGlobalInt( "Deathrun_RoundPhase" ) 46 | end 47 | 48 | function GM:GetRoundTime() 49 | return math.Round(math.max( GetGlobalInt( "Deathrun_RoundTime" ) - CurTime(), 0 )) 50 | end 51 | 52 | meta.OldAlive = meta.OldAlive or meta.Alive 53 | 54 | function meta:Alive() 55 | if self:Team() == TEAM_SPECTATOR then return false end 56 | 57 | return self:OldAlive() 58 | end 59 | 60 | -- Thanks BlackAwps! 61 | function string.FormattedTime( seconds, Format ) 62 | if not seconds then seconds = 0 end 63 | local hours = math.floor(seconds / 3600) 64 | local minutes = math.floor((seconds / 60) % 60) 65 | local millisecs = ( seconds - math.floor( seconds ) ) * 100 66 | seconds = seconds % 60 67 | 68 | if Format then 69 | return string.format( Format, minutes, seconds, millisecs ) 70 | else 71 | return { h=hours, m=minutes, s=seconds, ms=millisecs } 72 | end 73 | end 74 | 75 | -- Credit: AzuiSleet 76 | -- maybe. 77 | -- It's old, I don't remember who made it. 90% sure it was AzuiSleet. 78 | function GM:Move(pl, movedata) 79 | if pl:IsOnGround() or !pl:Alive() or pl:WaterLevel() > 0 then return end 80 | 81 | local aim = movedata:GetMoveAngles() 82 | local forward, right = aim:Forward(), aim:Right() 83 | local fmove = movedata:GetForwardSpeed() 84 | local smove = movedata:GetSideSpeed() 85 | 86 | forward.z, right.z = 0,0 87 | forward:Normalize() 88 | right:Normalize() 89 | 90 | local wishvel = forward * fmove + right * smove 91 | wishvel.z = 0 92 | 93 | local wishspeed = wishvel:Length() 94 | 95 | if(wishspeed > movedata:GetMaxSpeed()) then 96 | wishvel = wishvel * (movedata:GetMaxSpeed()/wishspeed) 97 | wishspeed = movedata:GetMaxSpeed() 98 | end 99 | 100 | local wishspd = wishspeed 101 | wishspd = math.Clamp(wishspd, 0, 30) 102 | 103 | local wishdir = wishvel:GetNormal() 104 | local current = movedata:GetVelocity():Dot(wishdir) 105 | 106 | local addspeed = wishspd - current 107 | 108 | if(addspeed <= 0) then return end 109 | 110 | local accelspeed = (120) * wishspeed * FrameTime() 111 | 112 | if(accelspeed > addspeed) then 113 | accelspeed = addspeed 114 | end 115 | 116 | local vel = movedata:GetVelocity() 117 | vel = vel + (wishdir * accelspeed) 118 | movedata:SetVelocity(vel) 119 | 120 | return false 121 | end -------------------------------------------------------------------------------- /deathrun/gamemode/sv_round.lua: -------------------------------------------------------------------------------- 1 | ROUND_WAITING = 0 2 | ROUND_PREPARING = 1 3 | ROUND_ACTIVE = 2 4 | ROUND_ENDING = 3 5 | 6 | SetGlobalInt( "Deathrun_RoundPhase", ROUND_WAITING ) 7 | SetGlobalInt( "Deathrun_RoundTime", 0 ) 8 | 9 | local minplayers = CreateConVar( "dr_min_players", 2, FCVAR_ARCHIVE ) 10 | 11 | function GM:SetRoundTime( time ) 12 | return SetGlobalInt( "Deathrun_RoundTime", CurTime() + (tonumber(time or 5) or 5) ) 13 | end 14 | 15 | CreateConVar( "dr_death_rate", 0.25, FCVAR_ARCHIVE ) 16 | CreateConVar( "dr_death_max", 6, FCVAR_ARCHIVE ) 17 | 18 | function GM:DoWeNeedDeath() 19 | 20 | local rate = math.Clamp( GetConVarNumber( "dr_death_rate" ), 0.1, 0.9 ) 21 | local plys = #player.GetAll() 22 | local md = math.max( GetConVarNumber("dr_death_max"), 2 ) 23 | 24 | local num = #team.GetPlayers(TEAM_DEATH) 25 | local need = math.floor(math.Clamp( plys * rate, 1, md )) 26 | if num >= need then return false end 27 | return true 28 | end 29 | 30 | function GM:SortPlayers( freezePlayers ) 31 | 32 | local pool = {} 33 | for k, v in pairs( player.GetAll() ) do 34 | if v:Team() == TEAM_DEATH then pool[#pool+1] = v end 35 | v:SetTeam(TEAM_SPECTATOR) 36 | end 37 | 38 | local pool2 = {} 39 | for k, v in RandomPairs( player.GetAll() ) do 40 | local need = self:DoWeNeedDeath() 41 | local stop = false 42 | if need then 43 | if not table.HasValue(pool, v) then 44 | v:SetTeam(TEAM_DEATH) 45 | else 46 | pool2[#pool2+1] = v 47 | stop = true 48 | end 49 | else 50 | v:SetTeam(TEAM_RUNNER) 51 | end 52 | if not stop then v:Spawn() end 53 | end 54 | 55 | if #pool2 > 0 then 56 | for k, v in RandomPairs( pool2 ) do 57 | if not IsValid(v) then continue end 58 | local need = self:DoWeNeedDeath() 59 | if need then 60 | v:SetTeam(TEAM_DEATH) 61 | v:PrintMessage( HUD_PRINTCONSOLE, "Sorry! We need more deaths." ) 62 | else 63 | v:SetTeam(TEAM_RUNNER) 64 | end 65 | v:Spawn() 66 | end 67 | end 68 | 69 | if freezePlayers then 70 | for k, v in pairs( player.GetAll() ) do 71 | v:Freeze(true) 72 | end 73 | end 74 | 75 | end 76 | 77 | local RTVoted = false 78 | local ShowRounds = CreateConVar( "dr_notify_rounds_left", "1", FCVAR_ARCHIVE ) 79 | 80 | GM.RoundFunctions = { 81 | 82 | [ROUND_WAITING] = function( gm ) 83 | 84 | gm:NotifyAll( "Not enough players!" ) 85 | gm:SetRoundTime( 0 ) 86 | 87 | end, 88 | 89 | [ROUND_PREPARING] = function( gm ) 90 | 91 | game.CleanUpMap() 92 | 93 | gm:SetRoundTime( 5 ) 94 | gm:SortPlayers( true ) 95 | 96 | local rounds = math.max(GetGlobalInt( "dr_rounds_left", 1 ), 0) 97 | if rounds > 0 and ShowRounds:GetInt() == 1 then 98 | gm:NotifyAll( "The map will change in "..rounds.." rounds." ) 99 | end 100 | 101 | end, 102 | 103 | [ROUND_ACTIVE] = function( gm ) 104 | 105 | gm:SetRoundTime( GetConVarNumber( "dr_roundtime_seconds" ) or 300 ) 106 | for k, v in pairs( player.GetAll() ) do 107 | v:Freeze(false) 108 | gm:PlayerLoadout( v ) 109 | end 110 | 111 | gm:NotifyAll( "The round has started!" ) 112 | 113 | end, 114 | 115 | [ROUND_ENDING] = function( gm, winner ) 116 | 117 | gm:SetRoundTime( 5 ) 118 | 119 | gm:NotifyAll( winner == 123 and "Time is up!" or team.GetName(winner).."s have won!" ) 120 | 121 | local rounds = math.max(GetGlobalInt( "dr_rounds_left", 1 ) - 1, 0) 122 | SetGlobalInt( "dr_rounds_left", rounds ) 123 | 124 | if rounds <= 1 and not RTVoted then 125 | RTV.Start() 126 | RTVoted = true 127 | end 128 | 129 | end, 130 | 131 | } 132 | 133 | function GM:SetRound( round, ... ) 134 | 135 | if not self.RoundFunctions[round] then return end 136 | 137 | local args = {...} 138 | 139 | SetGlobalInt( "Deathrun_RoundPhase", round ) 140 | self.RoundFunctions[round]( self, unpack(args) ) 141 | 142 | hook.Call( "OnRoundSet", self, round, unpack(args) ) 143 | 144 | end 145 | 146 | function GetRoundState() 147 | return GetGlobalInt( "Deathrun_RoundPhase" ) 148 | end 149 | 150 | local function GetAlivePlayersFromTeam( t ) 151 | 152 | local pool = {} 153 | for k, v in pairs( team.GetPlayers(t) ) do 154 | if v:Alive() then 155 | pool[#pool+1] = v 156 | end 157 | end 158 | 159 | return pool 160 | 161 | end 162 | 163 | local HasDoneCheck = false 164 | 165 | GM.ThinkRoundFunctions = { 166 | 167 | [ROUND_WAITING] = function( gm ) 168 | 169 | if #player.GetAll() < minplayers:GetInt() then return end 170 | 171 | gm:SetRound( ROUND_PREPARING ) 172 | 173 | end, 174 | 175 | [ROUND_PREPARING] = function( gm ) 176 | 177 | if gm:GetRoundTime() <= 0 then 178 | gm:SetRound( ROUND_ACTIVE ) 179 | end 180 | 181 | end, 182 | 183 | [ROUND_ACTIVE] = function( gm ) 184 | 185 | local time = gm:GetRoundTime() 186 | 187 | if time <= 0 then 188 | gm:SetRound( ROUND_ENDING, 123 ) 189 | return 190 | elseif not HasDoneCheck and time <= GetConVarNumber( "dr_roundtime_seconds" )*0.5 then 191 | HasDoneCheck = true 192 | for k, v in pairs( player.GetAll() ) do 193 | if v:Alive() and not v._HasPressedKey then 194 | v._HasPressedKey = true 195 | v:Kill() 196 | PrintMessage( HUD_PRINTTALK, "Automatically killed "..v:Nick().." for being AFK." ) 197 | end 198 | end 199 | end 200 | 201 | local numa = #GetAlivePlayersFromTeam( TEAM_RUNNER ) 202 | local numb = #GetAlivePlayersFromTeam( TEAM_DEATH ) 203 | 204 | if numa == 0 then 205 | gm:SetRound( ROUND_ENDING, TEAM_DEATH ) 206 | elseif numb == 0 then 207 | gm:SetRound( ROUND_ENDING, TEAM_RUNNER ) 208 | end 209 | 210 | end, 211 | 212 | [ROUND_ENDING] = function( gm ) 213 | 214 | if gm:GetRoundTime() <= 0 then 215 | gm:SetRound( ROUND_PREPARING ) 216 | return 217 | end 218 | 219 | end, 220 | 221 | } 222 | 223 | function GM:RoundThink() 224 | local cur = self:GetRound() 225 | 226 | if cur != ROUND_WAITING then 227 | if #player.GetAll() < 2 then 228 | self:SetRound(ROUND_WAITING) 229 | return 230 | end 231 | end 232 | 233 | if self.ThinkRoundFunctions[cur] then 234 | self.ThinkRoundFunctions[cur]( self ) 235 | end 236 | end 237 | -------------------------------------------------------------------------------- /deathrun/gamemode/sv_weps.lua: -------------------------------------------------------------------------------- 1 | local File = nil 2 | local Load = nil 3 | 4 | local function LoadWeapons() 5 | 6 | if not File then File = "deathrun/"..game.GetMap()..".txt" end 7 | 8 | if not Load then 9 | if not file.Exists( File, "DATA" ) then return end 10 | local read = file.Read( File, "DATA" ) 11 | 12 | read = util.JSONToTable(read) 13 | 14 | if not read then 15 | file.Delete( File ) 16 | ServerLog( "Deleting "..File.." because of some weird as shit error.\n" ) 17 | return 18 | end 19 | Load = read 20 | end 21 | 22 | for k, v in pairs( Load ) do 23 | 24 | local ent = ents.Create( v.ent ) 25 | if not IsValid(ent) then 26 | MsgN( "Could not create "..v.ent.."! Please fix "..File ) 27 | continue 28 | end 29 | ent:SetPos( v.pos ) 30 | ent:SetAngles( v.ang ) 31 | ent:Spawn() 32 | 33 | end 34 | 35 | end 36 | 37 | hook.Add( "OnRoundSet", "Load Weapons", function( round ) 38 | 39 | if round != ROUND_ACTIVE then return end 40 | 41 | LoadWeapons() 42 | 43 | end ) 44 | 45 | concommand.Add( "dr_add_weapon", function( ply, cmd, args ) 46 | 47 | if not ply:IsSuperAdmin() then return end 48 | if not ply:Alive() then return end 49 | 50 | local wep = args[1] 51 | 52 | if not wep then return end 53 | 54 | local ent = ents.Create( wep ) 55 | if not IsValid(ent) then 56 | ply:PrintMessage( 3, "Invalid entity!" ) 57 | return 58 | end 59 | ent:SetPos( ply:GetEyeTrace().HitPos + Vector( 0, 0, 50 ) ) 60 | ent:Spawn() 61 | 62 | if not ply:HasWeapon( "weapon_physgun" ) then 63 | ply:Give( "weapon_physgun" ) 64 | end 65 | 66 | end ) 67 | 68 | concommand.Add( "dr_save_weapon", function( ply, cmd, args ) 69 | 70 | if not ply:IsSuperAdmin() then return end 71 | 72 | local wep = ply:GetEyeTrace().Entity 73 | 74 | if not IsValid(wep) then ply:PrintMessage( 3, "Invalid entity." ) return end 75 | if not wep:IsWeapon() then ply:PrintMessage( 3, "You may only save weapons." ) return end 76 | 77 | if not File then File = "deathrun/"..game.GetMap()..".txt" end 78 | 79 | local tab = {} 80 | 81 | if file.Exists( File, "DATA" ) then 82 | tab = file.Read( File, "DATA" ) 83 | tab = util.JSONToTable(tab) 84 | 85 | if not tab then 86 | file.Delete( File ) 87 | ServerLog( "Deleting "..File.." because of some weird as shit error.\n" ) 88 | ply:PrintMessage( 3, File.." has been deleted because of some weird as shit error." ) 89 | tab = {} 90 | end 91 | end 92 | 93 | tab[#tab+1] = { ["ent"] = wep:GetClass(), ["pos"] = wep:GetPos(), ["ang"] = wep:GetAngles() } 94 | 95 | if not file.Exists( "deathrun", "DATA" ) then 96 | file.CreateDir( "deathrun" ) 97 | end 98 | 99 | file.Write( File, util.TableToJSON(tab) ) 100 | Load = tab 101 | 102 | ply:PrintMessage( 3, "Saved "..wep:GetClass().." to "..File.."!" ) 103 | 104 | end ) -------------------------------------------------------------------------------- /deathrun/hook_examples.lua: -------------------------------------------------------------------------------- 1 | -- Be sure to read the readme.txt file first! 2 | -- This would go in garrysmod/lua/autorun/, to get it to both run on the server and client. 3 | 4 | if SERVER then 5 | AddCSLuaFile() -- Send the file to the client. 6 | 7 | hook.Add( "OnRoundSet", "Round Set Example", function( round, winner ) 8 | 9 | if round == ROUND_WAITING then 10 | print( "We're waiting for the game to start!" ) 11 | elseif round == ROUND_PREPARING then 12 | print( "The round is preparing!" ) 13 | elseif round == ROUND_ACTIVE then 14 | print( "Let's play!" ) 15 | elseif round == ROUND_ENDING then 16 | print( "The winner is "..winner.."!" ) -- If the winner is the timelimit, it will be the number 123. 17 | if winner != 123 then 18 | print( team.GetName(winner).." is awesome!" ) 19 | end 20 | end 21 | 22 | end ) 23 | 24 | hook.Add( "ChangePlayerModel", "Overwrite Player Model Example", function( ply ) 25 | 26 | if ply:IsUserGroup( "vip" ) then -- If the player is in the "vip" group 27 | return "models/player/leet.mdl" -- Set their model to the CS:S leet model. 28 | end 29 | 30 | end ) 31 | 32 | return -- Stop the server from going any further. 33 | end 34 | -- Because we stopped the server from going any further, anything past this is clientside! 35 | 36 | hook.Add( "GetScoreboardNameColor", "Name Color Example", function( ply ) 37 | 38 | if ply:IsUserGroup( "vip" ) then -- If the player is in the "vip" group 39 | return Color( 255, 0, 0, 255 ) -- give the player a red name. 40 | end 41 | 42 | end ) 43 | 44 | hook.Add( "GetScoreboardIcon", "Icon Example", function( ply ) 45 | 46 | if ply:IsUserGroup( "vip" ) then -- If the player is in the "vip" group 47 | return "icon16/heart.png" -- give the player a heart icon! You can find 16x16 silkicons inside garrysmod/materials/icon16/ 48 | end 49 | 50 | end ) -------------------------------------------------------------------------------- /deathrun/icon24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mr-Gash/GMod-Deathrun/318798867c7230c12e066b89dadb84b2925a8b9b/deathrun/icon24.png -------------------------------------------------------------------------------- /deathrun/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mr-Gash/GMod-Deathrun/318798867c7230c12e066b89dadb84b2925a8b9b/deathrun/logo.png -------------------------------------------------------------------------------- /deathrun/readme.txt: -------------------------------------------------------------------------------- 1 | Hey! You've downloaded a deathrun gamemode, good job being able to click the download button. 2 | 3 | I made this gamemode because I felt bad people were using my old shitty one that I released. That gamemode was just to help me learn more about Lua, and is just awful. I apologize to all of those that have used it. 4 | 5 | Installation: 6 | 7 | Drop the "deathrun" folder inside /Server/orangebox/garrysmod/gamemodes/ 8 | 9 | Inside your server.cfg file, add: 10 | gamemode "deathrun" 11 | 12 | This !does not! have any weapons by default. If you want to have weapons, download a weapon pack and name them that of the CS:S weapons. For example, if you have a weapon_real_cs_ak47, rename it to weapon_ak47 to be used. The gamemode does NOT spawn the weapons automatically, the map does! 13 | If you don't want to do this, you can of course have the gamemode spawn the weapons, but this means you will have to place them all manually. To do this, join the map you want to place weapons on. 14 | Look to where you want it to spawn, and type in your console "dr_add_weapon weapon_name" - you MUST be a superadmin to do this. To save the weapon, look at it and type "dr_save_weapon" in your console. 15 | 16 | Don't forget to download some maps you can play! There are a lot you can find just by doing a Google search. Deathrun maps start with either "deathrun_" or "dr_" 17 | 18 | ConVars: 19 | 20 | dr_roundtime_seconds (default: 360) 21 | Will set the round length, in seconds. 22 | 23 | dr_highlight_admins (default: 1) 24 | If set to 1, admins will be highlighted gold on the scoreboard and also have a shield icon. 25 | 26 | dr_total_rounds (default: 10) 27 | The amount of rounds to play before a map change. 28 | 29 | dr_allow_death_suicide (default: 0) 30 | If set to 1, "Deaths" will be able to kill themselves with the use of the "kill" command. If set to 0, nothing will happen with use of the command. 31 | 32 | dr_allow_autojump (default: 1) 33 | If set to 0, players will not autojump by holding down their spacebar (regardless if they have it enabled/disabled). I don't recommend disabling this. 34 | 35 | dr_unlimited_ammo (default: 1) 36 | If set to 1, primary ammo will not be taken when players shoot weapons. This won't work with default HL2 weapons. 37 | 38 | dr_allow_death_pickup (default: 0) 39 | If set to 0, players on the Death team will be unable to pick up any weapons aside from the crowbar. 40 | 41 | dr_realistic_fall_damage (default: 1) 42 | If set to 1, players will be damaged based on the speed at which they fall. If set to 0, the fall damage will be 10, regardless of speed or height. 43 | 44 | dr_notify_rounds_left (default: 1) 45 | Notify everyone on the server how many rounds are left as the prep phase begins. 46 | 47 | dr_push_collide (default: 0) 48 | If set to 1, when one player enters another, they will be pushed apart. 49 | 50 | dr_death_rate (default: 0.25, minimum: 0.1, max: 0.9) 51 | Percentage of total players that will become a death. The player amount is multiplied by this number, then rounded down. 52 | 53 | dr_death_max (default: 6, minimum: 2 ) 54 | The maximum amount of deaths. 55 | 56 | Hooks: 57 | 58 | GetScoreboardNameColor (player) 59 | Clientside 60 | Called to get the color of a player on the scoreboard. Return a color to change it for this player. If you don't return anything, it will default to Color(255, 255, 255, 255) (white). 61 | 62 | GetScoreboardIcon (player) 63 | Clientside 64 | Called to get an icon to show on the scoreboard- must be a png. Admins by defualt have the "icon16/shield.png" icon. Return a string to use that icon, return false to not use an icon (default). 65 | 66 | OnRoundSet (round[, winner]) 67 | Serverside 68 | Called when the round is set. It can be set to ROUND_... WAITING, PREPARING, ACTIVE, ENDING 69 | If it is called with ROUND_ENDING, the second argument will be the winner of the round. 70 | 71 | ChangePlayerModel (player) 72 | Serverside 73 | Return a string to have a player set to that model. Return false to have it set to one of the default models. 74 | 75 | If you want help with the hooks, view hook_examples.lua in the same folder this file is in! 76 | 77 | To change the text in the F1 menu, edit menutext.lua 78 | Also, I apologize for the terrible logo/icon. I know that I'm bad at design work. 79 | 80 | My Steam: http://steamcommunity.com/id/mrgash2 81 | --------------------------------------------------------------------------------