local PlayerMeta = FindMetaTable( "Player" ) util.AddNetworkString('deathmenu') function PlayerMeta:SendMessage( text, duration, color ) if ( !IsValid( self ) ) then return end local duration = duration or 3 local color = color or color_white umsg.Start( "gms_sendmessage", self ) umsg.String( text ) umsg.Short( duration ) umsg.String( color.r .. "," .. color.g .. "," .. color.b .. "," .. color.a ) umsg.End() end function PlayerMeta:OpenCombiMenu( str ) umsg.Start( "gms_OpenCombiMenu", self ) umsg.String( str ) umsg.End() end function PlayerMeta:DeathMenu( res, wep ) net.Start('deathmenu') net.WriteTable(res) net.WriteTable(wep) net.Send(self) end function PlayerMeta:SendAchievement( text ) umsg.Start( "gms_sendachievement", self ) umsg.String( text ) umsg.End() local sound = CreateSound( self, Sound( "music/hl1_song11.mp3" ) ) sound:Play() timer.Simple( 5.5, function() sound:Stop() end ) end function PlayerMeta:SetSkill( skill, int ) skill = string.Capitalize( skill ) if ( !self.Skills[ skill ] ) then self.Skills[ skill ] = 0 end if ( skill != "Survival" ) then int = math.Clamp( int, 0, 200 ) else self.MaxResources = ( int * 5 ) + 25 end self.Skills[ skill ] = int umsg.Start( "gms_SetSkill", self ) umsg.String( skill ) umsg.Short( self:GetSkill( skill ) ) umsg.End() end function PlayerMeta:GetSkill( skill ) skill = string.Capitalize( skill ) if ( skill == "Survival" ) then self:SetNWInt( skill, self.Skills[skill] ) end return self.Skills[ skill ] or 0 end function PlayerMeta:IncSkill( skill, int ) skill = string.Capitalize( skill ) if ( !self.Skills[ skill ] ) then self:SetSkill( skill, 0 ) end if ( !self.Experience[ skill ] ) then self:SetXP( skill, 0 ) end if ( skill != "Survival" ) then int = math.Clamp( int, 0, 200 ) for id = 1, int do self:IncXP( "Survival", 20 ) end self:SendMessage( string.Replace( skill, "_", " " ) .. " +" .. int, 3, Color( 10, 200, 10, 255 ) ) else self.MaxResources = self.MaxResources + 5 self:SendAchievement( "Level Up!" ) end self.Skills[skill] = self.Skills[skill] + int umsg.Start( "gms_SetSkill", self ) umsg.String( skill ) umsg.Short( self:GetSkill( skill ) ) umsg.End() self:CheckForUnlocks() end function PlayerMeta:DecSkill( skill, int ) skill = string.Capitalize( skill ) self.Skills[skill] = math.max( self.Skills[skill] - int, 0 ) umsg.Start( "gms_SetSkill", self ) umsg.String( skill ) umsg.Short( self:GetSkill( skill ) ) umsg.End() end function PlayerMeta:SetXP( skill, int ) skill = string.Capitalize( skill ) if ( !self.Skills[skill] ) then self:SetSkill( skill, 0 ) end if ( !self.Experience[skill] ) then self.Experience[skill] = 0 end self.Experience[skill] = int umsg.Start( "gms_SetXP", self ) umsg.String( skill ) umsg.Short( self:GetXP( skill ) ) umsg.End() end function PlayerMeta:GetXP( skill ) skill = string.Capitalize( skill ) return self.Experience[skill] or 0 end function PlayerMeta:IncXP( skill, int ) skill = string.Capitalize( skill ) if ( !self.Skills[skill] ) then self.Skills[skill] = 0 end if ( !self.Experience[skill] ) then self.Experience[skill] = 0 end if ( self.Experience[skill] + int >= 100 ) then self.Experience[skill] = 0 self:IncSkill( skill, 1 ) else self.Experience[skill] = self.Experience[skill] + int end umsg.Start( "gms_SetXP", self ) umsg.String( skill ) umsg.Short( self:GetXP( skill ) ) umsg.End() end function PlayerMeta:DecXP( skill, int ) skill = string.Capitalize( skill ) self.Experience[skill] = self.Experience[skill] - int umsg.Start( "gms_SetXP", self ) umsg.String( skill ) umsg.Short( self:GetXP( skill ) ) umsg.End() end util.AddNetworkString( "gms_SetResource" ) function PlayerMeta:SetResource( resource, int ) print("SetResource called!") if(isstring(resource)) then resource = GMS.GetResourceByName(resource) end PrintTable(resource) print(int) --if ( !self.Resources[resource] ) then self.Resources[resource] = 0 end --self.Resources[resource] = int if(net.Start("gms_SetResource",false)) then net.WriteString(resource.Name) if(resource.UniqueData) then if(self.Resources[resource.Name] == nil) then self.Resources[resource.Name] = {} end table.insert(self.Resources[resource.Name],resource.UniqueDataID,resource) net.WriteTable(resource) else if(self.Resources[resource.Name] == nil) then self.Resources[resource.Name] = 0 end self.Resources[resource.Name] = int net.WriteInt(int, GMS.NETINT_BITCOUNT) end net.Send(self) else print("Error! could not send resource change data to client: " .. self:GetName()) end end function PlayerMeta:GetResource( resource ) resource = string.Capitalize( resource ) return self.Resources[ resource ] or 0 end function PlayerMeta:IncResource( resource, int ) resource = string.Capitalize( resource ) if ( !self.Resources[resource] ) then self.Resources[resource] = 0 end local all = self:GetAllResources() local max = self.MaxResources print("When adding resources, max resource is:") print(max) print("All is:") print(all) if ( all + int > max ) then self.Resources[resource] = self.Resources[resource] + ( max - all ) self:DropResource( resource, ( all + int ) - max ) self:SendMessage( "You can't carry anymore!", 3, Color( 200, 0, 0, 255 ) ) else self.Resources[resource] = self.Resources[resource] + int end self:SetResource(resource, self:GetResource( resource )) print("Now all is:") print(self:GetAllResources()) end function PlayerMeta:DecResource( resource, int ) if ( self.Resources[resource] == nil ) then self.Resources[resource] = 0 end self.Resources[resource] = self.Resources[resource] - int local r = self.Resources[resource] if ( resource == "Flashlight" and r < 1 ) then self:Flashlight( false ) end if ( resource == "Batteries" ) then local maxPow = 50 if ( r ) then maxPow = math.min( maxPow + r * 50, 500 ) end self.Power = math.min( self.Power, maxPow ) self:UpdateNeeds() end self:SetResource(resource, self:GetResource( resource )) end function PlayerMeta:GetAllResources() print("Totaling data in:") PrintTable(self.Resources) local num = 0 for k, v in pairs( self.Resources ) do num = num + v end print("Total was " .. num) return num end function PlayerMeta:CreateBuildingSite( pos, angle, model, class, cost ) local rep = ents.Create( "gms_buildsite" ) rep:SetPos( pos ) rep:SetAngles( angle ) rep.Costs = cost rep:Setup( model, class ) rep:Spawn() rep.Player = self rep.OwnerTable = { Team = self:Team(), SteamID = self:SteamID(), Name = self:Name(), EntIndex = self:EntIndex() } self:SetNetworkedEntity( "Hasbuildingsite", rep ) SPropProtection.PlayerMakePropOwner( self , rep ) return rep end function PlayerMeta:CreateStructureBuildingSite( pos, angle, model, class, cost, name ) local NoDropModels = { "models/props_c17/furniturefireplace001a.mdl", "models/props_c17/factorymachine01.mdl", "models/Gibs/airboat_broken_engine.mdl", "models/props_c17/furniturestove001a.mdl", "models/props_wasteland/controlroom_desk001b.mdl", "models/props_c17/FurnitureFridge001a.mdl", "models/props_lab/reciever_cart.mdl", "models/props_trainstation/trainstation_clock001.mdl" } local rep = ents.Create( "gms_buildsite" ) local str = ":" for k, v in pairs( cost ) do str = str .. "\n" .. string.Replace( k, "_", " " ) .. " ( " .. v .. "x )" end rep:SetAngles( angle ) rep.Costs = cost rep:Setup( model, class ) rep:SetPos( pos ) rep.Name = name rep:SetNWString( "Name", name ) rep:SetNWString( "Resources", str ) rep:Spawn() local cormin, cormax = rep:WorldSpaceAABB() local offset = cormax - cormin if ( model == "models/props_c17/FurnitureFridge001a.mdl" ) then pos = pos + Vector( 0, 0, 10 ) end rep:SetPos( Vector( pos.x, pos.y, pos.z + ( offset.z / 2 ) ) ) if ( !table.HasValue( NoDropModels, model ) ) then rep:DropToGround() end self:SetNWEntity( "Hasbuildingsite", rep ) rep.Player = self rep.OwnerTable = { Team = self:Team(), SteamID = self:SteamID(), Name = self:Name(), EntIndex = self:EntIndex() } SPropProtection.PlayerMakePropOwner( self, rep ) return rep end function PlayerMeta:GetBuildingSite() return self:GetNWEntity( "Hasbuildingsite" ) end function PlayerMeta:DropResource( resource, int ) print("PlayerMeta:DropResource") print("Resource:" .. resource) print("Ammount:" .. int) local nearby = {} for k, v in pairs( ents.FindByClass( "gms_resource*" ) ) do if ( v:GetPos():Distance( self:GetPos() ) < 150 ) then if ( v:GetClass() == "gms_resourcedrop" and v.Type != resource ) then else table.insert( nearby, v ) end end end for id, ent in pairs( nearby ) do if ( !SPropProtection.PlayerCanTouch( self, ent ) ) then continue end if ( ent:GetClass() == "gms_resourcedrop" ) then ent.Amount = ent.Amount + int ent:SetResourceDropInfoInstant( ent.Type, ent.Amount ) return else if ( !ent.Resources ) then ent.Resources = {} end if ( ent.Resources[ resource ] ) then ent.Resources[ resource ] = ent.Resources[ resource ] + int else ent.Resources[ resource ] = int end ent:SetResPackInfo( resource, ent.Resources[ resource ] ) return end end local ent = ents.Create( "gms_resourcedrop" ) ent:SetPos( self:TraceFromEyes( 60 ).HitPos + Vector( 0, 0, 15 ) ) ent:SetAngles( self:GetAngles() ) ent:Spawn() ent:GetPhysicsObject():Wake() ent.Type = resource ent.Amount = int ent:SetResourceDropInfo( ent.Type, ent.Amount ) SPropProtection.PlayerMakePropOwner( self, ent ) end function PlayerMeta:SetFood( int ) if ( int > 1000 ) then int = 1000 end self.Hunger = int self:UpdateNeeds() end function PlayerMeta:SetThirst( int ) if ( int > 1000 ) then int = 1000 end self.Thirst = int self:UpdateNeeds() end function PlayerMeta:Heal( int ) self:SetHealth( math.min( self:Health() + int, self:GetMaxHealth() ) ) end function PlayerMeta:AddUnlock( text ) self.FeatureUnlocks[text] = 1 umsg.Start( "gms_AddUnlock", self ) umsg.String( text ) umsg.End() if ( GMS.FeatureUnlocks[text].OnUnlock ) then GMS.FeatureUnlocks[text].OnUnlock( self ) end end function PlayerMeta:HasUnlock( text ) if ( self.FeatureUnlocks and self.FeatureUnlocks[text] ) then return true end return false end function PlayerMeta:CheckForUnlocks() for k, unlock in pairs( GMS.FeatureUnlocks ) do if ( !self:HasUnlock( k ) ) then local NrReqs = 0 for skill, value in pairs( unlock.Req ) do if ( self:GetSkill( skill ) >= value ) then NrReqs = NrReqs + 1 end end if ( NrReqs == table.Count( unlock.Req ) ) then self:AddUnlock( k ) end end end end function PlayerMeta:TraceFromEyes( dist ) return util.TraceLine( { start = self:GetShootPos(), endpos = self:GetShootPos() + ( self:GetAimVector() * dist ), filter = self } ) end function PlayerMeta:UpdateNeeds() umsg.Start( "gms_setneeds", self ) umsg.Short( self.Sleepiness ) umsg.Short( self.Hunger ) umsg.Short( self.Thirst ) umsg.Short( self.Oxygen ) umsg.Short( self.Power ) umsg.Short( Time ) umsg.End() end function PlayerMeta:PickupResourceEntity( ent ) if ( !SPropProtection.PlayerCanTouch( self, ent ) ) then return end local int = ent.Amount local room = self.MaxResources - self:GetAllResources() if ( room <= 0 ) then self:SendMessage( "You can't carry anymore!", 3, Color( 200, 0, 0, 255 ) ) return end if ( room < int ) then int = room end ent.Amount = ent.Amount - int if ( ent.Amount <= 0 ) then ent:Fadeout() else ent:SetResourceDropInfo( ent.Type, ent.Amount ) end self:IncResource( ent.Type, int ) self:SendMessage( "Picked up " .. string.Replace( ent.Type, "_", " " ) .. " ( " .. int .. "x )", 4, Color( 10, 200, 10, 255 ) ) end function PlayerMeta:PickupResourceEntityPack( ent ) if ( !SPropProtection.PlayerCanTouch( self, ent ) ) then return end if ( table.Count( ent.Resources ) > 0 ) then for res, int in pairs( ent.Resources ) do local room = self.MaxResources - self:GetAllResources() if ( room <= 0 ) then self:SendMessage( "You can't carry anymore!", 3, Color( 200, 0, 0, 255 ) ) return end if ( room < int ) then int = room end ent.Resources[res] = ent.Resources[res] - int ent:SetResPackInfo( res, ent.Resources[res] ) if ( ent.Resources[res] <= 0 ) then ent.Resources[res] = nil end self:IncResource( res, int ) self:SendMessage( "Picked up " .. string.Replace( res, "_", " " ) .. " ( " .. int .. "x )", 4, Color( 10, 200, 10, 255 ) ) end end end function PlayerMeta:MakeLoadingBar( msg ) umsg.Start( "gms_MakeLoadingBar", self ) umsg.String( msg ) umsg.End() end function PlayerMeta:StopLoadingBar() umsg.Start( "gms_StopLoadingBar",self ) umsg.End() end function PlayerMeta:MakeSavingBar( msg ) umsg.Start( "gms_MakeSavingBar", self ) umsg.String( msg ) umsg.End() end function PlayerMeta:StopSavingBar() umsg.Start( "gms_StopSavingBar", self ) umsg.End() end function PlayerMeta:AllSmelt( ResourceTable ) local resourcedata = {} resourcedata.Req = {} resourcedata.Results = {} local AmountReq = 0 for k, v in pairs( ResourceTable.Req ) do if ( self:GetResource( k ) > 0 ) then if ( self:GetResource( k ) <= ResourceTable.Max ) then resourcedata.Req[k] = self:GetResource( k ) AmountReq = AmountReq + self:GetResource( k ) else resourcedata.Req[k] = ResourceTable.Max AmountReq = AmountReq + ResourceTable.Max self:SendMessage( "You can only do " .. tostring( ResourceTable.Max ) .. " " .. string.Replace( k, "_", " " ) .. " at a time.", 3, Color( 200, 0, 0, 255 ) ) end else resourcedata.Req[k] = 1 end end for k, v in pairs( ResourceTable.Results ) do resourcedata.Results[k] = AmountReq end return resourcedata end function PlayerMeta:Sleep() if ( !self:Alive() or self:GetNWBool( "Sleeping" ) or self:GetNWBool( "AFK" ) ) then return end if ( self.Sleepiness > 700 ) then self:SendMessage( "You're not tired enough.", 3, Color( 255, 255, 255, 255 ) ) return end self:SetNWBool( "Sleeping", true ) self:Freeze( true ) -- Check for shelter local tr = util.TraceLine( { start = self:GetShootPos(), endpos = self:GetShootPos() + ( self:GetUp() * 300 ), filter = self } ) self.NeedShelter = false if ( !tr.HitWorld and !tr.HitNonWorld ) then self.NeedShelter = true end self:EmitSound( "stranded/start_sleeping.wav" ) end function PlayerMeta:Wakeup() if ( !self:GetNWBool( "Sleeping" ) ) then return end self:SetNWBool( "Sleeping", false ) self:Freeze( false ) --Check for shelter local trace = {} trace.start = self:GetShootPos() trace.endpos = trace.start + ( self:GetUp() * 300 ) trace.filter = self local tr = util.TraceLine( trace ) if ( self.NeedShelter ) then self:SendMessage( "I should get something to sleep under next time...", 6, Color( 200, 0, 0, 255 ) ) else self:SendMessage( "Ah, nothing like a good nights sleep!", 5, Color( 255, 255, 255, 255 ) ) end end function PlayerMeta:UpdatePlayerColor() local col = self:GetInfo( "cl_playercolor" ) if ( GetConVarNumber( "gms_TeamColors" ) > 0 ) then local tcol = team.GetColor( self:Team() ) col = tcol.r / 255 .. " " .. tcol.g / 255 .. " " .. tcol.b / 255 end self:SetPlayerColor( Vector( col ) ) end function PlayerMeta:ResetCharacter() self.Skills = {} self.Resources = {} self.Experience = {} self.FeatureUnlocks = {} self:SetSkill( "Survival", 0 ) self:SetXP( "Survival", 0 ) self.MaxResources = 25 self:SaveCharacter() umsg.Start( "gms_ResetPlayer", ply ) umsg.End() end function PlayerMeta:SaveCharacter() if ( !file.IsDir( "gmstranded", "DATA" ) ) then file.CreateDir( "gmstranded" ) end if ( !file.IsDir( "gmstranded/saves", "DATA" ) ) then file.CreateDir( "gmstranded/saves" ) end if ( !self.Loaded ) then print( "Player " .. self:Name() .. " tried to save before he has loaded!" ) self:SendMessage( "Character save failed: Not yet loaded!", 3, Color( 255, 50, 50, 255 ) ) return end local tbl = {} tbl["date"] = os.date( "%A %m/%d/%y" ) tbl["name"] = self:Nick() tbl["skills"] = self.Skills tbl["experience"] = self.Experience tbl["unlocks"] = self.FeatureUnlocks tbl["resources"] = {} tbl["weapons"] = {} tbl["ammo"] = {} for k, v in pairs( self.Resources ) do if ( v > 0 ) then tbl["resources"][ k ] = v end end for id, wep in pairs( self:GetWeapons() ) do if ( wep:GetClass() != "gms_fists" || wep:GetClass() != "weapon_physgun" || wep:GetClass() != "weapon_physcannon" ) then table.insert( tbl[ "weapons" ], wep:GetClass() ) end end local ammo_types = { "ar2", "smg1", "pistol", "buckshot", "357", "grenade", "alyxgun", "xbowbolt", "AlyxGun", "RPG_Round","SMG1_Grenade", "SniperRound", "SniperPenetratedRound", "Grenade", "Thumper", "Gravity", "Battery", "GaussEnergy", "CombineCannon", "AirboatGun", "StriderMinigun", "StriderMinigunDirect", "HelicopterGun", "AR2AltFire", "Grenade", "Hopwire", "CombineHeavyCannon", "ammo_proto1", "slam" } for id, str in pairs( ammo_types ) do local ammo = self:GetAmmoCount( str ) if ( ammo > 0 ) then tbl[ "ammo" ][ str ] = ammo end end file.Write( "gmstranded/saves/" .. self:UniqueID() .. ".txt", util.TableToJSON( tbl ) ) self:SendMessage( "Saved character!", 3, Color( 255, 255, 255 ) ) end function PlayerMeta:DoProcess( name, time, data ) if ( self.InProcess ) then self:SendMessage( "You can't do this much at once.", 3, Color( 200, 0, 0, 255 ) ) return end if ( self:GetNWBool( "AFK" ) ) then self:SendMessage( "You can't do this while afk.", 3, Color( 200, 0, 0, 255 ) ) return end if ( self:GetNWBool( "Sleeping" ) ) then self:SendMessage( "You can't do this while sleeping.", 3, Color( 200, 0, 0, 255 ) ) return end self.ProcessTable = table.Merge( table.Copy( GMS.Processes.BaseProcess ), table.Copy( GMS.Processes[ name ] ) ) self.ProcessTable.Owner = self self.ProcessTable.Time = time self.ProcessTable.StartTime = CurTime() self.ProcessTable.TimerID = self:UniqueID() if ( data ) then self.ProcessTable.Data = data end self.InProcess = true if ( self.ProcessTable.Freeze ) then self:Freeze( true ) end if ( self.ProcessTable.OnStart ) then self.ProcessTable:OnStart() end table.insert( GAMEMODE.ProcessThinkHookTable, self.ProcessTable ) timer.Create( "GMS_ProcessTimer_" .. self:UniqueID(), time, 1, function() self:StopProcess() end ) end function PlayerMeta:MakeProcessBar( name, time, cancel ) umsg.Start( "gms_MakeProcessBar", self ) umsg.String( name ) umsg.Short( time ) umsg.Bool( cancel ) umsg.End() end function PlayerMeta:StopProcessBar() umsg.Start( "gms_StopProcessBar", self ) umsg.End() end function PlayerMeta:StopProcess() if ( !IsValid( self ) or self.ProcessTable == nil ) then return end local bool = self.ProcessTable:BaseStop() if ( self.ProcessTable.Freeze ) then self:Freeze( false ) end if ( self.ProcessTable.OnStop ) then self.ProcessTable:OnStop() end if ( self.ProcessTable.Think ) then GAMEMODE:RemoveProcessThink( self.ProcessTable ) end self.InProcess = false self.ProcessTable = nil end function PlayerMeta:CancelProcess() if ( !self.InProcess ) then return end --If we just clear it out, it should all be good. for i = 1, 10 do if(timer.Exists("GMS_ProcessTimer_" .. i)) then timer.Destroy("GMS_ProcessTimer_" .. i) end end GAMEMODE.ProcessThinkHookTable = {} timer.Destroy("process") self:Freeze(false) self.InProcess = false self:SendMessage( "Cancelled.", 3, Color( 200, 0, 0, 255 ) ) self:StopProcessBar() end