diff options
Diffstat (limited to 'gamemode/init.lua')
| -rw-r--r-- | gamemode/init.lua | 2103 |
1 files changed, 2103 insertions, 0 deletions
diff --git a/gamemode/init.lua b/gamemode/init.lua new file mode 100644 index 0000000..eafdfcb --- /dev/null +++ b/gamemode/init.lua @@ -0,0 +1,2103 @@ + +include( 'player_class/player_base.lua' ) +include( 'player_class/player_zombie.lua' ) +include( 'map_defaults.lua' ) +include( 'resource.lua' ) +include( 'enums.lua' ) +include( 'items.lua' ) +include( 'events.lua' ) +include( 'shared.lua' ) +include( 'moddable.lua' ) +include( 'ply_extension.lua' ) +include( 'tables.lua' ) +include( 'weather.lua' ) + +AddCSLuaFile( 'player_class/player_base.lua' ) +AddCSLuaFile( 'player_class/player_zombie.lua' ) +AddCSLuaFile( 'animations.lua' ) +AddCSLuaFile( 'enums.lua' ) +AddCSLuaFile( 'items.lua' ) +AddCSLuaFile( 'shared.lua' ) +AddCSLuaFile( 'moddable.lua' ) +AddCSLuaFile( 'cl_notice.lua' ) +AddCSLuaFile( 'cl_hudstains.lua' ) +AddCSLuaFile( 'cl_targetid.lua' ) +AddCSLuaFile( 'cl_spawnmenu.lua' ) +AddCSLuaFile( 'cl_inventory.lua' ) +AddCSLuaFile( 'cl_init.lua' ) +AddCSLuaFile( 'cl_postprocess.lua' ) +AddCSLuaFile( 'cl_scoreboard.lua' ) +AddCSLuaFile( 'ply_extension.lua' ) +AddCSLuaFile( 'tables.lua' ) +AddCSLuaFile( 'weather.lua' ) +AddCSLuaFile( 'vgui/vgui_panelbase.lua' ) +AddCSLuaFile( 'vgui/vgui_dialogue.lua' ) +AddCSLuaFile( 'vgui/vgui_shopmenu.lua' ) +AddCSLuaFile( 'vgui/vgui_classpicker.lua' ) +AddCSLuaFile( 'vgui/vgui_zombieclasses.lua' ) +AddCSLuaFile( 'vgui/vgui_itempanel.lua' ) +AddCSLuaFile( 'vgui/vgui_helpmenu.lua' ) +AddCSLuaFile( 'vgui/vgui_endgame.lua' ) +AddCSLuaFile( 'vgui/vgui_itemdisplay.lua' ) +AddCSLuaFile( 'vgui/vgui_playerdisplay.lua' ) +AddCSLuaFile( 'vgui/vgui_playerpanel.lua' ) +AddCSLuaFile( 'vgui/vgui_panelsheet.lua' ) +AddCSLuaFile( 'vgui/vgui_goodmodelpanel.lua' ) +AddCSLuaFile( 'vgui/vgui_categorybutton.lua' ) +AddCSLuaFile( 'vgui/vgui_sidebutton.lua' ) +AddCSLuaFile( 'vgui/vgui_scroller.lua' ) + +util.AddNetworkString( "InventorySynch" ) +util.AddNetworkString( "StashSynch" ) +util.AddNetworkString( "StatsSynch" ) +util.AddNetworkString( "ItemPlacerSynch" ) +util.AddNetworkString( "WeatherSynch" ) + +function GM:Initialize() + + GAMEMODE.NextZombieThink = CurTime() + GetConVar( "sv_redead_setup_time" ):GetInt() + GAMEMODE.RandomLoot = {} + GAMEMODE.PlayerIDs = {} + GAMEMODE.Lords = {} + GAMEMODE.Wave = 1 + GAMEMODE.NextWave = CurTime() + 60 * GetConVar( "sv_redead_wave_length" ):GetInt() + + local length = #GAMEMODE.Waves * ( GetConVar( "sv_redead_wave_length" ):GetInt() * 60 ) + + for i=1, #GAMEMODE.Waves - 1 do + + local remain = length - i * GetConVar( "sv_redead_wave_length" ):GetInt() * 60 + local num = i * GetConVar( "sv_redead_wave_length" ):GetInt() + + timer.Simple( remain, function() for k,v in pairs( team.GetPlayers( TEAM_ARMY ) ) do v:Notice( num .. " minutes until evac arrives", GAMEMODE.Colors.White, 5 ) end end ) + + end + + timer.Simple( GetConVar( "sv_redead_setup_time" ):GetInt(), function() for k,v in pairs( player.GetAll() ) do v:Notice( "The undead onslaught has begun", GAMEMODE.Colors.White, 5 ) end end ) + + timer.Simple( GetConVar( "sv_redead_setup_time" ):GetInt() - 5, function() for k,v in pairs( team.GetPlayers( TEAM_ARMY ) ) do v:Notice( "Press F4 if you want to be the zombie lord", GAMEMODE.Colors.White, 5 ) end end ) + + timer.Simple( GetConVar( "sv_redead_setup_time" ):GetInt() + 5, function() GAMEMODE:PickLord() GAMEMODE.EarlyPick = true end ) + + timer.Simple( length - 60, function() + + if GetGlobalBool( "GameOver", false ) then return end + + GAMEMODE.EvacAlert = true + + for k,v in pairs( player.GetAll() ) do + + v:ClientSound( GAMEMODE.LastMinute ) + v:Notice( "The evac chopper is en route", GAMEMODE.Colors.White, 5 ) + + end + + end ) + + timer.Simple( length - 40, function() + + if GetGlobalBool( "GameOver", false ) then return end + + for k,v in pairs( team.GetPlayers( TEAM_ARMY ) ) do + + v:Notice( "The evac chopper has arrived", GAMEMODE.Colors.White, 5 ) + v:Notice( "You have 45 seconds to reach the evac zone", GAMEMODE.Colors.White, 5, 2 ) + v:Notice( "The location has been marked", GAMEMODE.Colors.White, 5, 4 ) + + end + + if IsValid( GAMEMODE.Antidote ) then + + GAMEMODE.Antidote:SetOverride() + + end + + GAMEMODE:SpawnEvac() + + end ) + + timer.Simple( length + 5, function() GAMEMODE:CheckGameOver( true ) end ) + + GAMEMODE:WeatherInit() + + if math.random( 1, 10 ) == 1 then + + GAMEMODE.RandomEvent = CurTime() + ( 60 * math.Rand( 1.5, 3.5 ) ) + + end + +end + +GM.Breakables = {} +GM.WoodLocations = {} +GM.WoodCount = 1 +GM.WoodPercent = 1 +GM.SpawnCounter = 0 +GM.LordExists = false +GM.EarlyPick = false + +function GM:InitPostEntity() + + GAMEMODE.Trader = ents.Create( "info_trader" ) + GAMEMODE.Trader:Spawn() + + GAMEMODE.SpecialTrader = ents.Create( "info_trader" ) + GAMEMODE.SpecialTrader:SetSpecial( true ) + GAMEMODE.SpecialTrader:Spawn() + + local badshit = ents.FindByClass( "npc_*" ) + badshit = table.Add( badshit, ents.FindByClass( "weapon_*" ) ) + badshit = table.Add( badshit, ents.FindByClass( "prop_ragdoll" ) ) + badshit = table.Add( badshit, ents.FindByClass( "item_*" ) ) + badshit = table.Add( badshit, ents.FindByClass( "point_servercommand" ) ) + badshit = table.Add( badshit, ents.FindByClass( "env_entity_maker" ) ) + badshit = table.Add( badshit, ents.FindByClass( "point_template" ) ) + badshit = table.Add( badshit, ents.FindByClass( "game_text" ) ) + + for k,v in pairs( ents.FindByClass( "prop_phys*" ) ) do + + if string.find( v:GetModel(), "explosive" ) or string.find( v:GetModel(), "propane" ) or string.find( v:GetModel(), "gascan" ) or string.find( v:GetModel(), "gib" ) then + + table.insert( badshit, v ) + + end + + local phys = v:GetPhysicsObject() + + if IsValid( phys ) and table.HasValue( { "wood", "wood_crate", "wood_furniture", "wood_plank", "default" }, phys:GetMaterial() ) and phys:GetMass() > 8 then + + table.insert( GAMEMODE.WoodLocations, { Pos = v:GetPos(), Ang = v:GetAngles(), Model = v:GetModel(), Health = v:Health() } ) + + GAMEMODE.WoodCount = GAMEMODE.WoodCount + 1 + + v.IsWooden = true + + if v:Health() == 0 then + + v:SetHealth( 100 ) + + end + + if phys:IsAsleep() then + + phys:Wake() + + end + + end + + end + + for k,v in pairs( badshit ) do + + v:Remove() + + end + + GAMEMODE.WoodPercent = math.floor( table.Count( ents.FindByClass( "prop_phys*" ) ) * GAMEMODE.WoodPercentage ) + + for k,v in pairs( ents.FindByClass( "prop_phys*" ) ) do + + local tbl = item.GetByModel( v:GetModel() ) + local phys = v:GetPhysicsObject() + + if tbl or ( IsValid( phys ) and phys:GetMass() <= 3 ) then + + v:Remove() + + end + + end + + GAMEMODE:LoadAllEnts() + + local tbl = ents.FindByClass( "prop_door_rotating" ) + tbl = table.Add( tbl, ents.FindByClass( "func_breakable*" ) ) + tbl = table.Add( tbl, ents.FindByClass( "func_door*" ) ) + + GAMEMODE.Breakables = tbl + GAMEMODE.NPCSpawns = ents.FindByClass( "info_npcspawn" ) + + local num = #ents.FindByClass( "point_radiation" ) + + if num < 5 then return end + + for i=1, math.floor( num * GAMEMODE.RadiationAmount ) do + + local rad = table.Random( ents.FindByClass( "point_radiation" ) ) + + while !rad:IsActive() do + + rad = table.Random( ents.FindByClass( "point_radiation" ) ) + + end + + rad:SetActive( false ) + + end + +end + +function GM:SaveAllEnts() + + MsgN( "Saving ReDead map config data..." ) + + local enttbl = { + info_player_zombie = {}, + info_player_army = {}, + info_lootspawn = {}, + info_npcspawn = {}, + info_evac = {}, + point_stash = {}, + point_radiation = {}, + prop_physics = {} + } + + for k,v in pairs( enttbl ) do + + for c,d in pairs( ents.FindByClass( k ) ) do + + if k == "prop_physics" then + + if d.AdminPlaced then + + local phys = d:GetPhysicsObject() + + if IsValid( phys ) then + + table.insert( enttbl[k], { d:GetPos(), d:GetModel(), d:GetAngles(), phys:IsMoveable() } ) + + end + + end + + elseif d.AdminPlaced then + + table.insert( enttbl[k], d:GetPos() ) + + end + + end + + end + + file.Write( "redead/" .. string.lower( game.GetMap() ) .. "_json.txt", util.TableToJSON( enttbl ) ) + +end + +function GM:LoadAllEnts() + + MsgN( "Loading ReDead map config data..." ) + + local read = file.Read( "redead/" .. string.lower( game.GetMap() ) .. "_json.txt", "DATA" ) + + if not read then + + MsgN( "No map config data found for " .. game.GetMap() .. "." ) + + return + + end + + local config = util.JSONToTable( read ) + + if not config then + + MsgN( "ERROR: ReDead map config data file was empty!" ) + + return + + end + + MsgN( "Loaded ReDead map config data successfully!" ) + + for k,v in pairs( config ) do + + if v[1] then + + if k == "prop_physics" then + + for c,d in pairs( v ) do + + local function spawnent() + + local ent = ents.Create( k ) + ent:SetPos( d[1] ) + ent:SetModel( d[2] ) + ent:SetAngles( d[3] ) + ent:SetSkin( math.random( 0, 6 ) ) + ent:Spawn() + ent.AdminPlaced = true + + local phys = ent:GetPhysicsObject() + + if IsValid( phys ) and not d[4] then + + phys:EnableMotion( false ) + + end + + end + + timer.Simple( c * 0.1, function() spawnent() end ) + + end + + else + + for c,d in pairs( ents.FindByClass( k ) ) do + + d:Remove() + + end + + for c,d in pairs( v ) do + + if k != "point_radiation" and k != "info_lootspawn" and k != "info_npcspawn" then + + local function spawnent() + + local ent = ents.Create( k ) + ent:SetPos( d ) + ent:Spawn() + ent.AdminPlaced = true + + end + + timer.Simple( c * 0.1, function() spawnent() end ) + + else + + local ent = ents.Create( k ) + ent:SetPos( d ) + ent:Spawn() + ent.AdminPlaced = true + + end + + end + + end + + end + + end + +end + +function GM:AddToZombieList( ply ) + + if team.NumPlayers( TEAM_ZOMBIES ) > 0 then + + ply:ClientSound( "HL1/fvox/buzz.wav", 100 ) + ply:Notice( "You cannot be the zombie lord now", GAMEMODE.Colors.Red, 5 ) + + return + + end + + if not table.HasValue( GAMEMODE.Lords, ply ) and not GAMEMODE.LordExists then + + table.insert( GAMEMODE.Lords, ply ) + + local snd = table.Random( GAMEMODE.AmbientScream ) + ply:ClientSound( snd, 100 ) + ply:Notice( "You have volunteered to be the zombie lord", GAMEMODE.Colors.White, 5 ) + + end + +end + +function GM:PickLord( force ) + + if table.Count( player.GetAll() ) < GetConVar( "sv_redead_minimum_players" ):GetInt() and not force then + + for k,v in pairs( player.GetAll() ) do + + v:Notice( "A zombie lord cannot be chosen at this time", GAMEMODE.Colors.White, 5 ) + + end + + return + + end + + local tbl = team.GetPlayers( TEAM_ZOMBIES ) + + for k,v in pairs( GAMEMODE.Lords ) do + + if IsValid( v ) then + + table.insert( tbl, v ) + + end + + end + + if table.Count( tbl ) < 1 then + + tbl = team.GetPlayers( TEAM_ARMY ) + + end + + local ply = table.Random( tbl ) + + local snd = table.Random( GAMEMODE.AmbientScream ) + ply:ClientSound( snd, 100 ) + + if ply:Team() == TEAM_ZOMBIES then + + ply:Notice( "You have become the zombie lord", GAMEMODE.Colors.White, 5 ) + + timer.Simple( 3, function() ply:Gib() ply:SetLord( true ) end ) + + else + + ply:Notice( "You will become the zombie lord", GAMEMODE.Colors.White, 5 ) + + timer.Simple( 3, function() ply:SetTeam( TEAM_ZOMBIES ) ply:SetPlayerClass( CLASS_RUNNER ) ply:SetCash( 0 ) ply:Gib() ply:SetLord( true ) end ) + + end + + for k,v in pairs( player.GetAll() ) do + + if v != ply and not force then + + v:Notice( "A zombie lord has been chosen", GAMEMODE.Colors.White, 5 ) + + end + + end + + GAMEMODE.LordExists = true + +end + +function GM:RespawnAntidote() + + if IsValid( ents.FindByClass( "sent_antidote" )[1] ) and ents.FindByClass( "sent_antidote" )[1]:CuresLeft() > 0 then return end + + if #ents.FindByClass( "info_lootspawn" ) < 3 then return end + + local ent = table.Random( ents.FindByClass( "info_lootspawn" ) ) + local pos = ent:GetPos() + local close = true + + while close do + + ent = table.Random( ents.FindByClass( "info_lootspawn" ) ) + pos = ent:GetPos() + close = false + + for k,v in pairs( ents.FindByClass( "sent_antidote" ) ) do + + if v:GetPos():Distance( pos ) < 500 then + + close = true + + end + + end + + end + + local ant = ents.Create( "sent_antidote" ) + ant:SetPos( pos ) + ant:Spawn() + + GAMEMODE.Antidote = ant + + for k,v in pairs( team.GetPlayers( TEAM_ARMY ) ) do + + v:Notice( "The antidote resupply location has changed", GAMEMODE.Colors.White, 5 ) + + end + +end + +function GM:SpawnEvac() + + local pos = Vector(0,0,0) + + if #ents.FindByClass( "info_evac" ) < 1 then + + local loot = ents.FindByClass( "info_lootspawn" ) + + if #loot < 1 then + + MsgN( "ERROR: Map not configured properly." ) + + return + + end + + local prop = table.Random( loot ) + + pos = prop:GetPos() + + else + + local point = table.Random( ents.FindByClass( "info_evac" ) ) + pos = point:GetPos() + + end + + local evac = ents.Create( "point_evac" ) + evac:SetPos( pos ) + evac:Spawn() + +end + +function GM:GetGeneratedLoot() + + local tbl = {} + + for k,v in pairs( GAMEMODE.RandomLoot ) do + + if IsValid( v ) then + + table.insert( tbl, v ) + + end + + end + + for k,v in pairs( GAMEMODE.RandomLoot ) do + + if not IsValid( v ) then + + table.remove( tbl, k ) + + return tbl + + end + + end + + return tbl + +end + +function GM:LootThink() + + for k,v in pairs( ents.FindByClass( "prop_phys*" ) ) do + + if v.Removal and v.Removal < CurTime() and IsValid( v ) then + + v:Remove() + + end + + end + + if #ents.FindByClass( "info_lootspawn" ) < 10 then return end + + local amt = math.floor( GAMEMODE.MaxLoot * #ents.FindByClass( "info_lootspawn" ) ) + local total = 0 + + local loots = GAMEMODE:GetGeneratedLoot() + + local num = amt - #loots + + if num > 0 then + + local tbl = { ITEM_SUPPLY, ITEM_LOOT, ITEM_AMMO, ITEM_MISC, ITEM_SPECIAL, ITEM_WPN_COMMON, ITEM_WPN_SPECIAL, ITEM_EXPLOSIVE } + local chancetbl = { 0.60, 0.70, 0.70, 0.95, 0.05, 0.03, 0.02, 0.10 } + + for i=1, num do + + local ent = table.Random( ents.FindByClass( "info_lootspawn" ) ) + local pos = ent:GetPos() + local rnd = math.Rand(0,1) + local choice = math.random( 1, table.Count( tbl ) ) + + while rnd > chancetbl[ choice ] do + + rnd = math.Rand(0,1) + choice = math.random( 1, table.Count( tbl ) ) + + end + + local rand = item.RandomItem( tbl[choice] ) + local proptype = "prop_physics" + + if rand.TypeOverride then + + proptype = rand.TypeOverride + + end + + local loot = ents.Create( proptype ) + loot:SetPos( pos + Vector(0,0,5) ) + loot:SetAngles( VectorRand():Angle() ) + + if rand.DropModel then + + loot:SetModel( rand.DropModel ) + + else + + loot:SetModel( rand.Model ) + + end + + loot:Spawn() + loot.RandomLoot = true + loot.IsItem = true + + if not rand.CollisionOverride then + + loot:SetCollisionGroup( COLLISION_GROUP_WEAPON ) + + end + + table.insert( GAMEMODE.RandomLoot, loot ) + + end + + end + +end + +function GM:WoodThink() + + if table.Count( GAMEMODE.WoodLocations ) < 1 then return end + + if GAMEMODE.WoodCount < GAMEMODE.WoodPercent then + + local tbl = table.Random( GAMEMODE.WoodLocations ) + local prop = ents.Create( "prop_physics" ) + prop:SetPos( tbl.Pos ) + prop:SetAngles( tbl.Ang ) + prop:SetModel( tbl.Model ) + prop:SetHealth( math.Clamp( tbl.Health, 50, 500 ) ) + prop:Spawn() + prop.IsWooden = true + + GAMEMODE.WoodCount = GAMEMODE.WoodCount + 1 + + elseif GAMEMODE.WoodCount > GAMEMODE.WoodPercent then + + local ent = table.Random( ents.FindByClass( "prop_phys*" ) ) + local phys = ent:GetPhysicsObject() + + if IsValid( phys ) and not ent.IsItem and ent.IsWooden then + + ent:Remove() + + GAMEMODE.WoodCount = GAMEMODE.WoodCount - 1 + + end + + end + +end + +function GM:EventThink() + + if not GAMEMODE.RandomEvent then + + GAMEMODE.RandomEvent = CurTime() + ( 60 * math.Rand( 3.5, 9.5 ) ) + + end + + if GAMEMODE.RandomEvent and GAMEMODE.RandomEvent < CurTime() then + + local ev = event.GetRandom() + + while ( ( ev.Type == EVENT_WEATHER and GAMEMODE.WeatherHappened ) or ev.Chance < math.Rand(0,1) ) do + + ev = event.GetRandom() + + end + + if ev.Type == EVENT_WEATHER then + + GAMEMODE.WeatherHappened = true + + end + + ev.Start() + + GAMEMODE.Event = ev + GAMEMODE.RandomEvent = nil + + end + + if GAMEMODE.Event then + + GAMEMODE.Event:Think() + + if GAMEMODE.Event:EndThink() then + + GAMEMODE.Event:End() + GAMEMODE.Event = nil + + end + + end + +end + +function GM:WaveThink() + + if GAMEMODE.NextWave < CurTime() then + + GAMEMODE.NextWave = CurTime() + 60 * GetConVar( "sv_redead_wave_length" ):GetInt() + GAMEMODE.Wave = GAMEMODE.Wave + 1 + + if GAMEMODE.Wave > #GAMEMODE.Waves then return end + + for k,v in pairs( player.GetAll() ) do + + v:Notice( "New undead mutations have been spotted", GAMEMODE.Colors.White, 5 ) + v:ClientSound( table.Random( GAMEMODE.AmbientScream ) ) + + end + + end + +end + +function GM:GetZombieClass() + + local rand = math.Rand(0,1) + local class = table.Random( GAMEMODE.Waves[ GAMEMODE.Wave ] or { "npc_nb_common" } ) + + while #GAMEMODE.Waves[ GAMEMODE.Wave ] != 1 and rand > GAMEMODE.SpawnChance[ class ] do + + rand = math.Rand(0,1) + class = table.Random( GAMEMODE.Waves[ GAMEMODE.Wave ] or { "npc_nb_common" } ) + + end + + return class + +end + +function GM:NPCRespawnThink() + + for k,v in pairs( ( GAMEMODE.NPCSpawns or {} ) ) do + + if IsValid( v ) then + + local box = ents.FindInBox( v:GetPos() + Vector( -32, -32, 0 ), v:GetPos() + Vector( 32, 32, 64 ) ) + local can = true + + for k,v in pairs( box ) do + + if v.NextBot then + + can = false + + end + + end + + if can and GAMEMODE.SpawnCounter > 0 then + + local ent = ents.Create( GAMEMODE:GetZombieClass() ) + ent:SetPos( v:GetPos() ) + ent:Spawn() + + GAMEMODE.SpawnCounter = GAMEMODE.SpawnCounter - 1 + + end + + end + + end + +end + +function GM:NPCThink() + + if GAMEMODE.Wave > #GAMEMODE.Waves then return end + + local tbl = ents.FindByClass( "npc_nb*" ) + + if #tbl < GetConVar( "sv_redead_max_zombies" ):GetInt() and #tbl < GetConVar( "sv_redead_zombies_per_player" ):GetInt() * team.NumPlayers( TEAM_ARMY ) then + + local total = math.Round( GetConVar( "sv_redead_zombies_per_player" ):GetInt() * team.NumPlayers( TEAM_ARMY ) + GetConVar( "sv_redead_zombies_per_player_zombie" ):GetFloat() * team.NumPlayers( TEAM_ZOMBIES ) ) + local num = math.Clamp( total, 1, math.Min( GetConVar( "sv_redead_max_zombies" ):GetInt() - #tbl, total ) ) + + GAMEMODE.SpawnCounter = num + + --[[for i=1, num do + + local tbl = ents.FindByClass( "info_npcspawn" ) + + if #tbl < 1 then return end + + local spawn = table.Random( tbl ) + local vec = VectorRand() * 5 + + vec.z = 1 + + local ent = ents.Create( GAMEMODE:GetZombieClass() ) + ent:SetPos( spawn:GetPos() + vec ) + ent:Spawn() + + end]] + + end + +end + +function GM:Think() + + if ( GAMEMODE.NextGameThink or 0 ) < CurTime() then + + if ( GAMEMODE.NextZombieThink or 0 ) < CurTime() then + + GAMEMODE:NPCThink() + + GAMEMODE.NextZombieThink = CurTime() + GetConVar( "sv_redead_wave_time" ):GetInt() + + end + + GAMEMODE:NPCRespawnThink() + GAMEMODE:RespawnAntidote() + GAMEMODE:EventThink() + GAMEMODE:LootThink() + GAMEMODE:WoodThink() + GAMEMODE:WaveThink() + GAMEMODE:WeatherThink() + GAMEMODE:CheckGameOver( false ) + GAMEMODE.NextGameThink = CurTime() + 1 + + end + + for k,v in pairs( player.GetAll() ) do + + if v:Team() != TEAM_UNASSIGNED then + + v:Think() + + end + + end + +end + +function GM:PhysgunPickup( ply, ent ) + + if ply:IsAdmin() or ply:IsSuperAdmin() then return true end + + if ent:IsPlayer() then return false end + + if not ent.Placer or ent.Placer != ply then return false end + + return true + +end + +function GM:PlayerDisconnected( pl ) + + if pl:Alive() then + + pl:DropLoot() + + end + + if not table.HasValue( GAMEMODE.PlayerIDs, pl:SteamID() ) then + + table.insert( GAMEMODE.PlayerIDs, pl:SteamID() ) + + end + + if pl:IsLord() then + + GAMEMODE.LordExists = false + + end + +end + +function GM:PlayerInitialSpawn( pl ) + + pl:GiveAmmo( 200, "Pistol", false ) + + if table.HasValue( GAMEMODE.PlayerIDs, pl:SteamID() ) then + + pl:SetTeam( TEAM_ZOMBIES ) + + elseif pl:IsBot() then + + pl:SetTeam( TEAM_ARMY ) + pl:Spawn() + + else + + pl:SetTeam( TEAM_UNASSIGNED ) + pl:Spectate( OBS_MODE_ROAMING ) + + end + +end + +function GM:PlayerSpawn( pl ) + + if pl:Team() == TEAM_UNASSIGNED then + + pl:Spectate( OBS_MODE_ROAMING ) + pl:SetPos( pl:GetPos() + Vector( 0, 0, 50 ) ) + + return + + end + + GAMEMODE:RespawnAntidote() + + if pl:Team() == TEAM_ARMY then + + local music = table.Random( GAMEMODE.OpeningMusic ) + + pl:ClientSound( music, 100 ) + + end + + pl:NoticeOnce( "Press F1 to view the help menu", GAMEMODE.Colors.Blue, 7, 15 ) + pl:NoticeOnce( "Press F2 to buy items and weapons", GAMEMODE.Colors.Blue, 7, 17 ) + pl:NoticeOnce( "Press F3 to activate the panic button", GAMEMODE.Colors.Blue, 7, 19 ) + pl:InitializeInventory() + pl:OnSpawn() + pl:OnLoadout() + + local oldhands = pl:GetHands() + + if IsValid( oldhands ) then + + oldhands:Remove() + + end + + local hands = ents.Create( "gmod_hands" ) + + if IsValid( hands ) then + + hands:DoSetup( pl ) + hands:Spawn() + + end + +end + +function GM:PlayerSetModel( pl ) + +end + +function GM:PlayerLoadout( pl ) + +end + +function GM:PlayerJoinTeam( ply, teamid ) + + local oldteam = ply:Team() + + if ply:Alive() and ply:Team() != TEAM_UNASSIGNED then return end + + if teamid != TEAM_UNASSIGNED and ply:Team() == TEAM_UNASSIGNED then + + ply:UnSpectate() + + end + + if teamid == TEAM_SPECTATOR or teamid == TEAM_UNASSIGNED then + + teamid = TEAM_ARMY + + end + + ply:SetTeam( teamid ) + + if ply.NextSpawn and ply.NextSpawn > CurTime() then + + ply.NextSpawn = CurTime() + 5 + + else + + ply:Spawn() + + end + +end + +function GM:PlayerSwitchFlashlight( ply, on ) + + return ply:Team() == TEAM_ARMY + +end + +function GM:GetFallDamage( ply, speed ) + + if ply:Team() == TEAM_ZOMBIES then + + return 5 + + end + + local pain = speed * 0.12 + + ply:AddStamina( math.floor( pain * -0.25 ) ) + + return pain + +end + +function GM:PlayerDeathSound() + + return true + +end + +function GM:CanPlayerSuicide( ply ) + + return false + +end + +function GM:KeyRelease( ply, key ) + + if ply:Team() != TEAM_ARMY then return end + + if key == IN_JUMP then + + ply:AddStamina( -2 ) + + end + + if key != IN_USE then return end + + local trace = {} + trace.start = ply:GetShootPos() + trace.endpos = trace.start + ply:GetAimVector() * 80 + trace.filter = ply + + local tr = util.TraceLine( trace ) + + if IsValid( tr.Entity ) and tr.Entity:GetClass() == "prop_physics" then + + if IsValid( ply.Stash ) then + + ply.Stash:OnExit( ply ) + + return true + + end + + ply:AddToInventory( tr.Entity ) + + return true + + elseif IsValid( tr.Entity ) and tr.Entity:GetClass() == "point_stash" then + + if IsValid( ply.Stash ) then + + ply.Stash:OnExit( ply ) + + else + + tr.Entity:OnUsed( ply ) + + end + + elseif not IsValid( tr.Entity ) then + + if IsValid( ply.Stash ) then + + ply.Stash:OnExit( ply ) + + end + + end + + return true + +end + +function GM:PropBreak( att, prop ) + + local phys = prop:GetPhysicsObject() + + if IsValid( phys ) and prop:GetModel() != "models/props_debris/wood_board04a.mdl" then + + if prop.IsWooden then + + GAMEMODE:SpawnChunk( prop:LocalToWorld( prop:OBBCenter() ) ) + GAMEMODE.WoodCount = GAMEMODE.WoodCount - 1 + + end + + end + +end + +function GM:SpawnChunk( pos ) + + local ent = ents.Create( "prop_physics" ) + ent:SetPos( pos ) + ent:SetModel( "models/props_debris/wood_chunk04a.mdl" ) + ent:SetCollisionGroup( COLLISION_GROUP_WEAPON ) + ent:Spawn() + ent.IsItem = true + +end + +function GM:AllowPlayerPickup( ply, ent ) + + local tbl = item.GetByModel( ent:GetModel() ) + + if tbl and tbl.AllowPickup then + + return true + + end + + return false + +end + +function GM:PlayerUse( ply, entity ) + + if ply:Team() == TEAM_ARMY and ( ply.LastUse or 0 ) < CurTime() then + + if table.HasValue( { "sent_propane_canister", "sent_propane_tank", "sent_fuel_diesel", "sent_fuel_gas" }, entity:GetClass() ) then + + ply.LastUse = CurTime() + 0.5 + + if not IsValid( ply.HeldObject ) and not IsValid( entity.Holder ) then + + ply:PickupObject( entity ) + ply.HeldObject = entity + entity.Holder = ply + entity:SetCollisionGroup( COLLISION_GROUP_WEAPON ) + + elseif entity == ply.HeldObject then + + ply:DropObject( entity ) + ply.HeldObject = nil + entity.Holder = nil + entity:SetCollisionGroup( COLLISION_GROUP_NONE ) + + end + + end + + return true + + end + + if ply:Team() != TEAM_ZOMBIES then return false end + + local trace = {} + trace.start = ply:GetShootPos() + trace.endpos = trace.start + ply:GetAimVector() * 80 + trace.filter = ply + + local tr = util.TraceLine( trace ) + + if entity:GetClass() == "prop_door_rotating" or entity:GetClass() == "func_button" then + + return false + + end + + return true + +end + +function GM:EntityTakeDamage( ent, dmginfo ) + + if ent.IsWooden then + + ent.WoodHealth = ( ent.WoodHealth or 150 ) - dmginfo:GetDamage() + + if ent.WoodHealth < 1 then + + ent:Fire( "break", 0, 0 ) + + end + + end + + if not ent:IsPlayer() and ent:IsOnFire() then + + ent:Extinguish() + + end + + if not ent:IsPlayer() and ent.IsItem then + + dmginfo:ScaleDamage( 0 ) + + return + + end + + local attacker = dmginfo:GetAttacker() + + if ent:IsPlayer() and ent:Team() == TEAM_ARMY and IsValid( attacker ) and ( attacker:IsNPC() or ( ( attacker:IsPlayer() and attacker:Team() == TEAM_ZOMBIES ) or ( attacker:IsPlayer() and attacker == ent ) ) ) then + + if ent:Health() <= 50 then + + ent:NoticeOnce( "Your health has dropped below 30%", GAMEMODE.Colors.Red, 5 ) + ent:NoticeOnce( "Health doesn't regenerate when below 30%", GAMEMODE.Colors.Blue, 5, 2 ) + + end + + if dmginfo:IsDamageType( DMG_BURN ) then + + ent:ViewBounce( 30 ) + + else + + ent:ViewBounce( 25 ) + ent:RadioSound( VO_PAIN ) + ent:DrawBlood() + + end + + if ent:GetPlayerClass() == CLASS_COMMANDO then + + dmginfo:ScaleDamage( GetConVar( "sv_redead_dmg_scale" ):GetFloat() * 0.85 ) + + else + + dmginfo:ScaleDamage( GetConVar( "sv_redead_dmg_scale" ):GetFloat() ) + + end + + if dmginfo:IsExplosionDamage() and attacker:Team() == TEAM_ZOMBIES then + + dmginfo:ScaleDamage( 0 ) + + else + + ent:AddStat( "Damage", math.Round( dmginfo:GetDamage() ) ) + + --[[if attacker:IsPlayer() then + + attacker:AddZedDamage( math.Round( dmginfo:GetDamage() ) ) + + end]] + + end + + elseif ent:IsPlayer() and ent:Team() == TEAM_ZOMBIES and IsValid( attacker ) and attacker:IsPlayer() and dmginfo:GetDamage() > 30 then + + sound.Play( table.Random( GAMEMODE.GoreBullet ), ent:GetPos() + Vector(0,0,50), 75, math.random( 90, 110 ), 0.8 ) + + end + + return self.BaseClass:EntityTakeDamage( ent, dmginfo ) + +end + +function GM:ScaleNPCDamage( npc, hitgroup, dmginfo ) // obsolete! + + if hitgroup == HITGROUP_HEAD then + + npc:EmitSound( "Player.DamageHeadShot" ) + npc:SetHeadshotter( dmginfo:GetAttacker(), true ) + + local effectdata = EffectData() + effectdata:SetOrigin( dmginfo:GetDamagePosition() ) + util.Effect( "headshot", effectdata, true, true ) + + dmginfo:ScaleDamage( math.Rand( 2.50, 3.00 ) ) + dmginfo:GetAttacker():NoticeOnce( "Headshot combos earn you more " .. GAMEMODE.CurrencyName .. "s", GAMEMODE.Colors.Blue, 5 ) + dmginfo:GetAttacker():AddHeadshot() + + elseif hitgroup == HITGROUP_CHEST then + + dmginfo:ScaleDamage( 1.25 ) + + npc:SetHeadshotter( dmginfo:GetAttacker(), false ) + dmginfo:GetAttacker():ResetHeadshots() + + elseif hitgroup == HITGROUP_STOMACH then + + dmginfo:ScaleDamage( 0.75 ) + + npc:SetHeadshotter( dmginfo:GetAttacker(), false ) + dmginfo:GetAttacker():ResetHeadshots() + + else + + dmginfo:ScaleDamage( 0.50 ) + + npc:SetHeadshotter( dmginfo:GetAttacker(), false ) + dmginfo:GetAttacker():ResetHeadshots() + + end + + return dmginfo + +end + +function GM:ScalePlayerDamage( ply, hitgroup, dmginfo ) + + if IsValid( ply.Stash ) then + + return + + end + + if hitgroup == HITGROUP_HEAD then + + ply:EmitSound( "Player.DamageHeadShot" ) + ply:ViewBounce( 25 ) + + dmginfo:ScaleDamage( 1.75 * GetConVar( "sv_redead_dmg_scale" ):GetFloat() ) + + return + + elseif hitgroup == HITGROUP_CHEST then + + ply:ViewBounce( 15 ) + + dmginfo:ScaleDamage( 1.50 * GetConVar( "sv_redead_dmg_scale" ):GetFloat() ) + + return + + elseif hitgroup == HITGROUP_STOMACH then + + dmginfo:ScaleDamage( 1.25 * GetConVar( "sv_redead_dmg_scale" ):GetFloat() ) + + else + + dmginfo:ScaleDamage( 0.50 * GetConVar( "sv_redead_dmg_scale" ):GetFloat() ) + + end + + ply:ViewBounce( ( dmginfo:GetDamage() / 20 ) * 10 ) + +end + +function GM:PlayerShouldTakeDamage( ply, attacker ) + + if ply:Team() == TEAM_UNASSIGNED then return false end + + if IsValid( attacker ) and attacker:IsPlayer() and attacker != ply then + + return ( ply:Team() != attacker:Team() or GetConVar( "sv_redead_team_dmg" ):GetBool() ) + + end + + return true + +end + +function GM:OnDamagedByExplosion( ply, dmginfo ) + + if dmginfo:GetDamage() > 25 then + + ply:SetBleeding( true ) + + end + + ply:SetDSP( 35, false ) + + umsg.Start( "GrenadeHit", ply ) + umsg.End() + +end + +function GM:PlayerDeathThink( ply ) + + if ply.NextSpawn and ply.NextSpawn > CurTime() then return end + + if ply:KeyDown( IN_JUMP ) or ply:KeyDown( IN_ATTACK ) or ply:KeyDown( IN_ATTACK2 ) then + + ply:Spawn() + + end + +end + +function GM:DoPlayerDeath( ply, attacker, dmginfo ) + + ply:OnDeath() + + if ply:Team() == TEAM_ARMY then + + if team.NumPlayers( TEAM_ZOMBIES ) < 1 then + + ply:AddStat( "Martyr" ) + + end + + local music = table.Random( GAMEMODE.DeathMusic ) + + ply:ClientSound( music, 100 ) + ply:RadioSound( VO_DEATH ) + ply:SetTeam( TEAM_ZOMBIES ) + + if not GAMEMODE.LordExists and GAMEMODE.EarlyPick then + + GAMEMODE:PickLord( true ) + + end + + if IsValid( attacker ) and attacker:IsPlayer() and attacker != ply then + + attacker:AddZedDamage( 50 ) + + end + + elseif ply:Team() == TEAM_ZOMBIES then + + if IsValid( attacker ) and attacker:IsPlayer() then + + attacker:AddCash( GAMEMODE.PlayerZombieKillValue ) + attacker:AddFrags( 1 ) + + end + + if ply:IsLord() and ply:GetZedDamage() >= GAMEMODE.RedemptionDamage then + + ply:SetTeam( TEAM_ARMY ) + ply:Notice( "Prepare to respawn as a human", GAMEMODE.Colors.Blue, 5, 2 ) + + end + + end + + if dmginfo:IsExplosionDamage() then + + ply:SetModel( table.Random( GAMEMODE.Corpses ) ) + + local ed = EffectData() + ed:SetOrigin( ply:GetPos() ) + util.Effect( "gore_explosion", ed, true, true ) + + end + + ply:CreateRagdoll() + +end + +function GM:SynchStats() + + net.Start( "StatsSynch" ) + net.WriteInt( table.Count( player.GetAll() ), 8 ) + + for k,v in pairs( player.GetAll() ) do + + net.WriteEntity( v ) + net.WriteTable( v:GetStats() ) + + end + + net.Broadcast() + +end + +function GM:EndGame( winner ) + + GAMEMODE:SynchStats() + + SetGlobalBool( "GameOver", true ) + SetGlobalInt( "WinningTeam", winner ) + + for k,v in pairs( player.GetAll() ) do + + if winner == TEAM_ZOMBIES then + + v:NoticeOnce( "The undead have overwhelmed " .. team.GetName( TEAM_ARMY ) , GAMEMODE.Colors.White, 7, 2 ) + + elseif team.NumPlayers( TEAM_ARMY ) > 0 then + + v:NoticeOnce( team.GetName( TEAM_ARMY ) .. " has successfully evacuated", GAMEMODE.Colors.White, 7, 2 ) + + end + + if v:Team() == winner and winner == TEAM_ARMY then + + local music = table.Random( GAMEMODE.WinMusic ) + + v:ClientSound( music, 100 ) + v:GodEnable() + + else + + local music = table.Random( GAMEMODE.LoseMusic ) + + v:ClientSound( music, 100 ) + + end + + v:NoticeOnce( "Next map: " .. game.GetMapNext() , GAMEMODE.Colors.White, 7, 4 ) + + end + + timer.Simple( GetConVar( "sv_redead_post_game_time" ):GetInt(), function() game.LoadNextMap() end ) + +end + +function GM:CheckGameOver( canend ) + + if GetGlobalBool( "GameOver", false ) then return end + + if team.NumPlayers( TEAM_ARMY ) < 1 and team.NumPlayers( TEAM_ZOMBIES ) > 0 then + + GAMEMODE:EndGame( TEAM_ZOMBIES ) + + elseif GAMEMODE.Wave > #GAMEMODE.Waves and canend then + + for k,v in pairs( team.GetPlayers( TEAM_ARMY ) ) do + + if not v:IsEvacuated() then + + v:Notice( "The evac chopper left without you", GAMEMODE.Colors.Red, 5 ) + v:SetTeam( TEAM_ZOMBIES ) + + end + + end + + GAMEMODE:EndGame( TEAM_ARMY ) + + end + +end + +function GM:ShowHelp( ply ) + + ply:SendLua( "GAMEMODE:ShowHelp()" ) + +end + +function GM:ShowTeam( ply ) + + if ply:Team() == TEAM_ZOMBIES then + + ply:SendLua( "GAMEMODE:ShowZombieClasses()" ) + + return + + end + + if not ply:Alive() then return end + + if ply:IsIndoors() then + + ply:Notice( "You cannot use your radio indoors", GAMEMODE.Colors.Red ) + + else + + if ply:GetPlayerClass() == CLASS_SPECIALIST then + + if IsValid( ply.Stash ) then + + GAMEMODE.SpecialTrader:OnExit( ply ) + + else + + if GAMEMODE.RadioBlock and GAMEMODE.RadioBlock > CurTime() then + + ply:Notice( "Radio communications are offline", GAMEMODE.Colors.Red ) + return + + end + + GAMEMODE.SpecialTrader:OnUsed( ply ) + + end + + else + + if IsValid( ply.Stash ) then + + GAMEMODE.Trader:OnExit( ply ) + + else + + if GAMEMODE.RadioBlock and GAMEMODE.RadioBlock > CurTime() then + + ply:Notice( "Radio communications are offline", GAMEMODE.Colors.Red ) + return + + end + + GAMEMODE.Trader:OnUsed( ply ) + + end + + end + + end + +end + +function GM:ShowSpare1( ply ) + + GAMEMODE:PanicButton( ply ) + +end + +function GM:ShowSpare2( ply ) + + GAMEMODE:AddToZombieList( ply ) + +end + +function GM:PanicButton( ply ) + + if ( ply.Panic or 0 ) > CurTime() or ply:Team() == TEAM_ZOMBIES then return end + + ply.Panic = CurTime() + 0.5 + + local panic = { { ply:IsBleeding(), { "Bandage" }, "bleeding" }, + { ply:GetRadiation() > 0, { "Vodka", "Moonshine Vodka", "Anti-Rad" }, "irradiated" }, + { ply:Health() < 50, { "Advanced Medikit", "Basic Medikit", "Canned Food" }, "severely wounded" }, + { ply:Health() < 100, { "Basic Medikit", "Canned Food" }, "wounded" }, + { ply:GetStamina() < 100, { "Energy Drink" }, "fatigued" }, + { ply:GetStamina() < 100, { "Water" }, "fatigued" } } + + for k,v in pairs( panic ) do + + if v[1] then + + for c,d in pairs( v[2] ) do + + local tbl = item.GetByName( d ) + + if tbl and ply:HasItem( tbl.ID ) then + + tbl.Functions[ 1 ]( ply, tbl.ID ) + + ply:Notice( "Panic button detected that you were " .. v[3], GAMEMODE.Colors.Blue ) + + return + + end + + end + + end + + end + + ply:Notice( "Panic button did not detect any usable items", GAMEMODE.Colors.Red ) + ply:ClientSound( "items/suitchargeno1.wav" ) + +end + +function DropItem( ply, cmd, args ) + + local id = tonumber( args[1] ) + local count = math.Clamp( tonumber( args[2] ), 1, 100 ) + + if not ply:HasItem( id ) then return end + + local tbl = item.GetByID( id ) + + if count == 1 then + + if ply:HasItem( id ) then + + local makeprop = true + + if tbl.DropFunction then + + makeprop = tbl.DropFunction( ply, id, true ) + + end + + if makeprop then + + local prop = ents.Create( "prop_physics" ) + prop:SetPos( ply:GetItemDropPos() ) + prop:SetAngles( ply:GetAimVector():Angle() ) + + if tbl.DropModel then + + prop:SetModel( tbl.DropModel ) + + else + + prop:SetModel( tbl.Model ) + + end + + prop:SetCollisionGroup( COLLISION_GROUP_WEAPON ) + prop:Spawn() + prop.IsItem = true + prop.Removal = CurTime() + 5 * 60 + + end + + ply:RemoveFromInventory( id, true ) + ply:EmitSound( Sound( "items/ammopickup.wav" ) ) + + end + + return + + end + + local itemcount = math.min( ply:GetItemCount( id ), count ) + local loot = ents.Create( "sent_lootbag" ) + + for i=1, itemcount do + + loot:AddItem( id ) + + end + + loot:SetAngles( ply:GetAimVector():Angle() ) + loot:SetPos( ply:GetItemDropPos() ) + loot:SetRemoval( 60 * 5 ) + loot:Spawn() + //loot:SetUser( ply ) + + ply:EmitSound( Sound( "items/ammopickup.wav" ) ) + ply:RemoveMultipleFromInventory( loot:GetItems() ) + + if tbl.DropFunction then + + tbl.DropFunction( ply, id ) + + end + +end + +concommand.Add( "inv_drop", DropItem ) + +function UseItem( ply, cmd, args ) + + local id = tonumber( args[1] ) + local pos = tonumber( args[2] ) + + if ply:HasItem( id ) then + + local tbl = item.GetByID( id ) + + if not tbl.Functions[pos] then return end + + tbl.Functions[pos]( ply, id ) + + end + +end + +concommand.Add( "inv_action", UseItem ) + +function TakeItem( ply, cmd, args ) + + local id = tonumber( args[1] ) + local count = math.Clamp( tonumber( args[2] ), 1, 100 ) + + if not IsValid( ply.Stash ) or not table.HasValue( ply.Stash:GetItems(), id ) or string.find( ply.Stash:GetClass(), "npc" ) then return end + + local tbl = item.GetByID( id ) + + if count == 1 then + + ply:AddIDToInventory( id ) + ply.Stash:RemoveItem( id ) + + return + + end + + local items = {} + + if IsValid( ply.Stash ) then + + for i=1, count do + + if table.HasValue( ply.Stash:GetItems(), id ) then + + table.insert( items, id ) + ply.Stash:RemoveItem( id ) + + end + + end + + ply:AddMultipleToInventory( items ) + ply:EmitSound( Sound( "items/itempickup.wav" ) ) + + end + +end + +concommand.Add( "inv_take", TakeItem ) + +function StoreItem( ply, cmd, args ) + + local id = tonumber( args[1] ) + local count = math.Clamp( tonumber( args[2] ), 1, 100 ) + + if not IsValid( ply.Stash ) or not ply:HasItem( id ) then return end + + local tbl = item.GetByID( id ) + + if count == 1 then + + ply.Stash:AddItem( id ) + + ply:RemoveFromInventory( id ) + ply:EmitSound( Sound( "c4.disarmfinish" ) ) + + if tbl.DropFunction then + + tbl.DropFunction( ply, id ) + + end + + return + + end + + local items = {} + + for i=1, count do + + if ply:HasItem( id ) then + + table.insert( items, id ) + ply.Stash:AddItem( id ) + + end + + end + + ply:RemoveMultipleFromInventory( items ) + ply:EmitSound( Sound( "c4.disarmfinish" ) ) + + if tbl.DropFunction then + + tbl.DropFunction( ply, id ) + + end + +end + +concommand.Add( "inv_store", StoreItem ) + +function SellbackItem( ply, cmd, args ) + + if not IsValid( ply ) then return end + + local id = tonumber( args[1] ) + + if not table.HasValue( ply:GetShipment(), id ) then return end + + local tbl = item.GetByID( id ) + + ply:AddCash( tbl.Price ) + ply:RemoveFromShipment( id ) + +end + +concommand.Add( "inv_refund", SellbackItem ) + +function OrderShipment( ply, cmd, args ) + + ply:SendShipment() + +end + +concommand.Add( "ordershipment", OrderShipment ) + +function BuyItem( ply, cmd, args ) + + local id = tonumber( args[1] ) + local count = tonumber( args[2] ) + + if not IsValid( ply.Stash ) or not ply.Stash:GetClass() == "info_trader" or not table.HasValue( ply.Stash:GetItems(), id ) or count < 0 then return end + + local tbl = item.GetByID( id ) + + if tbl.Price > ply:GetCash() then + + return + + end + + if tbl.Price > ply:GetStat( "Pricey" ) then + + ply:SetStat( "Pricey", tbl.Price ) + + end + + if count == 1 then + + ply:AddToShipment( { id } ) + ply:AddCash( -tbl.Price ) + + return + + end + + if ( tbl.Price * count ) > ply:GetCash() then + + return + + end + + local items = {} + + for i=1, count do + + table.insert( items, id ) + + end + + ply:AddToShipment( items ) + ply:AddCash( -tbl.Price * count ) + +end + +concommand.Add( "inv_buy", BuyItem ) + +function DropCash( ply, cmd, args ) + + local amt = tonumber( args[1] ) + + if amt > ply:GetCash() or amt < 5 then return end + + ply:AddCash( -amt ) + + local money = ents.Create( "sent_cash" ) + money:SetPos( ply:GetItemDropPos() ) + money:Spawn() + money:SetCash( amt ) + +end + +concommand.Add( "cash_drop", DropCash ) + +function StashCash( ply, cmd, args ) + + local amt = tonumber( args[1] ) + + if not IsValid( ply.Stash ) or amt > ply:GetCash() or amt < 5 or string.find( ply.Stash:GetClass(), "npc" ) then return end + + ply:AddCash( -amt ) + ply:SynchCash( ply.Stash:GetCash() + amt ) + ply.Stash:SetCash( ply.Stash:GetCash() + amt ) + +end + +concommand.Add( "cash_stash", StashCash ) + +function TakeCash( ply, cmd, args ) + + local amt = tonumber( args[1] ) + + if not IsValid( ply.Stash ) or amt > ply.Stash:GetCash() or amt < 5 or string.find( ply.Stash:GetClass(), "npc" ) then return end + + ply:AddCash( amt ) + ply:SynchCash( ply.Stash:GetCash() - amt ) + ply.Stash:SetCash( ply.Stash:GetCash() - amt ) + +end + +concommand.Add( "cash_take", TakeCash ) + +function SetPlyClass( ply, cmd, args ) + + local class = tonumber( args[1] ) + + if not GAMEMODE.ClassLogos[ class ] then return end + + if ply:Team() == TEAM_ARMY then return end + + if ply:Team() == TEAM_ZOMBIES then + + ply.NextClass = class + + else + + ply:SetPlayerClass( class ) + + end + +end + +concommand.Add( "changeclass", SetPlyClass ) + +function SaveGameItems( ply, cmd, args ) + + if ( !ply:IsAdmin() or !ply:IsSuperAdmin() ) then return end + + GAMEMODE:SaveAllEnts() + +end + +concommand.Add( "sv_redead_save_map_config", SaveGameItems ) + +function MapSetupMode( ply, cmd, args ) + + if not IsValid( ply ) then + + for k, ply in pairs( player.GetAll() ) do + + if ply:IsAdmin() or ply:IsSuperAdmin() then + + ply:Give( "rad_itemplacer" ) + ply:Give( "rad_propplacer" ) + ply:Give( "weapon_physgun" ) + + end + + end + + return + + end + + if ply:IsAdmin() or ply:IsSuperAdmin() then + + ply:Give( "rad_itemplacer" ) + ply:Give( "rad_propplacer" ) + ply:Give( "weapon_physgun" ) + ply:AddCash( 500 ) + + end + +end + +concommand.Add( "sv_redead_dev_mode", MapSetupMode ) + +function ItemListing( ply, cmd, args ) + + if IsValid( ply ) and ply:IsAdmin() then + + local itemlist = item.GetList() + + for k,v in pairs( itemlist ) do + + print( v.ID .. ": " .. v.Name ) + + end + + end + +end + +concommand.Add( "sv_redead_dev_itemlist", ItemListing ) + +function TestItem( ply, cmd, args ) + + if IsValid( ply ) and ply:IsAdmin() then + + local id = tonumber( args[1] ) + local tbl = item.GetByID( id ) + + if tbl then + + ply:AddIDToInventory( id ) + + end + + end + +end + +concommand.Add( "sv_redead_dev_give", TestItem ) |
