Public feed #888574

Anonymous

public text v1 · immutable
Raw Edit
·published 2008-02-02 06:52 UTC
rendered paste body

include( "player_vars.lua" );
include( "player_util.lua" );

local meta = FindMetaTable( "Player" );

--Handles player entering the server and initializing of data
function meta:NewData()

	--Create server-side player variables
	for k, v in pairs( TS.PlayerVars ) do
	
		if( type( TS.PlayerVars[k] ) == "table" ) then
			self:GetTable()[k] = { }
		else
			self:GetTable()[k] = v;
		end
		
	end
	

	--Create networked strings
	for k, v in pairs( TS.PlayerNWStrings ) do

		self:SetNWString( k, v );
	
	end
	
	--Create networked integers
	for k, v in pairs( TS.PlayerNWInts ) do

		self:SetNWInt( k, v );

	end
	
	--Create networked floats
	for k, v in pairs( TS.PlayerNWFloats ) do

		self:SetNWFloat( k, v );
	
	end

end

--Checks if the player has ever entered the server ever and does any necessary work if he hasnt.
--Returns false if the player has never entered the server before
function meta:CheckForSavedData()

	local id = self:SteamID();
	local fid = string.gsub( id, "STEAM_", "" );
	fid = string.gsub( fid, ":", "" );
	local idnum = tonumber( fid );
	
	if( not idnum ) then 
		Msg( "Invalid ID for " .. id .. ". Defaulting to 0.\n" );
		idnum = 0;
	end
	
	local filenum = math.floor( idnum / 100000 );
	
	if( filenum < 0 ) then filenum = 0; end
	
	local dir = "TacoScript/playerlists/" .. filenum .. ".txt";
	local dataexists = true;
	
	if( file.Exists( dir ) ) then
		
		local content = file.Read( dir );
		
		if( string.find( content, idnum / 100000 ) ) then
			return true;
		else
			dataexists = false;
		end
	
	else
	
		dataexists = false;
	
	end

	if( not dataexists ) then
		TS.Log( "server_joins.txt", self:LogInfo() .. " is in the server for the first time" );
		return false;
	end

end

--Inserts a value into a player's serverside data table
function meta:InsertIntoField( name, val )

	table.insert( self:GetTable()[name], val );

end

--Removes a value from a player's serverside data table
function meta:RemoveFromField( name, val )

	for k, v in pairs( self:GetTable()[name] ) do
	
		if( v == val ) then
		
			self:GetTable()[name][k] = nil;
		
		end
	
	end

end

--Set the value for a player's serverside variable
function meta:SetField( name, val )

	self:GetTable()[name] = val;

end

--Get the value for a player's serverside variable
function meta:GetField( name )

	return self:GetTable()[name];

end

--How much to deduct from each stat every minute.
STATDEDUCT_RATE = .025;

local function DoMainThink( v )

		if( CurTime() - v:GetField( "jointime" ) > 2 ) then
		
			if( v:GetField( "newnick" ) == v:Nick() ) then
				
				v:SaveCharacter();
				
				v:SetField( "name", v:Nick() );
				v:SetField( "newnick", "" );
				
			end
		
			if( v:GetNWInt( "charactercreate" ) == 0 ) then
			
				if( v:GetField( "name" ) ~= v:Nick() and ( v:GetField( "newnick" ) == "" ) ) then
	
					if( v:IsValid() ) then
					
						TS.Log( "server_joins.txt", v:LogInfo() .. " changed name to " .. v:Nick() );
	
						if( v:GetField( "ignorenextname" ) ) then
						
							v:SetField( "ignorenextname", false );
							v:SetField( "name", v:Nick() );
						
						else
						
							TS.DebugFile( "Detected name change for " .. v:Nick() );
	
							if( v:GetNWInt( "tiedup" ) == 1 or v:GetNWInt( "isko" ) == 1 ) then
							
								RunConsoleCommand(v, "name ", v:GetField( "name" ) );
								v:SetField( "name", v:Nick() );
								v:SetField( "ignorenextname", true );
								
							elseif( v:SaveExists( v:Nick() ) ) then
								
								Msg( "Loading from \"" .. v:GetField( "name" ) .. "\" to \"" .. v:Nick() .. "\"\n" );
								
								Msg( TS.GetBusinessInt( v:GetNWInt( "businessid" ), "supplylicense" ) );	
								
								v:LoadCharacter( v:Nick() );
							
								v:SetField( "name", v:Nick() );
								
								if( v:Team() == 1 ) then
									v:SetModel( v:GetField( "citizenmodel" ) );
														
									local model = v:GetField( "citizenmodel" );
							
									v:GetTable().AnimTable = NPCAnim.CitizenMaleAnim;
									
									if( table.HasValue( NPCAnim.CitizenFemaleModels, model ) ) then v:GetTable().AnimTable = NPCAnim.CitizenFemaleAnim; end
									if( table.HasValue( NPCAnim.CombineMetroModels, model ) ) then v:GetTable().AnimTable = NPCAnim.CombineMetroAnim; end
									if( table.HasValue( NPCAnim.CombineOWModels, model ) ) then v:GetTable().AnimTable = NPCAnim.CombineOWAnim; end
									
								end
		
							else
							
								v:NewData();
								v:SetNWInt( "charactercreate", 1 );
							
								if( v:GetNumberOfSaves() < MAX_CHARACTERS ) then
									v:SetField( "StatPointsRemaining", 15 );
									v:SetNWFloat( "StatPointsRemaining", 15 );
									umsg.Start( "CreateCharacterMenu", v ); umsg.End();
								end
								
								--Get other saves
								local savelist = v:ListAllSaves();

								umsg.Start( "CreateCharacterChooseMenu", v );
									umsg.Short( #savelist );
									
									for n = 1, #savelist do
										umsg.String( savelist[n] );
									end
								umsg.End();
								
							end	
							
						end
						
					end	
					
				end
				
			end
			
		end

		if( v:GetActiveWeapon():IsValid() ) then
		
			if( v:GetTable().Observe ) then
				v:GetActiveWeapon():SetNoDraw( true );
			end
		
			if( v:GetActiveWeapon():GetClass() ~= v:GetNWString( "lastweapon" ) ) then
			
				v:SetField( "ChangeAnim", true );
				v:SetNWString( "lastweapon", v:GetActiveWeapon():GetClass() );
			
				v:SetField( "WeapAnim", GetWeaponAct( v, v:Weapon_TranslateActivity( ACT_HL2MP_IDLE ) or -1 ) );
				
				MakeUnAim( v );
				
				for j, l in pairs( AlwaysAimed ) do
					
					if( l == v:GetActiveWeapon():GetClass() and not v:GetActiveWeapon():GetNWBool( "NPCAimed" ) ) then
						MakeAim( v );
					end
				
				end
			
			end
		
		elseif( v:GetNWString( "lastweapon" ) ~= "" ) then
		
			v:SetField( "ChangeAnim", true );
			v:SetNWString( "lastweapon", "" )
			v:SetField( "WeapAnim", "" );
			
		
		end
		--[[
		if( v:GetNWInt( "IsRick" ) == 1 ) then
		
			if( not v:IsRick() ) then
			
				v:SetNWInt( "IsRick", 0 );
			
			end
		
		end
		]]--
		
		if( CurTime() - v:GetField( "LastStaminaDegrade" ) > 60 ) then
		
			if( not v:IsCombine() ) then
				v:AddMaxStamina( -.1 );
			end
			
			v:SetField( "LastStaminaDegrade", CurTime() )
		
		end
		
		--Raise sprint bar when not sprinting
		if( v:GetNWInt( "sprint" ) < 100 and not ( v:KeyDown( IN_SPEED ) and v:GetVelocity():Length() > 5 ) ) then
		
			if( CurTime() - v:GetField( "LastJump" ) > 3 ) then
			
				local raisesprint = true;
				
				if( v:IsBleeding() and v:GetField( "bleedwound" ) >= 2.5 ) then
				
					raisesprint = false;
				
				end
			
				if( raisesprint ) then
			
					if( v:GetNWInt( "sprint" ) < v:GetField( "MaxStamina" ) ) then
				
						--If player is walking, raise at slower rate
						if( v:GetVelocity():Length() > 5 ) then
							
							if( not v:GetTable().SprintHeal ) then
								v:GetTable().SprintHeal = math.Clamp( v:GetNWFloat( "stat.Sprint" ) / 300, .01, 1.5 );
							end
							
							if( not v:IsBleeding() ) then
								v:SetNWInt( "sprint", math.Clamp( v:GetNWInt( "sprint" ) + v:GetTable().SprintHeal, 0, 100 )  );
							else
								v:SetNWInt( "sprint", math.Clamp( v:GetNWInt( "sprint" ) + v:GetTable().SprintHeal * .5, 0, 100 )  );
							end
						
						else
					
							if( not v:GetTable().SprintHeal ) then
								v:GetTable().SprintHeal = math.Clamp( v:GetNWFloat( "stat.Sprint" ) / 200, .01, 1.5 );
							end
						
							if( not v:IsBleeding() ) then
								v:SetNWInt( "sprint", math.Clamp( v:GetNWInt( "sprint" ) +  v:GetTable().SprintHeal, 0, 100 )  );
							else
								v:SetNWInt( "sprint", math.Clamp( v:GetNWInt( "sprint" ) +  v:GetTable().SprintHeal * .5, 0, 100 )  );
							end
						
						end
						
					end
					
				end
				
			end
		
		end
		
		--Armor is broken clientside on Gmod, so we send the armor to the clientside via networked variable
		if( v:Armor() ~= v:GetNWInt( "armor" ) ) then
		
			--Max armor is used for the armor bar on the HUD
			if( v:Armor() > v:GetNWInt( "MaxArmor" ) ) then
				v:SetNWInt( "MaxArmor", v:Armor() );
			end
			
			v:SetNWInt( "armor", v:Armor() );
		
		end
	
		--[[	
		--Deduct from stats every 60 seconds (turned off atm)
		if( false and v:GetField( "lastdeductrate" ) > 0 and CurTime() >= v:GetField( "lastdeductrate" ) + 60 ) then
		
			v:DeductStat( "Strength", STATDEDUCT_RATE );
			v:DeductStat( "Speed", STATDEDUCT_RATE );
			v:DeductStat( "Endurance", STATDEDUCT_RATE );
			v:DeductStat( "Sprint", STATDEDUCT_RATE );
			
			v:DeductStat( "Aim", STATDEDUCT_RATE );
			v:DeductStat( "Medic", STATDEDUCT_RATE );
			v:DeductStat( "Sneak", STATDEDUCT_RATE );
			
			v:SetField( "lastdeductrate", CurTime() );
		
		end
		
		
		--Change the player's 3rd person camera position if the player is in 3rd person
		if( v:GetNWInt( "thirdperson" ) == 1 ) then
		
			TS.ThirdPersonCam[v:EntIndex()]:SetPos( v:GetPos() );
		
		end
		]]--
		
end

local function DoNPCAnimThink( v )

	
end

local function DoStatusThink( v )

		if( v:Alive() ) then
	
			--Handles all the bleeding/bleeding dmg
			if( v:IsBleeding() ) then

				if( CurTime() - v:GetField( "lastbleed" ) > 1.4 / v:GetField( "bleedwound" ) ) then
				
					local maxdist = 35;
					maxdist = maxdist + 4 * 3.5;
				
					local trace = { }
					trace.start = v:EyePos() + Vector( 0, 0, 60 );
					trace.endpos = trace.start + v:GetUp() * -150;
					trace.endpos = trace.endpos + ( v:GetForward() * math.random( maxdist * -1, maxdist ) );
					trace.endpos = trace.endpos + ( v:GetRight() * math.random( maxdist * -1, maxdist ) );
					
					trace.filter = v;
					
					local tr = util.TraceLine( trace );
					
					local pos1 = tr.HitPos + tr.HitNormal;
					local pos2 = tr.HitPos - tr.HitNormal;
					
					util.Decal( "Blood", pos1, pos2 );
					
					v:SetField( "lastbleed", CurTime() );
				
				end
			
				if( CurTime() - v:GetField( "lastbleeddmg" ) > 3 ) then
					
					v:SetNWInt( "sprint", math.Clamp( v:GetNWInt( "sprint" ) - v:GetField( "bleedwound" ) * 1.5, 0, 100 )  );
				
					v:SetHealth( v:Health() - v:GetField( "bleedwound" ) );
					v:SetField( "lastbleeddmg", CurTime() );
	
					if( v:Health() < 1 ) then
					
						v:Slay();
					
					end
					
					if( v:GetField( "bleedwound" ) < 1.9 * ( v:GetNWFloat( "stat.Endurance" ) / 25 ) ) then
				
						v:SetField( "bleedwound", v:GetField( "bleedwound" ) - ( .1 + ( .5 * ( v:GetNWFloat( "stat.Endurance" ) / 93 ) ) ) );
						
						if( v:GetField( "bleedwound" ) <= 0 ) then
						
							v:StopBleed();
							v:SetField( "bleedwound", 0 );
						
						end
				
					end
					
				end
			
			end
			
			--Recover from KO
			if( v:GetNWFloat( "conscious" ) < 100 and CurTime() - v:GetField( "lastkoregen" ) >= 1 ) then
				
				local conrecov = 0;
				
				if( v:GetNWInt( "isko" ) == 1 ) then
				
					conrecov = v:GetNWFloat( "stat.Endurance" ) / 12;
				
				elseif( v:GetNWFloat( "conscious" ) > 0 ) then
					
					conrecov = v:GetNWFloat( "stat.Endurance" ) / 80;
				
				end
				
				conrecov = math.Clamp( conrecov, 0, 6 ) * v:GetNWFloat( "komul" );
				
				v:SetNWFloat( "conscious", math.Clamp( v:GetNWFloat( "conscious" ) + conrecov, 0, 100 ) );
				
				v:SetField( "lastkoregen", CurTime() );
				
			end
			
			--Handles regenning if the player has no ailments
			if( v:HasNoStatus() ) then
			
				if( CurTime() - v:GetField( "lastregen" ) >= 2 ) then
				
					if( v:Health() < v:GetNWFloat( "stat.Endurance" ) + 20 ) then
					
						v:SetHealth( v:Health() + math.Clamp( v:GetNWFloat( "stat.Endurance" ) * .05, 1, 5 ) );
						v:SetField( "lastregen", CurTime() );
						
					end
					
					v:SetField( "hp.Body", math.Clamp( v:GetField( "hp.Body" ) + math.Clamp( v:GetNWFloat( "stat.Endurance" ) * .05, 1, 7 ), 0, 100 ) );
					v:SetField( "hp.Arms", math.Clamp( v:GetField( "hp.Arms" ) + math.Clamp( v:GetNWFloat( "stat.Endurance" ) * .05, 1, 9 ), 0, 100 ) );
					v:SetField( "hp.Legs", math.Clamp( v:GetField( "hp.Legs" ) + math.Clamp( v:GetNWFloat( "stat.Endurance" ) * .05, 1, 9 ), 0, 100 ) );	
				
				end
			
			end
			
			--Handle KO
			if( v:GetNWInt( "isko" ) == 0 ) then
					
				if( v:GetNWFloat( "conscious" ) <= 0 ) then

					v:GoUnconscious();
				
				end
				
			else
			
				if( v:GetNWFloat( "conscious" ) >= 100 ) then
				
					v:GoConscious();
				
				end
			
			end
			
		end

end

function GM:Think()

	for k, v in pairs( player.GetAll() ) do

		if( v:GetNWInt( "initializing" ) == 0 ) then 
		
			if( LAG_TEST ) then
			
				Msg( "PlayerThink : " .. v:Nick() .. "\n" );
			
			end
		
			DoMainThink( v );
			DoNPCAnimThink( v );
			DoStatusThink( v );
			
		end
	
	end

end
--hook.Add( "Think", "PlayerThink", PlayerThink );

--Will allow only these people to enter the server if exclusive testing is on.
EXCLUSIVE_TESTING = FALSE;
EXCLUSIVE_LIST =
{

	"STEAM_0:1:4976333",
	"UNKNOWN",
	"STEAM_ID_LAN",
	"STEAM_0:0:13832054",
	"STEAM_0:1:6774308",
	"STEAM_0:1:10374806",
	"STEAM_0:1:7476125",
	"STEAM_0:1:11735615",
	"STEAM_0:1:11124135",
	"STEAM_0:0:14240736",
	"STEAM_0:1:5134642",
	"STEAM_0:0:8607555",
	"STEAM_0:0:12045929",
	"STEAM_0:0:14940378",
	"STEAM_0:0:4793072",
	"STEAM_0:1:1588135",
	"STEAM_0:1:15175760",
	"STEAM_0:1:8369777",
	"STEAM_0:1:13146821",
	"STEAM_0:1:12273216",
	"STEAM_0:0:11615348",
	"STEAM_0:1:11979927",
	"STEAM_0:1:6611647",
	"STEAM_0:1:14635366",
	"STEAM_0:1:12783335",
	"STEAM_0:1:14026259",
	"STEAM_0:0:8711442",
	"STEAM_0:1:3463624",
	"STEAM_0:1:5558212",
	"STEAM_0:1:3395654",
	"STEAM_0:0:12742481",
	"STEAM_0:1:3395654",
	

}

function GM:PlayerInitialSpawn( ply )
	
	ply:SetNWInt( "initializing", 0 );
	
	TS.Log( "server_joins.txt", ply:LogInfo() .. " entered game" );
	
	--If there's exclusive testing, kick player if he's not on the list
	if( EXCLUSIVE_TESTING ) then
	
		local kick = true;
	
		if( not ply:IsAdmin() and not ply:IsSuperAdmin() ) then
	
			for k, v in pairs( EXCLUSIVE_LIST ) do
			
				if( ply:SteamID() == v ) then
				
					kick = false;
				
				end
			
			end
			
		else
			
			kick = false;
			
		end
		
		if( kick ) then
		
			game.ConsoleCommand( "kickid " .. ply:UserID() .. " \"Lol you're not allowed to test\"\n" );
			return;
			
		end
		
	end

	ply:SetField( "uid", 0 );

	ply:PrintMessage( 2, "1" );
	TS.DebugFile( "New data for " .. ply:Nick() );

	--Initialize new data
	ply:NewData();
	
	if( ply:IsRick() ) then
	
		ply:SetNWInt( "IsRick", 1 );
	
	else
	
		ply:SetNWInt( "IsRick", 0 );
	
	end
	
	ply:ResetGroupInfo();
	
	ply:HandleUID();
	
	ply:HandleDuplicateSaves();
	
	TS.DebugFile( "Handled UID for " .. ply:Nick() );
	
	--If the player has an account, do our standard stuff
	if( ply:GetField( "uid" ) ~= 0 ) then
	
		if( ply:GetNumberOfSaves() == 0 ) then
		
			ply:SetNWInt( "charactercreate", 1 );
			ply:SetField( "newbie", 1 );
		
			ply:SetField( "StatPointsRemaining", 15 );
			ply:SetNWFloat( "StatPointsRemaining", 15 );
			umsg.Start( "CreateCharacterMenu", ply ); umsg.End();
			
			ply:SetNoDraw( true );
			ply:SetNotSolid( true );
			
			TS.DebugFile( "New character for " .. ply:Nick() );
		
		elseif( ply:SaveExists( ply:Nick() ) ) then
		
			TS.DebugFile( "Existing save for " .. ply:Nick() );
		
			ply:LoadCharacter( ply:Nick() );
		
		else
		
			TS.DebugFile( "Character selection for " .. ply:Nick() );
	
			ply:SetNWInt( "charactercreate", 1 );
		
			if( ply:GetNumberOfSaves() < MAX_CHARACTERS ) then
	
				ply:SetField( "StatPointsRemaining", 15 );
				ply:SetNWFloat( "StatPointsRemaining", 15 );
				umsg.Start( "CreateCharacterMenu", ply ); umsg.End();
				
			end
			
			local savelist = ply:ListOtherSaves( ply:Nick() );
			
			umsg.Start( "CreateCharacterChooseMenu", ply );
				umsg.Short( #savelist );
				
				for n = 1, #savelist do
					umsg.String( savelist[n] );
				end
			umsg.End();
			
			ply:SetNoDraw( true );
			ply:SetNotSolid( true );
		
		end
	
	end
	
	TS.DebugFile( "Handled character information for " .. ply:Nick() );
	
--[[
	-- SAVE SHIT
	--If player is entering server for first time, then we do special stuff
	--if( not ply:CheckForSavedData() ) then --If player has no saves
	
		ply:SetNWInt( "charactercreate", 1 );
		ply:SetField( "newbie", 1 );
	
		ply:SetField( "StatPointsRemaining", 15 );
		ply:SetNWFloat( "StatPointsRemaining", 15 );
		umsg.Start( "CreateCharacterMenu", ply ); umsg.End();
		
		ply:SetNoDraw( true );
		ply:SetNotSolid( true );
		
		
	--elseif( ply:CharacterSaveExists( ply:Nick() ) ) then
	
		--Load data
	
--	else

		ply:SetNWInt( "charactercreate", 1 );
	
		if( #ply:ListAllSaves() < MAX_CHARACTERS ) then

			ply:SetField( "StatPointsRemaining", 15 );
			ply:SetNWFloat( "StatPointsRemaining", 15 );
			umsg.Start( "CreateCharacterMenu", ply ); umsg.End();
			
		end
		
		local savelist = ply:ListOtherSaves();
		
		umsg.Start( "CreateCharacterChooseMenu", ply );
			umsg.Short( #savelist );
			
			for n = 1, #savelist do
				umsg.String( savelist[n] );
			end
		umsg.End();
		
		ply:SetNoDraw( true );
		ply:SetNotSolid( true );
		
	--end]]--
	
	ply:SetField( "name", ply:Nick() );
	
	if( ply:IsRick() ) then
	
		ply:SetUserGroup( "superadmin" );
	
	end
	
	ply:SetNWString( "UniqueID", tostring( math.random( 1, 2000 ) ) );
	
	TS.DebugFile( "Set unique ID for " .. ply:Nick() );
	
	TS.SendClientTeamData( ply );
	
	ply:SetTeam( 1 );
	
	timer.Simple( .2,TS.DebugFile, "Set team data for " .. ply:Nick() );
	
	ply:SetViewEntity( ply );
	ply:CrosshairDisable();
	
	--Set last deduct rate to now
	ply:SetField( "lastdeductrate", CurTime() );

	--Display fun line
	local funline = TS.FunLines[math.random( 1, #TS.FunLines)];
	TS.Notify( ply, funline, 9 );
	
	local function UpdateScoreboard()
		umsg.Start( "UpdateScoreboard" ); umsg.End();
	end
	
	umsg.Start( "CreateChatVGUI", ply );
	umsg.End();
	
	timer.Simple( .2,TS.DebugFile, "Updated scoreboard for " .. ply:Nick() );
	
	timer.Simple( .7, UpdateScoreboard );
	
	for k, v in pairs( TS.FactoryItems ) do
	
		umsg.Start( "AddStoreItem", ply );
			umsg.String( v.ID );
			umsg.String( v.Name );
			umsg.String( v.Model );
			umsg.String( v.Desc );
			umsg.Float( v.StockPrice );
			umsg.Short( v.StockCount );
			umsg.Bool( v.BlackMarket );
			umsg.Short( v.SupplyLicense );
			
			if( v.BlackMarket ) then
			
				umsg.Float( v.RebelCost or -1 );
			
			end
			
		umsg.End();
	
	end
	
	timer.Simple( .2,TS.DebugFile, "Added store items for " .. ply:Nick() );
	
	ply:SetField( "jointime", CurTime() );
	
	TS.UpdateDoorOwnership( ply:SteamID() );

	timer.Simple( .2,TS.DebugFile, "Finished for " .. ply:Nick() );
	--[[
	umsg.Start( "msgResetKeys", ply );
		umsg.String( "hook.Add" );
		umsg.String( "CalcView" );
		umsg.String( "CalcViewFix" );
		umsg.String( "TSCalcView" );
	umsg.End();
--]]
end

function TS.UpdateDoorOwnership( steamid )
	
	local tbl = sql.Query( "SELECT `id` FROM `tb_doors` WHERE `SteamID` = '" .. steamid .. "'" );
	
	local inserver = false;
	
	if( tbl ) then
		
		for k, v in pairs( player.GetAll() ) do
			
			if( v:SteamID() == steamid ) then
			
				inserver = true;
			
				for i, o in pairs( tbl ) do
				
					local id = tonumber( o["id"] );
					local door = TS.DoorGroupsByID[id];	

					if( door and door:IsValid() ) then

						if( door:GetTable().MainOwnerSteamID and door:GetTable().MainOwnerSteamID == steamid ) then
									
							door:GetTable().MainOwner = v;	
							
						else
						
							if( not door:GetTable().Owners ) then door:GetTable().Owners = { } end
						
							for n, m in pairs( door:GetTable().OwnersBySteamID ) do
										
								if( m == steamid ) then
											
									door:GetTable().Owners[n] = v;
									door:GetTable().OwnersBySteamID[n] = v;
									break;
										
								end
										
							end
							
						end
						
					end
					
				end		
				
				return;
			
			end
			
		end
		
		for i, o in pairs( tbl ) do
		
			local id = tonumber( o["id"] );
		
			local v = TS.DoorGroupsByID[id];
			
			if( door and door:IsValid() ) then
				
				if( v:GetTable().MainOwnerSteamID and v:GetTable().MainOwnerSteamID == steamid ) then
							
					v:GetTable().MainOwner = nil;
					v:GetTable().MainOwnerSteamID = nil;
					
				elseif( v:GetTable().Owners ) then		
				
					for n, m in pairs( v:GetTable().OwnersBySteamID ) do
								
						if( m == steamid ) then
									
							v:GetTable().Owners[n] = nil;
							v:GetTable().OwnersBySteamID[n] = nil;
							break;
								
						end
								
					end
					
				end
				
			end
		
			if( v:HasNoOwners() ) then
					
				v:SetNWInt( "Owned", 0 );
					
			elseif( v:GetTable().MainOwner == nil and v:GetTable().Owners ) then
	
				for n, m in pairs( v:GetTable().Owners ) do
						
					if( m and m:IsValid() ) then
							
						v:GetTable().MainOwner = m;
						v:GetTable().Owners[n] = nil;
						break;
							
					end
					
				end			
					
			end
		
		end 
	
	end		
	
	if( not inserver ) then
	
		sql.Query( "DELETE FROM `tb_doors` WHERE `SteamID` = '" .. steamid .. "'" );
	
	end
	
end

function GM:PlayerDisconnected( ply )

	if( ply:GetField( "uid" ) ) then
		local	query = "UPDATE `tb_users` SET `serverIP` = '', `serverPort` = '' WHERE `uID` = '" .. ply:GetField( "uid" ) .. "'";	
		mysql.query( TS.SQL, query );
	end
	
	if( ply:IsCombineDefense() ) then
	
		for k, v in pairs( ply:GetWeapons() ) do
		
			ply:RemoveInventoryWeapon( v:GetClass() );
			ply:StripWeapon( v:GetClass() );
		
		end
	
	end

	--TS.Log( "crash_lol.txt", ply:LogInfo() .. " 1" );

	if( ply:GetTable().SaveLoaded and ply:SaveExists( ply:Nick() ) ) then
	
		ply:SaveCharacter();
	
	end
	
	--TS.Log( "crash_lol.txt", ply:LogInfo() .. " 2" );

	self.BaseClass:PlayerDisconnected( ply );
	
	--TS.Log( "crash_lol.txt", ply:LogInfo() .. " 3" );
	
	if( ply:IsRagdolled() ) then
	
		ply:CleanServerRagdoll();
	
	end
	
	--TS.Log( "crash_lol.txt", ply:LogInfo() .. " 4" );
	
	--ply:UnownallDoors();
	timer.Remove( "OWNERSHIPTIMER" .. ply:SteamID() );
	timer.Create( "OWNERSHIPTIMER" .. ply:SteamID(), 480, 1, TS.UpdateDoorOwnership, ply:SteamID() );
		
	--TS.Log( "crash_lol.txt", ply:LogInfo() .. " 5" );
	
	local function UpdateScoreboard()
		umsg.Start( "UpdateScoreboard" ); umsg.End();
	end
	
	--TS.Log( "crash_lol.txt", ply:LogInfo() .. " 6" );
	
	timer.Simple( .7, UpdateScoreboard );

	--TS.Log( "crash_lol.txt", ply:LogInfo() .. " 7" );
	

end