Advertisement
Guest User

GHD sv_main.lua

a guest
Jan 2nd, 2012
43
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 51.80 KB | None | 0 0
  1. local GH = GravHull
  2. include('sh_codetools.lua')
  3. GH.HULLS = {} --contains all hull props, used to stop multiple designations
  4. GH.GHOSTS = {} --contains all hull ghosts, used for garbage collection.
  5. GH.SHIPS = {} --a list of all current ships, keyed by their master dampener
  6. GH.Transition = {} --a list of functions to call for certain classes when they are eaten
  7. GH.PHYSGHOSTS = {} --a list of dual-state objects inside or outside a ship
  8. GH.ROCKETHAX = {} --a list of rockets to hax
  9. GH.copyValues = {} --PUT VARIOUS ENTITY VARIABLES IN HERE
  10. hook.Add("Initialize","GravhullTag",function()
  11.     if !string.find(GetConVarString("sv_tags"),"gravhull") then
  12.         RunConsoleCommand("sv_tags",GetConVarString("sv_tags") .. ",gravhull")
  13.     end
  14. end)
  15. cvars.AddChangeCallback("ghd_debugoverrides",function()
  16.     Msg("Gravity Hull Designator - Debug Mode Toggled\nNOTE: Use debug mode if you're getting null entity errors to see where they are coming from. This may lag.")
  17.     GH.DebugOverride = GH.DebugOverrideCV:GetBool()
  18.     GH.GenSimpleOverrides()
  19. end)
  20. ------------------------------------------------------------------------------------------
  21. -- Name: UnHull
  22. -- Desc: Removes a gravity hull.
  23. ------------------------------------------------------------------------------------------
  24. function GH.UnHull(ent)
  25.     if !GH.SHIPS[ent] then return end
  26.     for _,e in pairs(GH.SHIPS[ent].Contents) do
  27.         GH.ShipSpit(ent,e)
  28.     end
  29.     for _,e in pairs(GH.SHIPS[ent].Hull) do
  30.         GH.HULLS[e] = nil
  31.         if ValidEntity(e.Ghost) then
  32.             e.Ghost:DontDeleteOnRemove(e)
  33.             e.Ghost:Remove()
  34.         end
  35.     end
  36.     --take out the trash
  37.     for _,e in pairs(GH.GHOSTS) do
  38.         if ValidEntity(e) and (!ValidEntity(e.MyShip) or !GH.SHIPS[e.MyShip]) then
  39.             e:Remove()
  40.         end
  41.     end
  42.     GH.SHIPS[ent] = nil
  43. end
  44. ------------------------------------------------------------------------------------------
  45. -- Name: ShipObject
  46. -- Desc: Send an object to the client.
  47. ------------------------------------------------------------------------------------------
  48. function GH.ShipObject(p,y,h,e,g)
  49.     umsg.Start("sl_ship_object")
  50.         umsg.Short(p:EntIndex())
  51.         umsg.Bool(y)
  52.         umsg.Bool(h)
  53.         if e then
  54.             umsg.Short(e:EntIndex())
  55.             umsg.Short(g:EntIndex())
  56.         end
  57.     umsg.End()
  58. end
  59. function GH.ClientGhost(ent,ge,e)
  60.     GH.ShipObject(ge,true,true,ent,e)
  61.     if (ValidEntity(ge)) then
  62.         ge:SetColor(255,255,255,255)
  63.         ge:SetMaterial("models/effects/vol_light001")
  64.     end
  65. end
  66. ------------------------------------------------------------------------------------------
  67. -- Name: GhostSetup
  68. -- Desc: Used when creating a hull ghost.
  69. ------------------------------------------------------------------------------------------
  70. function GH.GhostSetup(ent,e,ge,pos,nrm)
  71.     local ang
  72.     if !nrm then nrm = Vector(0,0,1) end
  73.     ge:SetModel(e:GetModel())
  74.     e.Ghost = ge
  75.     if ent == e then
  76.         ge:SetRealPos(pos)
  77.         ge:SetAngles(e:AlignAngles(nrm:Angle(),Vector(0,0,1):Angle()))
  78.     else
  79.         if ValidEntity(ent.Ghost) then
  80.             ge:SetRealPos(ent.Ghost:RealLocalToWorld(ent:RealWorldToLocal(e:GetRealPos())))
  81.             ge:SetAngles(ent.Ghost:RealLocalToWorldAngles(ent:RealWorldToLocalAngles(e:GetRealAngles())))
  82.         else
  83.             local gpos,gang = LocalToWorld(e:GetRealPos(),e:GetRealAngles(),ent:GetRealPos(),ent:GetRealAngles())
  84.             gpos,gang = WorldToLocal(gpos,gang,ent.Ghost:GetRealPos(),ent.Ghost:GetRealAngles())
  85.             ge:SetRealPos(gpos)
  86.             ge:SetAngles(gang)
  87.         end
  88.         e:CallOnRemove("GHUpdateHull",GH.UpdateHull,ent)
  89.     end
  90.     ge:DeleteOnRemove(e)
  91.     ge:Spawn()
  92.     ge:SetColor(0,0,0,0) --temp invisibility until the client sees us
  93.     ge:DrawShadow(false)
  94.     ge:SetCollisionGroup(e:GetCollisionGroup())
  95.     timer.Simple(0,GH.ClientGhost,ent,ge,e) --true invisibility
  96.     local gep = ge:GetPhysicsObject()
  97.     if gep:IsValid() then
  98.         gep:EnableMotion(false)
  99.         gep:SetMass(50000) --the "solid" effect
  100.     end
  101.     if e.IsNotSolid then ge:SetNotSolid(true) end
  102.     for _,v in pairs(GH.copyValues) do
  103.         ge[v] = e[v]
  104.     end
  105.     e:DeleteOnRemove(ge)
  106.     ge.MyShip = ent
  107. end
  108. ------------------------------------------------------------------------------------------
  109. -- Entity Removal Hooks
  110. -- Desc: Fixes for removing things, as well as the explosion fix
  111. ------------------------------------------------------------------------------------------
  112. hook.Add("EntityRemoved","SLDestroyShip",function(ent)
  113.     if GH.SHIPS[ent] then GH.UnHull(ent) end
  114. end)
  115. local explosive_models = kv_swap{
  116.     "models/props_c17/oildrum001_explosive.mdl",
  117.     "models/props_phx/mk-82.mdl",
  118.     "models/props_phx/oildrum001_explosive.mdl",
  119.     "models/props_phx/torpedo.mdl",
  120.     "models/props_phx/ww2bomb.mdl",
  121.     "models/props_phx/misc/flakshell_big.mdl",
  122.     "models/props_phx/amraam.mdl",
  123.     "models/props_phx/cannonball.mdl",
  124.     "models/props_phx/ball.mdl",
  125.     "models/props_junk/gascan001a.mdl",
  126.     "models/props_junk/propane_tank001a.mdl",
  127. }
  128. hook.Add("EntityRemoved","SLBarrelFix",function(ent)
  129. xpcall(function()
  130.     if ent.InShip && ((ent:GetClass() == "prop_physics" && ent:Health() <= 0 && explosive_models[ent:GetModel()]) || ent:GetClass() == "npc_grenade_frag") then
  131.         umsg.Start("sl_ship_explosion")
  132.             umsg.Vector(ent:GetPos())
  133.             umsg.Vector(ent:GetRealPos())
  134.         umsg.End()
  135.     end
  136. end,ErrorNoHalt)
  137. end)
  138. hook.Add("ValidHull","NoPhysbox",function(ent)
  139.     if string.find(ent:GetClass(),"physbox") then return false end
  140. end)
  141. ------------------------------------------------------------------------------------------
  142. -- Name: ConstrainedEntities
  143. -- Desc: Get all entities that are actually physically constrained to ent (not nocollide)
  144. ------------------------------------------------------------------------------------------
  145. function GH.ConstrainedEntities(ent)
  146.     local out = {[ent] = ent}
  147.     local tbtab = {{ent,1}}
  148.     if ent.Constraints then
  149.         while #tbtab > 0 do
  150.             local bd = tbtab[#tbtab]
  151.             local bde = bd[1]
  152.             local bdc = bde.Constraints[bd[2]]
  153.             local ce
  154.             if bdc then
  155.                 if bde == bdc.Ent1 then
  156.                     ce = bdc.Ent2
  157.                 else
  158.                     ce = bdc.Ent1
  159.                 end
  160.             end
  161.             if bd[2] > #bde.Constraints then --last constraint for this entity
  162.                 tbtab[#tbtab] = nil --pop from the stack
  163.             elseif !ValidEntity(bdc) or !ValidEntity(ce) or bdc:GetClass() == "phys_keepupright" or bdc:GetClass() == "logic_collision_pair" then --NULL, skip
  164.                 bd[2] = bd[2] + 1 --next constraint
  165.             else --not keep upright or no collide
  166.                 if !out[ce] then
  167.                     tbtab[#tbtab+1] = {ce,1}
  168.                 else
  169.                     bd[2] = bd[2] + 1 --next constraint
  170.                 end
  171.                 out[bde] = bde
  172.                 out[ce] = ce
  173.             end
  174.         end
  175.     end
  176.     return out
  177. end
  178. ------------------------------------------------------------------------------------------
  179. -- Name: RegisterHull(Entity, Vertical Protrusion Factor, Gravity Percentage)
  180. -- Desc: Begin designation of a hull-- call UpdateHull(ent) to fill in the rest.
  181. ------------------------------------------------------------------------------------------
  182. function GH.RegisterHull(ent,vpf,grav)
  183.     GravHull.SHIPS[ent] = {Hull = {}, Ghosts = {}, Contents = {}, Parts = {}, FloorDist = vpf, Gravity = grav}
  184. end
  185. ------------------------------------------------------------------------------------------
  186. -- Name: UpdateHull
  187. -- Desc: Create or update a gravity hull's ghost, including moving parts.
  188. ------------------------------------------------------------------------------------------
  189. function GH.UpdateHull(ent,gravnormal)
  190.     if !(ValidEntity(ent) and GH.SHIPS[ent]) then return end
  191.     local xcon = GH.ConstrainedEntities(ent) --this is just for the update check
  192.     local gents = GH.SHIPS[ent].Ghosts
  193.     local welds = {[ent] = ent}
  194.     local parts = {}
  195.     local tbtab = {{ent,1}}
  196.     local weldpass = false
  197.     --THE HULL SCANNER
  198.     -------------------
  199.     --Adds any prop connected solidly to ent as part of its hull,
  200.     --and any prop connected with a nonsolid constraint to the parts list.
  201.     --Also adds other constrained hulls as special parts.
  202.     if ent.Constraints then
  203.         while #tbtab > 0 do
  204.             local bd = tbtab[#tbtab]
  205.             local bde = bd[1]
  206.             local bdc = bde.Constraints[bd[2]]
  207.             local ce
  208.             if bdc then
  209.                 if bde == bdc.Ent1 then
  210.                     ce = bdc.Ent2
  211.                 else
  212.                     ce = bdc.Ent1
  213.                 end
  214.             end
  215.             if bd[2] > #bde.Constraints then --last constraint for this entity
  216.                 tbtab[#tbtab] = nil --pop from the stack
  217.                 if #tbtab == 0 and !weldpass then
  218.                     weldpass = true
  219.                     tbtab = {{ent,1}}
  220.                 end
  221.             elseif !ValidEntity(bdc) or !ValidEntity(ce) then --NULL, skip
  222.                 bd[2] = bd[2] + 1 --next constraint
  223.             elseif GH.HULLS[ce] and !GH.SHIPS[ent].Hull[ce] and bdc:GetClass() != "logic_collision_pair" then --connecting another hull ghost, not a nocollide
  224.                 bd[2] = bd[2] + 1 --next constraint
  225.                 parts[ce] = ce --add to the parts list
  226.             elseif bdc:GetClass() == "phys_constraint" then --weld/nail
  227.                 if weldpass then
  228.                     if !welds[ce] then
  229.                         tbtab[#tbtab+1] = {ce,1}
  230.                     else
  231.                         bd[2] = bd[2] + 1 --next constraint
  232.                     end
  233.                     parts[bde] = nil
  234.                     parts[ce] = nil
  235.                     welds[bde] = bde
  236.                     welds[ce] = ce
  237.                 else
  238.                     if !parts[ce] then
  239.                         tbtab[#tbtab+1] = {ce,1}
  240.                     else
  241.                         bd[2] = bd[2] + 1 --next constraint
  242.                     end
  243.                     parts[bde] = bde
  244.                     parts[ce] = ce
  245.                 end
  246.             elseif !weldpass and bdc:GetClass() != "phys_keepupright" and bdc:GetClass() != "logic_collision_pair" then --not keep upright or no collide, must be a nonfixed constraint
  247.                 if !parts[ce] then
  248.                     tbtab[#tbtab+1] = {ce,1}
  249.                 else
  250.                     bd[2] = bd[2] + 1 --next constraint
  251.                 end
  252.                 parts[bde] = bde
  253.                 parts[ce] = ce
  254.             else --some other constraint
  255.                 bd[2] = bd[2] + 1 --skip, go to the next constraint
  256.             end
  257.         end
  258.     end
  259.     for k,e in pairs(welds) do
  260.         if !(ValidEntity(e) && e:GetModel() && e:GetMoveType() == MOVETYPE_VPHYSICS && e:GetPhysicsObjectCount() == 1 && hook.Call("ValidHull",nil,e) != false) then
  261.             welds[k]=nil
  262.         end
  263.     end
  264.     local pos = vector_origin
  265.     local rad = 0
  266.     local amt = 0
  267.     for _,p in pairs(welds) do
  268.         if ValidEntity(p) then
  269.             pos = pos + p:GetRealPos()
  270.             amt = amt + 1
  271.         end
  272.     end
  273.     if amt > 0 then pos = pos / amt end
  274.     for _,p in pairs(welds) do
  275.         if ValidEntity(p) then
  276.             local mrad = p:GetRealPos():Distance(pos) + p:BoundingRadius()
  277.             if mrad > rad then rad = mrad end
  278.         end
  279.     end
  280.     local npos = GH.SHIPS[ent].NPos or GH.FindNowhere(rad)
  281.     for k,e in pairs(GH.SHIPS[ent].Hull) do
  282.         if !welds[e] then
  283.             GH.HULLS[e] = nil
  284.             GH.SHIPS[ent].Hull[k] = nil
  285.             if ValidEntity(e) and ValidEntity(e.Ghost) then
  286.                 e.Ghost:DontDeleteOnRemove(e)
  287.                 e.Ghost:Remove() --WHO YOU GONNA CALL?
  288.             end
  289.         end
  290.     end
  291.     for _,e in pairs(GH.SHIPS[ent].Parts) do
  292.         if !parts[e] && ValidEntity(e.SLMyGhost) then
  293.             GH.DisablePhysGhost(e,e.SLMyGhost)
  294.         end
  295.     end
  296.     if !ValidEntity(GH.SHIPS[ent].MainGhost) then
  297.         local mg = ents.Create("prop_physics")
  298.         GH.GhostSetup(ent,ent,mg,npos,gravnormal)
  299.         GH.GHOSTS[mg] = mg
  300.         GH.HULLS[ent] = ent
  301.         gents[mg] = ent
  302.         GH.SHIPS[ent].MainGhost = mg
  303.     end
  304.     for _,e in pairs(welds) do
  305.         if ent != e and !ValidEntity(GH.HULLS[e]) and ValidEntity(e) then --if something's already part of a hull, don't ghost it
  306.             local ge = ents.Create("prop_physics")
  307.             GH.GhostSetup(ent,e,ge,npos,gravnormal)
  308.             GH.GHOSTS[ge] = ge
  309.             GH.HULLS[e] = e
  310.             gents[ge] = e
  311.             if ent == e then
  312.                 GH.SHIPS[ent].MainGhost = ge
  313.             end
  314.         end
  315.     end
  316.     for _,e in pairs(parts) do
  317.         GH.PhysGhost(ent,e).Permanent = true
  318.     end
  319.     GH.SHIPS[ent].Hull = welds
  320.     GH.SHIPS[ent].Parts = parts
  321.     GH.SHIPS[ent].Welds = xcon
  322.     GH.SHIPS[ent].NPos = npos
  323.     GH.SHIPS[ent].Ghosts = gents
  324.     GH.SHIPS[ent].Center = ent:WorldToLocal(pos)
  325.     GH.SHIPS[ent].Radius = rad
  326.     GH.SHIPS[ent].Volume = {}
  327. end
  328. ------------------------------------------------------------------------------------------
  329. -- Name: FindNowhere
  330. -- Desc: Find a place to put the ghost ship.
  331. ------------------------------------------------------------------------------------------
  332. function GH.FindNowhere(rad)
  333.     local nowhere = vector_origin
  334.     --local skycam = ents.FindByClass("sky_camera")[1]
  335.     --if ValidEntity(skycam) then skycam = skycam:GetRealPos() else skycam = nil end
  336.     while !((util.PointContents(nowhere) == CONTENTS_EMPTY or util.PointContents(nowhere) == CONTENTS_TESTFOGVOLUME) and
  337.             !util.TraceHull{start=nowhere,endpos=nowhere,mins=Vector(1,1,1)*-rad,maxs=Vector(1,1,1)*rad,mask = MASK_SOLID + CONTENTS_WATER}.Hit and --HIT EVERYTHING
  338.             hook.Call("AllowGhostSpot",nil,nowhere) != false)do--and (!skycam or util.RealTraceLine{start=nowhere,endpos=skycam,mask=MASK_NPCWORLDSTATIC}.Hit)) do
  339.         nowhere = Vector(math.random(-16384,16384),math.random(-16384,16384),math.random(-16384,16384))
  340.     end
  341.     return nowhere
  342. end
  343. ------------------------------------------------------------------------------------------
  344. -- Name: sl_antiteleport
  345. -- Desc: Used by the client to stop SetPos packet loss
  346. ------------------------------------------------------------------------------------------
  347. concommand.Add("sl_antiteleport",function(p)
  348.     if !p.AntiTeleportPos then return end
  349.     if (p:GetRealPos():Distance(p.AntiTeleportPos) > 3000) and !p:InVehicle() then
  350.         p:SetRealPos(p.AntiTeleportPos)
  351.         SendUserMessage("sl_antiteleport_cl",p,p.AntiTeleportPos) --pingpong until they're where they should be
  352.     else
  353.         p.AntiTeleportPos = nil
  354.     end
  355. end)
  356. ------------------------------------------------------------------------------------------
  357. -- Name: sl_external_use
  358. -- Desc: Sent by the client to use an object while inside a hull
  359. ------------------------------------------------------------------------------------------
  360. concommand.Add("sl_external_use",function(p)
  361.     if !(p.InShip and GH.SHIPS[p.InShip]) then return end
  362.     local tr = p:GetEyeTrace()
  363.     if p:GetPos():Distance(tr.HitPos) < 140 && tr.Entity.InShip != p.InShip then
  364.         local e = tr.Entity
  365.         if e:IsVehicle() then
  366.             timer.Simple(0.2,p.EnterVehicle,p,e)
  367.         elseif e.Use then
  368.             e:Use(p,p)
  369.         else
  370.             e:Fire("Use","1",0)
  371.         end
  372.         WorldSound("common/wpn_select.wav",e:GetPos(),60,100)
  373.     end
  374. end)
  375. ------------------------------------------------------------------------------------------
  376. -- Name: SLToolFix
  377. -- Desc: Stops tools on physghosts, then manually recreates it with a transformed trace
  378. ------------------------------------------------------------------------------------------
  379. hook.Add("CanTool","SLToolFix",function(pl,tr,tm,nope)
  380.     if nope == "SLToolFix" then return end
  381.     local can = hook.Call("CanTool",GAMEMODE,pl,tr,tm,"SLToolFix")
  382.     if !can then return false end
  383.     if ValidEntity(tr.Entity) and tr.Entity.SLIsGhost and ValidEntity(tr.Entity.SLMyGhost) and ValidEntity(tr.Entity.SLMyGhost.InShip) then --hit a physghost that's in a ship
  384.         local tool = pl:GetActiveWeapon():GetToolObject()
  385.         local dofx = false
  386.         local ttr = GH.GetInteriorEyeTrace(tr.Entity.SLMyGhost.InShip, pl)
  387.         if hook.Call("CanTool",GAMEMODE,pl,ttr,tm,"SLToolFix") == false then return end
  388.         if !pl:KeyDownLast(IN_ATTACK) and pl:KeyDown(IN_ATTACK) then
  389.             dofx = tool:LeftClick(ttr)
  390.         elseif !pl:KeyDownLast(IN_ATTACK2) and pl:KeyDown(IN_ATTACK2) then
  391.             dofx = tool:RightClick(ttr)
  392.         elseif !pl:KeyDownLast(IN_RELOAD) and pl:KeyDown(IN_RELOAD) then
  393.             dofx = tool:Reload(ttr)
  394.         end
  395.         if dofx then
  396.             umsg.Start("sl_fake_tooltrace")
  397.                 umsg.Entity(pl:GetActiveWeapon())
  398.                 umsg.Entity(tr.Entity)
  399.                 umsg.Vector(tr.HitPos)
  400.                 umsg.Vector(tr.HitNormal)
  401.                 umsg.Short(tr.PhysicsBone)
  402.             umsg.End()
  403.         end
  404.         return false --don't do the normal tool stuff
  405.     end
  406. end)
  407. ------------------------------------------------------------------------------------------
  408. -- Name: AntiTeleport
  409. -- Desc: Start the AntiTeleport handshake
  410. ------------------------------------------------------------------------------------------
  411. function GH.AntiTeleport(p,ppos)
  412.     if !p:Alive() or p:InVehicle() then return end
  413.     p.AntiTeleportPos = ppos
  414.     SendUserMessage("sl_antiteleport_cl",p,p.AntiTeleportPos)
  415. end
  416. local never_eat = kv_swap{
  417.     "physgun_beam"
  418. }
  419. function GH.Transition:gmod_hoverball(old,new,oldpos,oldang)
  420.     self.dt.TargetZ = new:LocalToWorld(old:WorldToLocal(Vector(oldpos.x,oldpos.y,self.dt.TargetZ))).z
  421. end
  422. function GH.Transition:rpg_missile()
  423.     local ply = GH.ROCKETHAX[self] or self:GetOwner()
  424.     if ValidEntity(ply) and (ply.InShip or self.InShip) then
  425.         GH.ROCKETHAX[self] = ply
  426.         self:SetOwner(NULL)
  427.         self.Attacker = ply
  428.     else
  429.         GH.ROCKETHAX[self] = nil
  430.         self:SetOwner(ply)
  431.     end
  432. end
  433. local function FixMass(p)
  434.     if p.HeldBone and p.OldMass and p:GetPhysicsObjectNum(p.HeldBone):IsValid() then
  435.         p:GetPhysicsObjectNum(p.HeldBone):SetMass(p.OldMass)
  436.         if ValidEntity(p.SLMyGhost) and p.SLMyGhost:GetPhysicsObjectNum(p.HeldBone):IsValid() then
  437.             p.SLMyGhost:GetPhysicsObjectNum(p.HeldBone):SetMass(p.OldMass)
  438.         end
  439.     end
  440. end
  441. NO_VEL = 1
  442. ------------------------------------------------------------------------------------------
  443. -- Name: ShipEat
  444. -- Desc: Put an entity inside a ship.
  445. ------------------------------------------------------------------------------------------
  446. function GH.ShipEat(e,p,nm)
  447.     if !GH.SHIPS[e] then return end
  448.     if !ValidEntity(p) then return end
  449.     if p.SLIsGhost then return end
  450.     if p:IsWorld() then return end
  451.     if p.InShip == e then return end
  452.     if never_eat[p:GetClass()] then return end
  453.     local g = GH.SHIPS[e].MainGhost
  454.     p.InShip = e
  455.     GH.SHIPS[e].Contents[p] = p
  456.     local oldpos,oldang = p:GetRealPos(),p:GetRealAngles()
  457.     if (nm!=true) or (e:GetPos() and !e.UsedFakePos) then
  458.         if p:IsPlayer() then
  459.             if ValidEntity(p.Holding) then
  460.                 FixMass(p.Holding)
  461.                 p:Freeze(true)
  462.                 timer.Simple(0.02,p.Freeze,p,false)
  463.                 if p.Holding.SLIsGhost then
  464.                     GH.DisablePhysGhost(p.Holding,p.Holding.SLMyGhost)
  465.                 end
  466.             end
  467.             local ppos = g:RealLocalToWorld(e:RealWorldToLocal(p:GetRealPos()+p:OBBCenter()))
  468.             ppos = util.TraceLine{start = ppos, endpos = ppos+Vector(0,0,p:OBBMaxs().z)}.HitPos-Vector(0,0,p:OBBMaxs().z)
  469.             ppos = util.TraceLine{start = ppos, endpos = ppos-p:OBBCenter()}.HitPos
  470.             p.OldGravity = p:GetGravity()
  471.             if GH.SHIPS[e].Gravity == 0 then --fixes the "can't have 0 gravity" problem
  472.                 p:SetGravity(0.0000001)
  473.             else
  474.                 p:SetGravity((GH.SHIPS[e].Gravity or 100) / 100)
  475.             end
  476.             p:SetRealPos(ppos)
  477.             GH.AntiTeleport(p,ppos)
  478.             if nm == 1 then
  479.                 p:SetLocalVelocity(g:RealLocalToWorld(e:RealWorldToLocal(p:GetRealVelocity()+e:GetRealPos()))-g:GetRealPos())
  480.             else
  481.                 p:SetLocalVelocity(g:RealLocalToWorld(e:RealWorldToLocal((p:GetRealVelocity()-e:GetRealVelocity())+e:GetRealPos()))-g:GetRealPos())
  482.             end
  483.             local pa = g:RealLocalToWorldAngles(e:RealWorldToLocalAngles(p:EyeAngles()))
  484.             p:SetEyeAngles(pa)
  485.             p.SLRollFix = true
  486.             if ValidEntity(p.RocketHax) then
  487.                 GH.ROCKETHAX[p.RocketHax] = p
  488.                 p.RocketHax:SetOwner(NULL)
  489.                 p.RocketHax.Attacker = ply
  490.             end
  491.         elseif p:IsNPC() then
  492.             p:SetRealPos(g:RealLocalToWorld(e:RealWorldToLocal(p:GetRealPos()+p:OBBCenter()))-p:OBBCenter())
  493.             p:SetLocalVelocity(g:RealLocalToWorld(e:RealWorldToLocal(p:GetRealVelocity()+e:GetRealPos()))-g:GetRealPos())
  494.         else
  495.             local i
  496.             local pv,pp,pa = {},{},{}
  497.             for i=1,p:GetPhysicsObjectCount() do
  498.                 local po = p:GetPhysicsObjectNum(i-1)
  499.                 if po:IsValid() then
  500.                     if nm == 1 then
  501.                         pv[i] = g:RealLocalToWorld(e:RealWorldToLocal(po:GetVelocity()+e:GetRealPos()))-g:GetRealPos()
  502.                     else
  503.                         pv[i] = g:RealLocalToWorld(e:RealWorldToLocal((po:GetVelocity()-e:GetRealVelocity())+e:GetRealPos()))-g:GetRealPos()
  504.                     end
  505.                     if (p:GetPhysicsObjectCount() > 1) then
  506.                         pp[i] = g:RealLocalToWorld(e:RealWorldToLocal(po:GetPos()))
  507.                         pa[i] = g:RealLocalToWorldAngles(e:RealWorldToLocalAngles(po:GetAngle()))
  508.                     end
  509.                 end
  510.             end
  511.             p:SetRealPos(g:RealLocalToWorld(e:RealWorldToLocal(p:GetRealPos())))
  512.             p:SetAngles(g:RealLocalToWorldAngles(e:RealWorldToLocalAngles(p:GetRealAngles())))
  513.             if p:GetPhysicsObjectCount() > 1 then
  514.                 for i=1,p:GetPhysicsObjectCount() do
  515.                     local po = p:GetPhysicsObjectNum(i-1)
  516.                     if (po:IsValid()) then
  517.                         po:SetPos(pp[i])
  518.                         po:SetAngle(pa[i])
  519.                     end
  520.                 end
  521.             end
  522.             for i=1,p:GetPhysicsObjectCount() do
  523.                 local po = p:GetPhysicsObjectNum(i-1)
  524.                 if po:IsValid() then
  525.                     po:SetVelocity(pv[i])
  526.                 end
  527.             end
  528.             local pg = GH.PHYSGHOSTS[p]
  529.             if ValidEntity(p.HeldBy) && p.HeldBy.InShip != e then
  530.                 FixMass(p)
  531.                 GH.PhysGhost(e,p).Expire = CurTime()+0.5
  532.                 p.HeldBy:Freeze(true)
  533.                 timer.Simple(0.02,p.HeldBy.Freeze,p.HeldBy,false)
  534.             elseif ValidEntity(pg) && ValidEntity(pg.HeldBy) && pg.HeldBy.InShip == e then
  535.                 FixMass(pg)
  536.                 GH.DisablePhysGhost(p,pg)
  537.                 pg.HeldBy:Freeze(true)
  538.                 timer.Simple(0.02,pg.HeldBy.Freeze,pg.HeldBy,false)
  539.             end
  540.         end
  541.     end
  542.     GH.ShipObject(p,true,false,e,g)
  543.     if GH.Transition[p:GetClass()] then GH.Transition[p:GetClass()](p,e,g,oldpos,oldang) end
  544.     hook.Call("EnterShip",nil,p,e,g,oldpos,oldang)
  545. end
  546. ------------------------------------------------------------------------------------------
  547. -- Name: ShipSpit
  548. -- Desc: Remove an entity from a ship.
  549. ------------------------------------------------------------------------------------------
  550. function GH.ShipSpit(e,p,nm,nog,nt)
  551.     if !GH.SHIPS[e] then return end
  552.     local g = GH.SHIPS[e].MainGhost
  553.     if !ValidEntity(p) then return end
  554.     if p.SLIsGhost then return end
  555.     GH.SHIPS[e].Contents[p] = nil
  556.     local oldpos,oldang = p:GetRealPos(),p:GetRealAngles()
  557.     if p:IsPlayer() then
  558.         if ValidEntity(p.Holding) then
  559.             FixMass(p.Holding)
  560.             p:Freeze(true)
  561.             timer.Simple(0.02,p.Freeze,p,false)
  562.         end
  563.         p:SetGravity(p.OldGravity)
  564.         p.OldGravity = nil
  565.         local ppos,pang = WorldToLocal(p:GetRealPos()+p:OBBCenter(), p:EyeAngles(), g:GetRealPos(), g:GetRealAngles())
  566.         ppos,pang = LocalToWorld(ppos,pang,e:GetPos(),e:GetAngles())
  567.         ppos = util.TraceLine{start = ppos, endpos = ppos+Vector(0,0,p:OBBMaxs().z)}.HitPos-Vector(0,0,p:OBBMaxs().z)
  568.         ppos = util.TraceLine{start = ppos, endpos = ppos-p:OBBCenter()}.HitPos
  569.         p.InShip = nil
  570.         p:SetPos(ppos)
  571.         if !nt then
  572.             GH.AntiTeleport(p,ppos)
  573.         end
  574.         local pvel = WorldToLocal(p:GetRealVelocity(),Angle(0,0,0),vector_origin,g:GetRealAngles())
  575.         pvel = LocalToWorld(pvel,Angle(0,0,0),vector_origin,e:GetAngles())
  576.         p:SetLocalVelocity(pvel+e:GetVelocity())
  577.         p:SetEyeAngles(pang)
  578.         p.SLRollFix = true
  579.     elseif p:IsNPC() then
  580.         p:SetRealPos(e:LocalToWorld(g:WorldToLocal(p:GetRealPos()+p:OBBCenter()))-p:OBBCenter())
  581.     else
  582.         local i
  583.         local pv,pp,pa = {},{},{}
  584.         for i=1,p:GetPhysicsObjectCount() do
  585.             local po = p:GetPhysicsObjectNum(i-1)
  586.             if po:IsValid() then
  587.                 pv[i] = e:RealLocalToWorld(g:RealWorldToLocal(po:GetVelocity()+g:GetRealPos()))-e:GetRealPos()
  588.                 if (p:GetPhysicsObjectCount() > 1) then
  589.                     pp[i], pa[i] = WorldToLocal(po:GetPos(),po:GetAngle(),g:GetRealPos(),g:GetRealAngles())
  590.                     pp[i], pa[i] = LocalToWorld(pp[i], pa[i], e:GetPos(), e:GetAngles())
  591.                 end
  592.             end
  593.         end
  594.         local ppos,pang = WorldToLocal(p:GetRealPos(),p:GetRealAngles(),g:GetRealPos(),g:GetRealAngles())
  595.         ppos,pang = LocalToWorld(ppos,pang,e:GetPos(),e:GetAngles())
  596.         p:SetRealPos(ppos)
  597.         p:SetAngles(pang)
  598.         if p:GetPhysicsObjectCount() > 1 then
  599.             for i=1,p:GetPhysicsObjectCount() do
  600.                 local po = p:GetPhysicsObjectNum(i-1)
  601.                 if (po:IsValid()) then
  602.                     po:SetPos(pp[i])
  603.                     po:SetAngle(pa[i])
  604.                 end
  605.             end
  606.         end
  607.         for i=1,p:GetPhysicsObjectCount() do
  608.             local po = p:GetPhysicsObjectNum(i-1)
  609.             if po:IsValid() then
  610.                 po:SetVelocity(pv[i]+e:GetVelocity())
  611.             end
  612.         end
  613.         if !nog then
  614.             local pg = GH.PHYSGHOSTS[p]
  615.             if ValidEntity(p.HeldBy) && p.HeldBy.InShip == e then
  616.                 FixMass(p)
  617.                 p.InShip = nil
  618.                 GH.PhysGhost(e,p).Expire = CurTime()+0.5
  619.                 p.HeldBy:Freeze(true)
  620.                 timer.Simple(0.02,p.HeldBy.Freeze,p.HeldBy,false)
  621.             elseif ValidEntity(pg) && ValidEntity(pg.HeldBy) && !pg.HeldBy.InShip then
  622.                 FixMass(pg)
  623.                 GH.DisablePhysGhost(p,pg)
  624.                 pg.HeldBy:Freeze(true)
  625.                 timer.Simple(0.02,pg.HeldBy.Freeze,pg.HeldBy,false)
  626.             end
  627.         end
  628.     end
  629.     p.InShip = nil
  630.     if ValidEntity(e.InShip) and GH.SHIPS[e.InShip] then
  631.         GH.ShipEat(e.InShip,p)
  632.     else
  633.         local do_send = true
  634.         for ent,d in pairs(GH.SHIPS) do --check for other cantidates
  635.             ent.SLLastFind[#ent.SLLastFind+1] = p --tell every ship that we MIGHT be near them
  636.             if e != ent and GH.TryEat(ent,p,d) then
  637.                 do_send = false
  638.                 break
  639.             end
  640.         end
  641.         if do_send then
  642.             GH.ShipObject(p,false,false)
  643.         end
  644.     end
  645.     if GH.Transition[p:GetClass()] then GH.Transition[p:GetClass()](p,g,e,oldpos,oldang) end
  646.     hook.Call("ExitShip",nil,p,e,g,oldpos,oldang)
  647. end
  648. local NotRagdolls = {}
  649. function GH.IsRagdoll(p)
  650.     if NotRagdolls[p:GetClass()] then return false end
  651.     if p:GetPhysicsObjectCount() <= 1 then return false end
  652.     if p:IsVehicle() then return false end
  653.     return true
  654. end
  655. local function GhostDelete(ent)
  656.     local re = ent.SLMyGhost
  657.     GH.PHYSGHOSTS[re] = nil
  658.     if ValidEntity(re) then
  659.         re.SLMyGhost = nil
  660.         re.SLHull = nil
  661.     end
  662. end
  663. local dont_ghost = kv_swap{"sbep_elev_system","func_physbox"}
  664. hook.Add("CanPhysghost","BrokenGhosts",function(ent,p)
  665.     if dont_ghost[p:GetClass()] then return false end
  666. end)
  667. ------------------------------------------------------------------------------------------
  668. -- Name: PhysGhost
  669. -- Desc: Create a Physghost for a prop.
  670. ------------------------------------------------------------------------------------------
  671. function GH.PhysGhost(ent,p)
  672.     if ent == p then return {} end
  673.     if p.SLIsGhost then return {} end
  674.     local data = GH.SHIPS[ent]
  675.     if !(ValidEntity(p) and ValidEntity(ent) and !p:IsPlayer() and !p:IsNPC() and !ent.MyShip and ent:GetMoveType() == MOVETYPE_VPHYSICS and data and hook.Call("CanPhysghost",nil,ent,p) != false) then return {} end
  676.     if p.InShip == ent then --inside, make a physghost outside
  677.         local mg = data.MainGhost
  678.         if !ValidEntity(mg) then return {} end
  679.         if !ValidEntity(p.SLMyGhost) then p.SLMyGhost = nil end
  680.         local g = p.SLMyGhost or (GH.IsRagdoll(p) and ents.Create("prop_ragdoll") or ents.Create("prop_physics"))
  681.         g.InShip = nil
  682.         g:SetRealPos(ent:RealLocalToWorld(mg:RealWorldToLocal(p:GetRealPos())))
  683.         local i
  684.         g:SetAngles(ent:RealLocalToWorldAngles(mg:RealWorldToLocalAngles(p:GetRealAngles())))
  685.         g:SetModel(p:GetModel())
  686.         p:DeleteOnRemove(g)
  687.         g:CallOnRemove("GhostDelete",GhostDelete,g)
  688.         p.SLHull = mg
  689.         g.SLHull = ent
  690.         g.SLIsGhost = true
  691.         if ValidEntity(p:GetPhysicsAttacker()) then
  692.             g:SetPhysicsAttacker(p:GetPhysicsAttacker())
  693.         end
  694.         g:SetOwner(p:GetOwner())
  695.         g.Owner = p.Owner
  696.         g.Spawner = p.Spawner
  697.         if !p.SLMyGhost then g:Spawn() end
  698.         p.SLMyGhost = g
  699.         g.SLMyGhost = p
  700.         g:SetSolid(p:GetSolid())
  701.         g:SetMoveType(p:GetMoveType())
  702.         g:SetCollisionGroup(p:GetCollisionGroup())
  703.         if p:GetPhysicsObjectCount() > 1 then
  704.             for i=1,p:GetPhysicsObjectCount() do
  705.                 local po = p:GetPhysicsObjectNum(i-1)
  706.                 local gp = g:GetPhysicsObjectNum(i-1)
  707.                 if (gp && po && gp:IsValid() && po:IsValid()) then
  708.                     gp:SetPos(ent:RealLocalToWorld(mg:WorldToLocal(po:GetPos())))
  709.                     gp:SetAngle(ent:RealLocalToWorldAngles(mg:WorldToLocalAngles(po:GetAngle())))
  710.                 end
  711.             end
  712.         end
  713.         for i=1,p:GetPhysicsObjectCount() do
  714.             local po = p:GetPhysicsObjectNum(i-1)
  715.             local gp = g:GetPhysicsObjectNum(i-1)
  716.             if gp && po && gp:IsValid() && po:IsValid() then
  717.                 gp:EnableGravity(false)
  718.                 gp:EnableCollisions(true)
  719.                 gp:EnableMotion(po:IsMoveable())
  720.             end
  721.         end
  722.         g:SetColor(0,0,0,0) --it's just for physics!!
  723.         g:SetMaterial("models/effects/vol_light001") --seriously!!
  724.         GH.PHYSGHOSTS[p] = g --register as a physghost
  725.         hook.Call("OnCreatePhysghost",nil,ent,p,g)
  726.         return g
  727.     else --outside, make a physghost inside
  728.         local mg = data.MainGhost
  729.         if !ValidEntity(mg) then return {} end
  730.         if !ValidEntity(p.SLMyGhost) then p.SLMyGhost = nil end
  731.         local g = p.SLMyGhost or (GH.IsRagdoll(p) and ents.Create("prop_ragdoll") or ents.Create("prop_physics"))
  732.         g:SetPos(mg:LocalToWorld(ent:RealWorldToLocal(p:GetRealPos())))
  733.         local i
  734.         g:SetAngles(mg:LocalToWorldAngles(ent:RealWorldToLocalAngles(p:GetRealAngles())))
  735.         g:SetModel(p:GetModel())
  736.         p:DeleteOnRemove(g)
  737.         g:CallOnRemove("GhostDelete",GhostDelete,g)
  738.         p.SLHull = ent
  739.         g.SLHull = mg
  740.         g.SLIsGhost = true
  741.         if !p.SLMyGhost then g:Spawn() end
  742.         p.SLMyGhost = g
  743.         g.SLMyGhost = p
  744.         if ValidEntity(p:GetPhysicsAttacker()) then
  745.             g:SetPhysicsAttacker(p:GetPhysicsAttacker())
  746.         end
  747.         g:SetOwner(p:GetOwner())
  748.         g.Owner = p.Owner
  749.         g.Spawner = p.Spawner
  750.         g:SetSolid(p:GetSolid())
  751.         g:SetMoveType(p:GetMoveType())
  752.         g:SetCollisionGroup(p:GetCollisionGroup())
  753.         g:SetColor(0,0,0,0) --it's just for physics!!
  754.         g:SetMaterial("models/effects/vol_light001") --seriously!!
  755.         if p:GetPhysicsObjectCount() > 1 then
  756.             for i=1,p:GetPhysicsObjectCount() do
  757.                 local po = p:GetPhysicsObjectNum(i-1)
  758.                 local gp = g:GetPhysicsObjectNum(i-1)
  759.                 if (gp && po && gp:IsValid() && po:IsValid()) then
  760.                     gp:SetPos(mg:RealLocalToWorld(ent:RealWorldToLocal(po:GetPos())))
  761.                     gp:SetAngle(mg:RealLocalToWorldAngles(ent:RealWorldToLocalAngles(po:GetAngle())))
  762.                 end
  763.             end
  764.         end
  765.         for i=1,p:GetPhysicsObjectCount() do
  766.             local po = p:GetPhysicsObjectNum(i-1)
  767.             local gp = g:GetPhysicsObjectNum(i-1)
  768.             if gp && po && gp:IsValid() and po:IsValid() then
  769.                 gp:EnableGravity(false)
  770.                 gp:EnableCollisions(true)
  771.                 gp:EnableMotion(po:IsMoveable())
  772.             end
  773.         end
  774.         g.InShip = ent
  775.         GH.PHYSGHOSTS[p] = g --register as a physghost
  776.         hook.Call("OnCreatePhysghost",nil,ent,p,g)
  777.         return g
  778.     end
  779. end
  780. local ShipVol_MinRadius = 130
  781. local ShipVol_Res = 30
  782. local OBBPadding = 8
  783. function GetCorners(p)
  784.     local a,b,c,o = p:OBBMins(),p:OBBMaxs(),p:OBBCenter(),OBBPadding
  785.     if math.abs(b.z-a.z) < ShipVol_MinRadius then
  786.         return {
  787.             Vector(a.x+o,a.y+o,c.z),
  788.             Vector(b.x-o,a.y+o,c.z),
  789.             Vector(b.x-o,b.y-o,c.z),
  790.             Vector(a.x+o,b.y-o,c.z),
  791.             Vector(b.x-o,b.y-o,c.z),
  792.         }
  793.     else
  794.         return {
  795.             a,//or(a.x,a.y,a.z),
  796.             Vector(b.x-o,a.y+o,a.z+o),
  797.             Vector(b.x-o,b.y-o,a.z+o),
  798.             Vector(a.x+o,b.y-o,a.z+o),
  799.             Vector(b.x-o,b.y-o,a.z+o),
  800.             Vector(b.x-o,a.y+o,b.z-o),
  801.             Vector(b.x-o,b.y-o,b.z-o),
  802.             Vector(a.x+o,b.y-o,b.z-o),
  803.             Vector(b.x-o,b.y-o,b.z-o),
  804.             b,//or(b.x,b.y,b.z),
  805.         }
  806.     end
  807. end
  808. ------------------------------------------------------------------------------------------
  809. -- Name: EntInShip
  810. -- Desc: Check if the entity is in the ship by performing several PointInShip calls
  811. ------------------------------------------------------------------------------------------
  812. function GH.EntInShip(e,p,_ie)
  813.     local data = GH.SHIPS[e]
  814.     local ie = _ie or e
  815.     if !(ValidEntity(e) and data and ValidEntity(p)) then return end
  816.     local obc = LocalToWorld(p:OBBCenter(),Angle(0,0,0),vector_origin,p:GetRealAngles())
  817.     local out = false
  818.     if p.InShip == e then
  819.         out = GH.PointInShip(e,data.MainGhost:RealWorldToLocal(p:GetRealPos()+obc))
  820.     else
  821.         out = GH.PointInShip(e,ie:RealWorldToLocal(p:GetRealPos()+obc))
  822.     end
  823.     if out and !GH.IsRagdoll(p) and p:BoundingRadius() > ShipVol_MinRadius then
  824.         p.SLCorners = p.SLCorners or GetCorners(p)
  825.         for _,v in pairs(p.SLCorners) do
  826.             local pos,ang = LocalToWorld(v,Angle(0,0,0),vector_origin,p:GetRealAngles())
  827.             if p.InShip == e then
  828.                 out = GH.PointInShip(e,data.MainGhost:RealWorldToLocal(p:GetRealPos()+pos))
  829.             else
  830.                 out = GH.PointInShip(e,ie:RealWorldToLocal(p:GetRealPos()+pos))
  831.             end
  832.             if !out then break end
  833.         end
  834.     end
  835.     return out
  836. end
  837. ------------------------------------------------------------------------------------------
  838. -- Name: PointInShip
  839. -- Desc: Determine if a point is inside a ship, uses traces and a volume map
  840. ------------------------------------------------------------------------------------------
  841. function GH.PointInShip(e,v)
  842.     local data = GH.SHIPS[e]
  843.     if !(ValidEntity(e) and data) then return end
  844.     local lv = Vector(math.Round(v.x/ShipVol_Res),math.Round(v.y/ShipVol_Res),math.Round(v.z/ShipVol_Res))
  845.     local key = lv.x .. ' ' .. lv.y .. ' ' .. lv.z
  846.     local mg = data.MainGhost
  847.     if (data.Volume[key] == nil) then
  848.         local wv = mg:RealLocalToWorld((lv*ShipVol_Res))
  849.         local filt = {}
  850.         table.Add(filt,data.Contents)
  851.         table.Add(filt,GH.PHYSGHOSTS)
  852.         local floortr = util.RealTraceLine{start = wv, endpos = wv-Vector(0,0,data.Radius*2), filter = filt}
  853.         if data.Ghosts[floortr.Entity] then -- FLOOR
  854.             if floortr.HitPos:Distance(floortr.StartPos) > data.FloorDist then
  855.                 local otherdirs = {
  856.                     Vector(0,0,data.Radius*2), --up
  857.                     Vector(-data.Radius*2,0,0), --left
  858.                     Vector(data.Radius*2,0,0), --right
  859.                     Vector(0,-data.Radius*2,0), --back
  860.                     Vector(0,data.Radius*2,0) -- forward
  861.                 }
  862.                 for _,od in pairs(otherdirs) do
  863.                     if data.Ghosts[util.RealTraceLine{start = wv, endpos = wv+od, filter = filt}.Entity] then -- WALL OR CEILING = YEP
  864.                         data.Volume[key] = true
  865.                         return true
  866.                     end
  867.                 end
  868.             else
  869.                 data.Volume[key] = true
  870.                 return true
  871.             end
  872.         end
  873.         data.Volume[key] = false
  874.         return false
  875.     else
  876.         return data.Volume[key]
  877.     end
  878. end
  879. ------------------------------------------------------------------------------------------
  880. -- Name: DisablePhysGhost
  881. -- Desc: Remove a Physghost without destroying it.
  882. ------------------------------------------------------------------------------------------
  883. function GH.DisablePhysGhost(p,g)
  884.     if ValidEntity(p) and ValidEntity(g) and g.SLIsGhost then
  885.         g:SetSolid(SOLID_NONE)
  886.         g:SetMoveType(MOVETYPE_NONE)
  887.         GH.PHYSGHOSTS[p] = nil
  888.     end
  889. end
  890. ------------------------------------------------------------------------------------------
  891. -- Name: GetExteriorEyeTrace
  892. -- Desc: Determine what a player would be looking at were they not in a ship
  893. ------------------------------------------------------------------------------------------
  894. function GH.GetExteriorEyeTrace(p)
  895.     if !p:IsPlayer() then return {} end
  896.     if !(ValidEntity(p.InShip) and GH.SHIPS[p.InShip]) then return p:RealEyeTrace() end
  897.     local ship = p.InShip
  898.     local ghost = GH.SHIPS[ship].MainGhost
  899.     --do the actual trace now
  900.     if !(ValidEntity(ghost) && ValidEntity(ship)) then return {} end
  901.     local strt = ship:RealLocalToWorld(ghost:RealWorldToLocal(p:EyePos()))
  902.     local endp = ship:RealLocalToWorld(ghost:RealWorldToLocal(p:EyePos()+p:RealCursorAimVector()*4096))
  903.     return util.TraceLine{start = strt, endpos = endp, filter = p}
  904. end
  905. ------------------------------------------------------------------------------------------
  906. -- Name: GetInteriorEyeTrace
  907. -- Desc: Determine what a player would be looking at were they in a ship
  908. ------------------------------------------------------------------------------------------
  909. function GH.GetInteriorEyeTrace(e,p)
  910.     if !(ValidEntity(e) and GH.SHIPS[e] and p:IsPlayer()) then return {} end
  911.     local ghost = GH.SHIPS[e].MainGhost
  912.     --do the actual trace now
  913.     if !(ValidEntity(ghost) && ValidEntity(e)) then return {} end
  914.     local strt = p:EyePos()
  915.     local endp = p:EyePos()+p:RealCursorAimVector()*4096
  916.     if p.InShip != e then
  917.         strt = WorldToLocal(strt,Angle(0,0,0),e:GetPos(),e:GetAngles())
  918.         strt = ghost:RealLocalToWorld(strt)
  919.         endp = WorldToLocal(endp,Angle(0,0,0),e:GetPos(),e:GetAngles())
  920.         endp = ghost:RealLocalToWorld(endp)
  921.     end
  922.     return util.TraceLine{start = strt, endpos = endp, filter = p}
  923. end
  924. hook.Add("SetupPlayerVisibility","SLShipVis",function(ply)
  925. xpcall(function()
  926.     if ValidEntity(ply.InShip) then
  927.         AddOriginToPVS(ply:GetPos())
  928.     end
  929.     for e,dat in pairs(GH.SHIPS) do
  930.         if ValidEntity(dat.MainGhost) then
  931.             AddOriginToPVS(dat.MainGhost:GetRealPos())
  932.         end
  933.         if ValidEntity(e) and e:WaterLevel() > 1 then
  934.             AddOriginToPVS(e:GetPos())
  935.         end
  936.     end
  937. end,ErrorNoHalt)
  938. end)
  939. --BULLET INFLICTOR FIXES
  940. hook.Add("EntityTakeDamage","SLInflictorFix",function(ent,inf,att,amt,dmg)
  941.     local inf = dmg:GetInflictor()
  942.     if inf.Inflictor then dmg:SetInflictor(inf.Inflictor) end
  943.     if inf.Attacker then dmg:SetAttacker(inf.Attacker) end
  944. end)
  945. local nexttick = 0
  946. local numticks = 0
  947. local a0 = Angle(0,0,0)
  948. local ignore_in_contraption = kv_swap{
  949.     "gmod_thruster","gmod_hoverball","gmod_turret"
  950. }
  951. ------------------------------------------------------------------------------------------
  952. -- Name: ShouldEat
  953. -- Desc: return whether an entity is even a cantidate for being put in a ship the normal way.
  954. ------------------------------------------------------------------------------------------
  955. function GH.ShouldEat(ent,p,data)
  956.     return !(!ValidEntity(p) or p.InShip == ent or p.MyShip == ent or data.Hull[p] or data.Welds[p] or p:IsWorld() or p.SLIsGhost or p.SLLastTick[ent] == numticks or p == GH.BulletGhost or
  957.             p:GetMoveType() == MOVETYPE_NONE or !p:GetPhysicsObject():IsValid() or p:GetPhysicsObject():IsAsleep() or !p:GetPhysicsObject():IsMoveable() or ValidEntity(p:GetParent()) or
  958.             (p:IsPlayer() and !p:Alive()))
  959. end
  960. ------------------------------------------------------------------------------------------
  961. -- Name: TryEat
  962. -- Desc: Eat an object into a ship if it's inside the hull boundaries.
  963. ------------------------------------------------------------------------------------------
  964. function GH.TryEat(ent,p,data)
  965.     local out = false
  966.     if type(p.SLLastTick) != 'table' then p.SLLastTick = {} end
  967.     if GH.ShouldEat(ent,p,data) then
  968.         if p:IsConstrained() then --ENTIRE CONTRAPTIONS MUST BE MOVED ALL AT ONCE
  969.             local pcon = GH.ConstrainedEntities(p)
  970.             local doit = true
  971.             local isship = false
  972.             for _,con in pairs(pcon) do
  973.                 con.SLLastTick = con.SLLastTick or {}
  974.                 con.SLLastTick[ent] = numticks
  975.                 if con==ent or (doit and !ignore_in_contraption[con:GetClass()] and !GH.EntInShip(ent,con)) then
  976.                     doit = false
  977.                 end
  978.             end
  979.             if doit then
  980.                 for _,con in pairs(pcon) do
  981.                     GH.ShipEat(ent,con) --do it all at once
  982.                     out = true
  983.                 end
  984.             end
  985.         elseif GH.EntInShip(ent,p) then --If the ent is physically in the ship
  986.             GH.ShipEat(ent,p) --teleport it to the clone
  987.             out = true
  988.         end
  989.         p.SLLastTick[ent] = numticks
  990.     end
  991.     return out
  992. end
  993. ------------------------------------------------------------------------------------------
  994. -- Name: TrySpit
  995. -- Desc: Spit an object out of a ship if it's not inside the hull boundaries.
  996. ------------------------------------------------------------------------------------------
  997. function GH.TrySpit(k,ent,p,data)
  998.     if ValidEntity(p) and p.InShip == ent and !p.SLIsGhost and p != GH.BulletGhost then
  999.         if p:IsPlayer() and !p:Alive() then
  1000.             GH.ShipSpit(ent,p) --SPIT OUT ALL THE DEAD PEOPLE O.o
  1001.         elseif !p:GetPhysicsObject():IsValid() or (!p:GetPhysicsObject():IsAsleep() and p:GetPhysicsObject():IsMoveable()) and p.SLLastInTick != numticks then --either doesn't have a physobj or its physobj is awake and unfrozen
  1002.             if p:IsConstrained() then --ENTIRE CONTRAPTIONS MUST BE MOVED ALL AT ONCE
  1003.                 local pcon = GH.ConstrainedEntities(p)
  1004.                 local doit = false
  1005.                 local isship = false
  1006.                 for _,con in pairs(pcon) do
  1007.                     con.SLLastInTick = numticks
  1008.                     if con.MyShip then isship = true end
  1009.                     if !isship and !doit and !ignore_in_contraption[con:GetClass()] and !GH.EntInShip(ent,con) then --something is sticking out
  1010.                         doit = true
  1011.                     end
  1012.                 end
  1013.                 if doit and !isship then
  1014.                     for _,con in pairs(pcon) do
  1015.                         GH.ShipSpit(ent,con) --all at once.
  1016.                     end
  1017.                 end
  1018.             elseif !GH.EntInShip(ent,p) then
  1019.                 GH.ShipSpit(ent,p)
  1020.             end
  1021.         end
  1022.         p.SLLastInTick = numticks
  1023.     end
  1024. end
  1025. ------------------------------------------------------------------------------------------
  1026. -- Name: PhysGhostTick
  1027. -- Desc: Process a physghost pair.
  1028. ------------------------------------------------------------------------------------------
  1029. function GH.PhysGhostTick(p,g)
  1030.     if ValidEntity(p) and ValidEntity(g) then
  1031.         if g.Expire and !g.Permanent and CurTime() > g.Expire then --obai mr ghost (we'll let him live in case we need him again)
  1032.             GH.DisablePhysGhost(p,g)
  1033.         else
  1034.             --calculate stuff
  1035.             local ph,gh = p.SLHull,g.SLHull
  1036.             if (ValidEntity(ph) && ValidEntity(gh)) then
  1037.                 --do stuff
  1038.                 local gbang = gh:LocalToWorldAngles(ph:WorldToLocalAngles(p:GetRealAngles()))
  1039.                 local gbpos = gh:LocalToWorld(ph:WorldToLocal(p:GetRealPos()))
  1040.                 local i
  1041.                 for i=1,p:GetPhysicsObjectCount() do
  1042.                     local pp,gp = p:GetPhysicsObjectNum(i-1),g:GetPhysicsObjectNum(i-1)
  1043.                     local gpos = gh:LocalToWorld(ph:WorldToLocal(pp:GetPos()))
  1044.                     local gang = gh:LocalToWorldAngles(ph:WorldToLocalAngles(pp:GetAngle()))
  1045.                     if pp and gp and pp:IsValid() and gp:IsValid() then
  1046.                         local gvel = pp:LocalToWorld(gp:WorldToLocal(gp:GetVelocity()+gp:GetPos()))-pp:GetPos()
  1047.                         if (gp:IsMoveable() && !pp:IsMoveable()) then pp:EnableMotion(true) end
  1048.                         if (ValidEntity(g.HeldBy) and g.HeldBone == i-1) or gp:HasGameFlag(4) then --safe to assume it's being physgunned-- that means we obey the ghost
  1049.                             /*if (gp:GetMass() < 500) then --if its mass is low enough that it moves too slow
  1050.                                 g.OldBoneMass = gp:GetMass() --record the old mass
  1051.                                 gp:SetMass(500) --change the mass to something draggable
  1052.                                 g.FixBoneMass = g.HeldBone --and tell the "let go" hook to fix it later
  1053.                             end*/
  1054.                             gp:EnableCollisions(true)
  1055.                             pp:SetVelocity((gp:GetPos() - gpos) + gvel) --apply vel changes to the nonghost
  1056.                             pp:AddAngleVelocity(a0-pp:GetAngleVelocity()) --nullify angular velocity
  1057.                             pp:AddAngleVelocity(gp:GetAngleVelocity()) --inherit ghost's angvel
  1058.                             gp:AddAngleVelocity(a0-gp:GetAngleVelocity()) --nullify ghost's angvel
  1059.                             g.Expire = CurTime()+0.5
  1060.                         else --freely moving, so obey the nonghost
  1061.                             g:SetRealPos(gbpos) --update the base location
  1062.                             gp:SetVelocity(pp:GetVelocity())
  1063.                             gp:SetPos(gpos) --update the ghost's location
  1064.                             if p.InShip then
  1065.                                 gp:EnableCollisions(false)
  1066.                             end
  1067.                             gp:AddAngleVelocity(a0-gp:GetAngleVelocity())
  1068.                             gp:AddVelocity(vector_origin) --nullify the ghosts's velocity to avoid spazz
  1069.                         end
  1070.                         --NO SLEEPING KTHX
  1071.                         pp:Wake()
  1072.                         gp:Wake()
  1073.                         pp:SetMass(gp:GetMass()) --make sure this thing feels like it's in a physgun
  1074.                         gp:SetPos(gpos) --update the bone's location
  1075.                         gp:SetAngle(gang) --update the bone's angles
  1076.                     end
  1077.                 end
  1078.                 g:SetMaxHealth(10000)
  1079.                 g:SetHealth(10000) --don't let it explode
  1080.                 g:SetRealPos(gbpos) --update the ghost's location
  1081.                 g:SetAngles(gbang) --update the ghost's angles
  1082.                 g:SetColor(0,0,0,0) --don't let them see me...EVER
  1083.             end
  1084.         end
  1085.     else
  1086.         GH.PHYSGHOSTS[p] = nil
  1087.     end
  1088. end
  1089. ------------------------------------------------------------------------------------------
  1090. -- Name: PlayerEyeGhosts
  1091. -- Desc: Summons physghosts for any illusionary object the player is looking at.
  1092. ------------------------------------------------------------------------------------------
  1093. function GH.PlayerEyeGhosts(p)
  1094.     local e = GH.GetExteriorEyeTrace(p).Entity
  1095.     if ValidEntity(p.InShip) and ValidEntity(e) and !(e.MyShip == p.InShip or e.InShip == p.InShip or GH.SHIPS[p.InShip].Welds[e] or e:IsWorld() or e:IsNPC()) then
  1096.         if ValidEntity(GH.PHYSGHOSTS[e]) && GH.PHYSGHOSTS[e].InShip == p.InShip then
  1097.             GH.PHYSGHOSTS[e].Expire = CurTime()+0.5
  1098.         else
  1099.             GH.PhysGhost(p.InShip,e).Expire = CurTime()+0.5
  1100.         end
  1101.     elseif ValidEntity(e) and ValidEntity(e.Ghost) and ValidEntity(e.Ghost.MyShip) and GH.SHIPS[e.Ghost.MyShip] and p.InShip != e.Ghost.MyShip then
  1102.         local ph = e.Ghost.MyShip
  1103.         local ie = GH.GetInteriorEyeTrace(ph,p).Entity --lol it says php and the variable is IE, what a coincidence
  1104.         if ValidEntity(ie) and ie.InShip == ph and !(ie.SLIsGhost and ie.SLMyGhost.InShip == p.InShip) then
  1105.             if ValidEntity(GH.PHYSGHOSTS[ie]) && GH.PHYSGHOSTS[ie].InShip == ph then
  1106.                 GH.PHYSGHOSTS[ie].Expire = CurTime()+0.5
  1107.             else
  1108.                 GH.PhysGhost(ie.InShip,ie).Expire = CurTime()+0.5
  1109.             end
  1110.         end
  1111.     elseif ValidEntity(p.InShip) then
  1112.         local ph = p.InShip
  1113.         local ie = GH.GetInteriorEyeTrace(ph,p).Entity
  1114.         if ValidEntity(ie) and ie.InShip == ph then
  1115.             if ValidEntity(GH.PHYSGHOSTS[ie]) && GH.PHYSGHOSTS[ie].InShip == ph then
  1116.                 GH.PHYSGHOSTS[ie].Expire = CurTime()+0.5
  1117.             else
  1118.                 GH.PhysGhost(ie.InShip,ie).Expire = CurTime()+0.5
  1119.             end
  1120.         end
  1121.     end
  1122. end
  1123. ------------------------------------------------------------------------------------------
  1124. -- Name: RocketFly
  1125. -- Desc: Manually sets the velocities of rpg_missiles so they obey external aim.
  1126. ------------------------------------------------------------------------------------------
  1127. function GH.RocketFly(r,p)
  1128.     if !(ValidEntity(r) and ValidEntity(p)) then GH.ROCKETHAX[r] = nil; return end
  1129.     local tr = util.TraceLine{start = p:GetShootPos(), endpos = p:GetShootPos() + p:GetAimVector()*16384, filter = {r,p}}
  1130.     local dst = tr.HitPos - tr.HitNormal
  1131.     if r.InShip and GH.SHIPS[r.InShip] then
  1132.         dst = GH.SHIPS[r.InShip].MainGhost:LocalToWorld(r.InShip:WorldToLocal(dst))
  1133.     end
  1134.     local nrm = (dst - r:GetRealPos()):Normalize()
  1135.     local ang = r:GetRealAngles()
  1136.     local nang = nrm:Angle()
  1137.     ang.p = math.ApproachAngle(ang.p,nang.p,(nang.p-ang.p)/8)
  1138.     ang.y = math.ApproachAngle(ang.y,nang.y,(nang.y-ang.y)/8)
  1139.     ang.r = math.ApproachAngle(ang.r,nang.r,(nang.r-ang.r)/8)
  1140.     r:SetAngles(ang)
  1141.     r:SetVelocity(r:GetForward()*1500-r:GetVelocity())
  1142. end
  1143. ------------------------------------------------------------------------------------------
  1144. -- Name: SLShipTick
  1145. -- Desc: Think hook that handles hulls and physghosts
  1146. ------------------------------------------------------------------------------------------
  1147. hook.Add("Think","SLShipTick",function()
  1148. xpcall(function()
  1149.     --external physghost summoning
  1150.     for _,p in pairs(player.GetAll()) do
  1151.         GH.PlayerEyeGhosts(p)
  1152.     end
  1153.     --update the physghosts
  1154.     for p,g in pairs(GH.PHYSGHOSTS) do
  1155.         --check stuff
  1156.         GH.PhysGhostTick(p,g)
  1157.     end
  1158.     --hax the rockets
  1159.     for r,p in pairs(GH.ROCKETHAX) do
  1160.         GH.RocketFly(r,p)
  1161.     end
  1162.     --scary discovery stuff hurr durr
  1163.     if CurTime() > nexttick then
  1164.         numticks = (numticks > 4 and 0 or numticks + 1)
  1165.         nexttick = CurTime()+0.2
  1166.         for ent,data in pairs(GH.SHIPS) do
  1167.             if ValidEntity(ent) and ValidEntity(data.MainGhost) then
  1168.                 if numticks == 3 then
  1169.                     if table.Count(data.Welds) != table.Count(GH.ConstrainedEntities(ent)) then
  1170.                         GH.UpdateHull(ent) --reconstruct the ghosts if any constraints are changed
  1171.                     end
  1172.                 end
  1173.                 local pos,rad = ent:LocalToWorld(data.Center),data.Radius
  1174.                 ent.SLLastFind = (numticks > 0 and ent.SLLastFind or ents.RealFindInSphere(pos,rad+300))
  1175.                 for _,p in pairs(ent.SLLastFind) do
  1176.                     GH.TryEat(ent,p,data)
  1177.                 end
  1178.                 for k,p in pairs(data.Contents) do
  1179.                     GH.TrySpit(k,ent,p,data)
  1180.                 end
  1181.             end
  1182.         end
  1183.     end
  1184. end,ErrorNoHalt)
  1185. end)
  1186. ------------------------------------------------------------------------------------------
  1187. -- Name: SLSpawn
  1188. -- Desc: Hook for created entities to automatically place them in the right hull/cell
  1189. ------------------------------------------------------------------------------------------
  1190. local function SLSpawn(ent,two)
  1191. xpcall(function()
  1192.     if !ValidEntity(ent) then return end
  1193.     if ent.SLIsGhost then return end
  1194.     local ply = ent:GetOwner()
  1195.     if !ValidEntity(ply) then ply = ent:GetPhysicsAttacker() end
  1196.     if !ValidEntity(ply) then ply = ent.Owner or ent.Spawner end
  1197.     if !ValidEntity(ply) then ply = ((ent.Constraints||{})[1]||{}).Ent2 end --extremely hacky way to find prop spawner parent
  1198.     if !ValidEntity(ply) then ply = (((ent.OnDieFunctions||{}).GetCountUpdate||{}).Args||{})[1] end --extremely hacky way to find out who spawned this
  1199.     if ent:GetClass() == "rpg_missile" and ValidEntity(ply) then
  1200.         ply.RocketHax = ent
  1201.     end
  1202.     if ply and MapRepeat then
  1203.         if !ply.Cells then MapRepeat.SetCell(ply,"0 0 0") end
  1204.         MapRepeat.SetCell(ent,ply.Cells[1])
  1205.     elseif MapRepeat and ent:IsWeapon() then
  1206.         print(ent)
  1207.         MapRepeat.ClaimWep(ent)
  1208.     end
  1209.     if ValidEntity(ply) and GH.SHIPS[ply.InShip or ply.MyShip] then
  1210.         local ship = (ply.InShip or ply.MyShip)
  1211.         //if GH.EntInShip(
  1212.         if GH.EntInShip(ship,ent) then
  1213.             local ea = ent:GetAngles()
  1214.             GH.ShipEat(ship,ent,NO_VEL)
  1215.             if ent:GetClass() == "prop_physics" then
  1216.                 ent:SetAngles(ea)
  1217.             end
  1218.         elseif ValidEntity(ent:GetOwner()) then
  1219.             GH.ShipEat(ship,ent,true)
  1220.         end
  1221.     elseif !two then
  1222.         timer.Simple(0,SLSpawn,ent,true)
  1223.     end
  1224. end,ErrorNoHalt)
  1225. end
  1226. hook.Add("OnEntityCreated","SLSpawn",SLSpawn)
  1227. ------------------------------------------------------------------------------------------
  1228. -- Vehicle Hooks
  1229. -- Desc: Hook vehicles and provide needed functionality
  1230. ------------------------------------------------------------------------------------------
  1231. hook.Add("CanPlayerEnterVehicle","SLVehicleEnterFix",function(ply,car)
  1232.     if (ply.InShip && !car.InShip) then
  1233.         GH.ShipSpit(ply.InShip,ply)
  1234.     end
  1235. end)
  1236. hook.Add("PlayerLeaveVehicle","SLVehicleFix",function(ply,car)
  1237.     if (car.InShip && !ply.InShip) then
  1238.         GH.ShipEat(car.InShip,ply,true)
  1239.     end
  1240. end)
  1241. ------------------------------------------------------------------------------------------
  1242. -- Name: SLDeath
  1243. -- Desc: Remove dead players from ships
  1244. ------------------------------------------------------------------------------------------
  1245. hook.Add("PlayerDeath","SLDeath",function(ply)
  1246.     if (ValidEntity(ply) && ValidEntity(ply.InShip)) then
  1247.         xpcall(GH.ShipSpit,ErrorNoHalt,ply.InShip,ply)
  1248.     end
  1249. end)
  1250. ------------------------------------------------------------------------------------------
  1251. -- Physgun/Collision Hooks
  1252. -- Desc: Hook the physgun and collision and provide needed functionality
  1253. ------------------------------------------------------------------------------------------
  1254. hook.Add("OnPhysgunFreeze","PhysGhostFreeze",function(wep,phy,ent,ply)
  1255.     if (ValidEntity(ent) && ValidEntity(ent.SLMyGhost)) then ent.SLMyGhost:GetPhysicsObject():EnableMotion(false) end
  1256. end)
  1257. hook.Add("PhysgunPickup","NoGrab",function(ply,ent)
  1258.     if ValidEntity(ent) && ValidEntity(ply) then
  1259.         if !ValidEntity(ply.InShip) then ply.InShip = nil end
  1260.         if !ValidEntity(ent.InShip) then ent.InShip = nil end
  1261.         if ply.InShip != ent.InShip then
  1262.             return false
  1263.         end
  1264.         if ValidEntity(ent.MyShip) and GH.SHIPS[ent.MyShip] then --indicates that it's a ghost hull and shouldn't be moved
  1265.             return false
  1266.         end
  1267.     end
  1268. end)
  1269. hook.Add("PhysgunPickup","HeldBy",function(ply,ent)
  1270.     if ValidEntity(ent) && ValidEntity(ply) then
  1271.         ent.HeldBy = ply
  1272.         ent.HeldBone = ply:RealEyeTrace().PhysicsBone
  1273.         if ent:GetPhysicsObjectNum(ent.HeldBone) then
  1274.             ent.OldMass = ent:GetPhysicsObjectNum(ent.HeldBone):GetMass()
  1275.         end
  1276.         ply.Holding = ent
  1277.     end
  1278. end)
  1279. hook.Add("PhysgunDrop","HeldBy",function(ply,ent)
  1280.     if ValidEntity(ent) && ValidEntity(ply) then
  1281.         ent.HeldBy = nil
  1282.         ent.HeldBone = nil
  1283.         ply.Holding = nil
  1284.         if ent.FixBoneMass and ent.OldBoneMass then
  1285.             ent:GetPhysicsObjectNum(ent.FixBoneMass):SetMass(ent.OldBoneMass)
  1286.         end
  1287.     end
  1288. end)
  1289. hook.Add("CanPlayerUnfreeze","NoUnfreeze",function(ply,ent)
  1290.     if ply.InShip != ply:GetEyeTrace(true,true).Entity.InShip then
  1291.         return false
  1292.     end
  1293.     if ValidEntity(ent.MyShip) and GH.SHIPS[ent.MyShip] then --indicates that it's a ghost hull and shouldn't be moved
  1294.         return false
  1295.     end
  1296. end)
  1297. hook.Add("ShouldCollide","SLShipCollide",function(en1,en2)
  1298.     local out = nil
  1299. xpcall(function()
  1300.     if en1 == GH.BulletGhost or en2 == GH.BulletGhost then return end
  1301.     if !(en1:IsWorld() or en2:IsWorld()) then
  1302.         local e1,e2 = en1,en2
  1303.         if ValidEntity(e1.MyShip) and GH.SHIPS[e1.MyShip] and --ghost hull, should only collide with ghost children.
  1304.         !(e2.InShip == e1.MyShip) then --not a ghost child so don't collide, period.
  1305.             out = false
  1306.             return
  1307.         end
  1308.         if ValidEntity(e1.InShip) and GH.SHIPS[e1.InShip] and --ghost child, should only collide with hulls and other children.
  1309.         !(e2.MyShip == e1.InShip or e2.InShip == e1.InShip) then --not a ghost child or hull, so don't collide, period.
  1310.             out = false
  1311.             return
  1312.         end
  1313.         local e1,e2 = en2,en1
  1314.         if ValidEntity(e1.MyShip) and GH.SHIPS[e1.MyShip] and --ghost hull, should only collide with ghost children.
  1315.         !(e2.InShip == e1.MyShip) then --not a ghost child so don't collide, period.
  1316.             out = false
  1317.             return
  1318.         end
  1319.         if ValidEntity(e1.InShip) and GH.SHIPS[e1.InShip] and --ghost child, should only collide with hulls and other children.
  1320.         !(e2.MyShip == e1.InShip or e2.InShip == e1.InShip) then --not a ghost child or hull, so don't collide, period.
  1321.             out = false
  1322.             return
  1323.         end
  1324.     end
  1325. end,ErrorNoHalt)
  1326.     return out
  1327. end)
  1328. ------------------------------------------------------------------------------------------
  1329. -- Name: SLClientData
  1330. -- Desc: Send a newly joining client any usermessages that it missed before
  1331. ------------------------------------------------------------------------------------------
  1332. function SLClientData(ply)
  1333.     for ent,data in pairs(GH.SHIPS) do
  1334.         for k,v in pairs(data.Ghosts) do
  1335.             ply:ShipObject(k,true,true,ent,v)
  1336.         end
  1337.         for k,v in pairs(data.Contents) do
  1338.             ply:ShipObject(v,true,false,ent,data.MainGhost)
  1339.         end
  1340.     end
  1341. end
  1342. hook.Add("PlayerInitialSpawn","SLInitialSpawn",SLClientData)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement