Public feed
#888574
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