Advertisement
Guest User

Untitled

a guest
Jan 22nd, 2019
147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.50 KB | None | 0 0
  1. local ENT = {}
  2.  
  3. ENT.Type            = "anim"
  4. ENT.Base            = "base_anim"
  5. ENT.Spawnable       = true
  6. ENT.AdminSpawnable  = true
  7. ENT.PrintName       = "Lua Room"
  8.  
  9. local MAT_FLOOR = Material("hunter/myplastic")
  10. local MAT_CEILING = Material("hunter/myplastic")
  11. local MAT_WALL = Material("hunter/myplastic")
  12. local MAT_DOORWAY = Material("hunter/myplastic")
  13.  
  14. -- Mapped as
  15. --    F
  16. --  L   R
  17. --    B
  18. local DATA_LEFT_SIDE = 1
  19. local DATA_FRONT_SIDE = 2
  20. local DATA_RIGHT_SIDE = 3
  21. local DATA_BACK_SIDE = 4
  22. local DATA_FLOOR = 5
  23. local DATA_CEILING = 6
  24.  
  25. -- +x = FWD
  26. -- +y = LEFT
  27.  
  28. local _Angle = Angle(0, 0, 0)
  29. local SEGMENT_DIRECTION =
  30. {
  31.     [DATA_LEFT_SIDE] = (-_Angle:Right()):Angle(),
  32.     [DATA_FRONT_SIDE] = (_Angle:Forward()):Angle(),
  33.     [DATA_RIGHT_SIDE] = (_Angle:Right()):Angle(),
  34.     [DATA_BACK_SIDE] = (-_Angle:Forward()):Angle(),
  35.     [DATA_FLOOR] = (_Angle:Up()):Angle(),
  36.     [DATA_CEILING] = (-_Angle:Up()):Angle(),
  37. }
  38.  
  39. local WALL_SEGMENT_W = 128
  40. local WALL_SEGMENT_H = 128
  41.  
  42. local DOOR_SEGMENT_W = 48
  43. local DOOR_SEGMENT_H = 108
  44.  
  45. local DATA_ENTRY_WALL = 1
  46. local DATA_ENTRY_DOOR = 2
  47. local DATA_ENTRY_FLOOR = 3
  48. local DATA_ENTRY_CEILING = 4
  49.  
  50. function ENT:SetupDataTables()
  51.     self:NetworkVar("Int", 0, "RoomCycle")
  52.     self:NetworkVar("Int", 1, "RoomSeed")
  53.     self:NetworkVar("Int", 2, "RoomWidth")
  54.     self:NetworkVar("Int", 3, "RoomHeight")
  55.    
  56.     self:NetworkVar("Float", 0, "RoomPosX")
  57.     self:NetworkVar("Float", 1, "RoomPosY")
  58.     self:NetworkVar("Float", 2, "RoomPosZ")
  59.    
  60.     self:NetworkVar("Float", 3, "RoomAngX")
  61.     self:NetworkVar("Float", 4, "RoomAngY")
  62.     self:NetworkVar("Float", 5, "RoomAngZ")
  63. end
  64.  
  65. function ENT:GetRoomPos()
  66.     return Vector(self:GetRoomPosX(), self:GetRoomPosY(), self:GetRoomPosZ())
  67. end
  68.  
  69. function ENT:SetRoomPos(pos)
  70.     self:SetRoomPosX(pos.x)
  71.     self:SetRoomPosY(pos.y)
  72.     self:SetRoomPosZ(pos.z)
  73. end
  74.  
  75. function ENT:GetRoomAng()
  76.     return Angle(self:GetRoomAngX(), self:GetRoomAngY(), self:GetRoomAngZ())
  77. end
  78.  
  79. function ENT:SetRoomAng(ang)
  80.     self:SetRoomAngX(ang.x)
  81.     self:SetRoomAngY(ang.y)
  82.     self:SetRoomAngZ(ang.z)
  83. end
  84.  
  85. function ENT:Initialize()
  86.    
  87.     -- Data
  88.     self.RoomData = self.RoomData or {}
  89.     self.RoomData[DATA_LEFT_SIDE] = self.RoomData[DATA_LEFT_SIDE] or {}
  90.     self.RoomData[DATA_RIGHT_SIDE] = self.RoomData[DATA_RIGHT_SIDE] or {}
  91.     self.RoomData[DATA_BACK_SIDE] = self.RoomData[DATA_BACK_SIDE] or {}
  92.     self.RoomData[DATA_FRONT_SIDE] = self.RoomData[DATA_FRONT_SIDE] or {}
  93.     self.RoomData[DATA_FLOOR] = self.RoomData[DATA_FLOOR] or {}
  94.     self.RoomData[DATA_CEILING] = self.RoomData[DATA_CEILING] or {}
  95.    
  96.     -- Meshes.
  97.     self.Objects = self.Objects or {}
  98.  
  99.     if CLIENT then
  100.         self.RoomCycle = -1
  101.     else
  102.         self:SetRoomCycle(-1)
  103.     end
  104.    
  105.     self:SetModel("models/props_combine/breenglobe.mdl")
  106.    
  107.     if CLIENT then
  108.         self:SetRenderBounds(Vector(-2000, -2000, -2000), Vector(2000, 2000, 2000))
  109.     else
  110.         self:CreateRoom(1, 10, 10)
  111.     end
  112. end
  113.  
  114. function ENT:OnReloaded()
  115.     if SERVER then
  116.         self:CreateRoom(self:GetRoomSeed(), self:GetRoomWidth(), self:GetRoomHeight()) 
  117.     end
  118. end
  119.  
  120. function ENT:AddQuad(verts, pos, w, h, ang)
  121.    
  122.     local mat = Matrix()
  123.     mat:SetTranslation(Vector(0, 0, 0))
  124.     mat:SetAngles(ang)
  125.    
  126.     --pos = mat:__mul(pos)
  127.    
  128.     -- FIXME: Scale this shit properly.
  129.     local uScale = 1
  130.     local vScale = 1
  131.  
  132.     local newVerts = {
  133.         -- Front side.
  134.         { pos = pos + mat:__mul(Vector( 0, 0, 0 )), u = 1 * uScale, v = 1 * vScale },
  135.         { pos = pos + mat:__mul(Vector( 0, w, 0 )), u = 1 * uScale, v = 0 * vScale },
  136.         { pos = pos + mat:__mul(Vector( 0, w, h )), u = 0 * uScale, v = 0 * vScale },
  137.        
  138.         { pos = pos + mat:__mul(Vector( 0, w, h )), u = 1 * uScale, v = 1 * vScale },
  139.         { pos = pos + mat:__mul(Vector( 0, 0, h )), u = 0 * uScale, v = 1 * vScale },
  140.         { pos = pos + mat:__mul(Vector( 0, 0, 0 )), u = 0 * uScale, v = 0 * vScale },
  141.            
  142.         -- Back side.
  143.         { pos = pos + mat:__mul(Vector( 0, w, h )), u = 0 * uScale, v = 0 * vScale },
  144.         { pos = pos + mat:__mul(Vector( 0, w, 0 )), u = 1 * uScale, v = 0 * vScale },
  145.         { pos = pos + mat:__mul(Vector( 0, 0, 0 )), u = 1 * uScale, v = 1 * vScale },
  146.        
  147.         { pos = pos + mat:__mul(Vector( 0, 0, 0 )), u = 0 * uScale, v = 0 * vScale },
  148.         { pos = pos + mat:__mul(Vector( 0, 0, h )), u = 0 * uScale, v = 1 * vScale },
  149.         { pos = pos + mat:__mul(Vector( 0, w, h )), u = 1 * uScale, v = 1 * vScale },
  150.     }
  151.    
  152.     for _,v in pairs(newVerts) do
  153.         table.insert(verts, v)
  154.     end
  155.    
  156. end
  157.  
  158. function ENT:CreateWallSegment(pos, ang)
  159.    
  160.     local verts = {}
  161.     self:AddQuad(verts, pos, WALL_SEGMENT_W, WALL_SEGMENT_H, ang)
  162.        
  163.     local wall = {}
  164.     wall.Verts = verts
  165.     wall.Width = WALL_SEGMENT_W
  166.     wall.Height = WALL_SEGMENT_H
  167.     wall.Type = DATA_ENTRY_WALL
  168.     wall.Mat = MAT_WALL
  169.    
  170.     if CLIENT then
  171.         local obj = Mesh()
  172.         obj:BuildFromTriangles(verts)
  173.         wall.Mesh = obj
  174.     end
  175.    
  176.     table.insert(self.Objects, wall)
  177.    
  178.     return wall
  179.    
  180. end
  181.  
  182. function ENT:CreateDoorSegment(pos, ang)
  183.    
  184.     local verts = {}
  185.    
  186.     -- Door segment has a small gap fill above door entry
  187.     -- Left and right side wall.
  188.     local wallSize = WALL_SEGMENT_W - DOOR_SEGMENT_W
  189.     local wallSizeLeft = wallSize / 2
  190.     local wallSizeRight = wallSize / 2
  191.    
  192.     local doorGapHeight = WALL_SEGMENT_H - DOOR_SEGMENT_H
  193.     local doorGapZ = DOOR_SEGMENT_H
  194.    
  195.     local p = Vector(pos)
  196.    
  197.     -- Left wall
  198.     self:AddQuad(verts, p, wallSizeLeft, WALL_SEGMENT_H, ang)
  199.     p = p - (ang:Right() * wallSizeLeft)
  200.    
  201.     -- Gap
  202.     self:AddQuad(verts, p + Vector(0, 0, doorGapZ), DOOR_SEGMENT_W, doorGapHeight, ang)
  203.     p = p - (ang:Right() * DOOR_SEGMENT_W)
  204.    
  205.     -- Right wall
  206.     self:AddQuad(verts, p, wallSizeLeft, WALL_SEGMENT_H, ang)
  207.     --pos = pos + (ang:Right() * wallSizeRight)
  208.    
  209.     local door = {}
  210.     door.Verts = verts
  211.     door.Width = WALL_SEGMENT_W
  212.     door.Height = DOOR_SEGMENT_H
  213.     door.Type = DATA_ENTRY_DOOR
  214.     door.Mat = MAT_DOORWAY
  215.    
  216.     if CLIENT then
  217.         local obj = Mesh()
  218.         obj:BuildFromTriangles(verts)
  219.         door.Mesh = obj
  220.     end
  221.    
  222.     table.insert(self.Objects, door)
  223.    
  224.     return door
  225.    
  226. end
  227.  
  228. function ENT:CreateFloorSegment(pos, ang, sizeX, sizeY)
  229.    
  230.     local verts = {}
  231.    
  232.     self:AddQuad(verts, pos, sizeY, sizeX, ang)
  233.    
  234.     local floor = {}
  235.     floor.Verts = verts
  236.     floor.Width = sizeX
  237.     floor.Height = sizeY
  238.     floor.Type = DATA_ENTRY_FLOOR
  239.     floor.Mat = MAT_FLOOR
  240.    
  241.     if CLIENT then
  242.         local obj = Mesh()
  243.         obj:BuildFromTriangles(verts)
  244.         floor.Mesh = obj
  245.     end
  246.    
  247.     table.insert(self.Objects, floor)
  248.    
  249.     return floor
  250.    
  251. end
  252.  
  253. function ENT:CreateCeilingSegment(pos, ang, sizeX, sizeY)
  254.    
  255.     local verts = {}
  256.    
  257.     self:AddQuad(verts, pos + Vector(0, 0, WALL_SEGMENT_H), sizeY, sizeX, ang)
  258.    
  259.     local ceiling = {}
  260.     ceiling.Verts = verts
  261.     ceiling.Width = sizeX
  262.     ceiling.Height = sizeY
  263.     ceiling.Type = DATA_ENTRY_CEILING
  264.     ceiling.Mat = MAT_CEILING
  265.    
  266.     if CLIENT then
  267.         local obj = Mesh()
  268.         obj:BuildFromTriangles(verts)
  269.         ceiling.Mesh = obj
  270.     end
  271.    
  272.     table.insert(self.Objects, ceiling)
  273.    
  274.     return ceiling
  275.    
  276. end
  277.  
  278. function ENT:CreateEntry(v, pos, ang, sizeX, sizeY)
  279.     if v == DATA_ENTRY_WALL then
  280.         return self:CreateWallSegment(pos, ang, sizeX, sizeY)
  281.     elseif v == DATA_ENTRY_DOOR then
  282.         return self:CreateDoorSegment(pos, ang, sizeX, sizeY)
  283.     elseif v == DATA_ENTRY_FLOOR then
  284.         return self:CreateFloorSegment(pos, ang, sizeX, sizeY)
  285.     elseif v == DATA_ENTRY_CEILING then
  286.         return self:CreateCeilingSegment(pos, ang, sizeX, sizeY)
  287.     end
  288.     return nil
  289. end
  290.  
  291. function ENT:CreateMesh()
  292.    
  293.     --PrintTable(self.RoomData)
  294.    
  295.     -- Back side.
  296.     local sizeY = 0
  297.     do
  298.         local pos = Vector(0, 0, 0)
  299.         local data = self.RoomData[DATA_BACK_SIDE]
  300.         local ang = Angle(SEGMENT_DIRECTION[DATA_BACK_SIDE])
  301.         for _,v in pairs(data) do
  302.             local obj = self:CreateEntry(v, pos, ang, sizeX, sizeY)
  303.             sizeY = sizeY + obj.Width
  304.             pos = pos + (_Angle:Right() * obj.Width)
  305.         end
  306.     end
  307.  
  308.     -- Left side.
  309.     local sizeX = 0
  310.     do
  311.         local pos = Vector(WALL_SEGMENT_W, 0, 0)
  312.         local data = self.RoomData[DATA_LEFT_SIDE]
  313.         local ang = Angle(SEGMENT_DIRECTION[DATA_LEFT_SIDE])
  314.         for _,v in pairs(data) do
  315.             local obj = self:CreateEntry(v, pos, ang, sizeX, sizeY)
  316.             sizeX = sizeX + obj.Width
  317.             pos = pos + (_Angle:Forward() * obj.Width)
  318.         end
  319.     end
  320.  
  321.     -- Right side.
  322.     do
  323.         local pos = Vector(0, -sizeY, 0)
  324.         local data = self.RoomData[DATA_RIGHT_SIDE]
  325.         local ang = Angle(SEGMENT_DIRECTION[DATA_RIGHT_SIDE])
  326.         for _,v in pairs(data) do
  327.             local obj = self:CreateEntry(v, pos, ang, sizeX, sizeY)
  328.             pos = pos + (_Angle:Forward() * obj.Width)
  329.         end
  330.     end
  331.  
  332.     -- Front side.
  333.     do
  334.         local pos = Vector(sizeX, -WALL_SEGMENT_W, 0)
  335.         local data = self.RoomData[DATA_FRONT_SIDE]
  336.         local ang = Angle(SEGMENT_DIRECTION[DATA_FRONT_SIDE])
  337.         for _,v in pairs(data) do
  338.             local obj = self:CreateEntry(v, pos, ang)
  339.             pos = pos + (_Angle:Right() * obj.Width)
  340.         end
  341.     end
  342.  
  343.     -- Floor
  344.     do
  345.         local pos = Vector(sizeX, -sizeY, 0)
  346.         local data = self.RoomData[DATA_FLOOR]
  347.         local ang = Angle(SEGMENT_DIRECTION[DATA_FLOOR])
  348.         for _,v in pairs(data) do
  349.             self:CreateEntry(v, pos, ang, sizeX, sizeY)
  350.         end
  351.     end
  352.  
  353.     -- Ceiling
  354.     do
  355.         local pos = Vector(0, -sizeY, 0)
  356.         local data = self.RoomData[DATA_CEILING]
  357.         local ang = Angle(SEGMENT_DIRECTION[DATA_CEILING])
  358.         for _,v in pairs(data) do
  359.             self:CreateEntry(v, pos, ang, sizeX, sizeY)
  360.         end
  361.     end
  362.  
  363. end
  364.  
  365. function ENT:ComputeBounds()
  366.     if CLIENT then
  367.         --return
  368.     end
  369.     local mins = Vector(999999, 999999, 9999999)
  370.     local maxs = Vector(0, 0, 0)
  371.     for _,v in pairs(self.Objects) do
  372.         if v.Verts == nil then
  373.             continue
  374.         end
  375.         for _, vert in pairs(v.Verts) do
  376.             mins.x = math.min(vert.pos.x, mins.x)
  377.             mins.y = math.min(vert.pos.y, mins.y)
  378.             mins.z = math.min(vert.pos.z, mins.z)
  379.            
  380.             maxs.x = math.max(vert.pos.x, maxs.x)
  381.             maxs.y = math.max(vert.pos.y, maxs.y)
  382.             maxs.z = math.max(vert.pos.z, maxs.z)
  383.         end
  384.     end
  385.     print(mins, maxs)
  386.     self:SetCollisionBounds(mins, maxs)
  387. end
  388.  
  389. function ENT:CreatePhysics()
  390.     if CLIENT then
  391.         --return
  392.     end
  393.     local verts = {}
  394.     for _,v in pairs(self.Objects) do
  395.         if v.Verts == nil then
  396.             continue
  397.         end
  398.         for _, vert in pairs(v.Verts) do
  399.             table.insert(verts, vert)
  400.         end
  401.     end
  402.     self:PhysicsFromMesh(verts)
  403.     self:SetMoveType(MOVETYPE_VPHYSICS)
  404.     self:SetSolid(SOLID_VPHYSICS)
  405.     self:EnableCustomCollisions(true)
  406.     local phys = self:GetPhysicsObject()
  407.     if IsValid(phys) then
  408.         phys:EnableMotion(false)   
  409.     end
  410.    
  411. end
  412.  
  413. function ENT:CreateRoom(seed, maxSegmentsW, maxSegmentsH)
  414.    
  415.     if maxSegmentsW == nil then
  416.         maxSegmentsW = 3
  417.     end
  418.     if maxSegmentsH == nil then
  419.         maxSegmentsH = 5
  420.     end
  421.     if seed == nil then
  422.         seed = 1
  423.     end
  424.    
  425.     if SERVER then
  426.         self:SetRoomSeed(seed)
  427.         self:SetRoomWidth(maxSegmentsW)
  428.         self:SetRoomHeight(maxSegmentsH)
  429.         self:SetRoomCycle(self:GetRoomCycle() + 1)
  430.     end
  431.    
  432.     self.Objects = {}
  433.     self.RoomData = {}
  434.     self.RoomData[DATA_LEFT_SIDE] = {}
  435.     self.RoomData[DATA_RIGHT_SIDE] = {}
  436.     self.RoomData[DATA_BACK_SIDE] = {}
  437.     self.RoomData[DATA_FRONT_SIDE] = {}
  438.    
  439.     self.RoomData[DATA_FLOOR] = {}
  440.     self.RoomData[DATA_CEILING] = {}
  441.    
  442.     math.randomseed(seed)
  443.    
  444.     -- Walls
  445.     do
  446.        
  447.         -- Note this is represented in 2d coordinates from a top view.
  448.         local segmentsHeight = math.random(2, maxSegmentsH)
  449.         local segmentsWidth = math.random(2, maxSegmentsW)
  450.        
  451.         -- Begin with the back of the room.
  452.         for i = 1, segmentsWidth do
  453.             local data = self.RoomData[DATA_BACK_SIDE]
  454.             table.insert(data, DATA_ENTRY_WALL)
  455.         end
  456.        
  457.         -- Front has equal amount.
  458.         for i = 1, segmentsWidth do
  459.             local data = self.RoomData[DATA_FRONT_SIDE]
  460.             table.insert(data, DATA_ENTRY_WALL)
  461.         end
  462.        
  463.         -- Left side.
  464.         for i = 1, segmentsHeight do
  465.             local data = self.RoomData[DATA_LEFT_SIDE]
  466.             table.insert(data, DATA_ENTRY_WALL)
  467.         end
  468.        
  469.         -- Right side.
  470.         for i = 1, segmentsHeight do
  471.             local data = self.RoomData[DATA_RIGHT_SIDE]
  472.             table.insert(data, DATA_ENTRY_WALL)
  473.         end
  474.        
  475.         -- One floor
  476.         for i = 1, 1 do
  477.             local data = self.RoomData[DATA_FLOOR]
  478.             table.insert(data, DATA_ENTRY_FLOOR)
  479.         end
  480.        
  481.         -- One ceiling
  482.         for i = 1, 1 do
  483.             local data = self.RoomData[DATA_CEILING]
  484.             table.insert(data, DATA_ENTRY_CEILING)
  485.         end
  486.  
  487.     end
  488.  
  489.     -- Doors
  490.     -- TODO: Conditionally.
  491.     do
  492.         for _,v in pairs(self.RoomData) do
  493.             if #v == 0 then
  494.                 continue
  495.             end
  496.             local selected = math.random(1, #v)
  497.             if v[selected] == DATA_ENTRY_WALL then
  498.                 -- Turn into door.
  499.                 v[selected] = DATA_ENTRY_DOOR
  500.             end
  501.         end
  502.     end
  503.    
  504.     --PrintTable(self.RoomData)
  505.    
  506.     self:CreateMesh()
  507.     self:ComputeBounds()
  508.     self:CreatePhysics()
  509.     self:ComputeBounds()
  510.    
  511. end
  512.  
  513. function ENT:Think()
  514.    
  515.     local phys = self:GetPhysicsObject()
  516.            
  517.     if CLIENT then
  518.         self:SetNextClientThink(CurTime())
  519.    
  520.         local serverCycle = self:GetRoomCycle()
  521.         if self.RoomCycle ~= serverCycle then
  522.             self.RoomCycle = serverCycle
  523.            
  524.             local seed = self:GetRoomSeed()
  525.             local roomW = self:GetRoomWidth()
  526.             local roomH = self:GetRoomHeight()
  527.            
  528.             self:CreateRoom(seed, roomW, roomH)
  529.         end
  530.        
  531.         if IsValid(phys) then
  532.             local newPos = LerpVector(FrameTime() * 20, phys:GetPos(), self:GetRoomPos())
  533.             local newAng = LerpAngle(FrameTime() * 20, phys:GetAngles(), self:GetRoomAng())
  534.             phys:SetPos(newPos)
  535.             phys:SetAngles(newAng)
  536.             --phys:EnableMotion(false)
  537.         end
  538.     else
  539.        
  540.         self:NextThink(CurTime())
  541.         --self:CreateRoom(CurTime(), 10, 10)
  542.         if IsValid(phys) then
  543.             self:SetRoomPos(phys:GetPos())
  544.             self:SetRoomAng(phys:GetAngles())
  545.             --phys:EnableMotion(false)
  546.         end
  547.     end
  548.    
  549.     return true
  550.  
  551. end
  552.  
  553. function ENT:Draw()
  554.    
  555.     local vmat = Matrix()
  556.     vmat:SetTranslation(self:GetPos())
  557.     vmat:SetAngles(self:GetAngles())
  558.            
  559.     cam.PushModelMatrix(vmat)
  560.     for _,v in pairs(self.Objects) do
  561.         if v.Mesh == nil then
  562.             continue
  563.         end
  564.         render.SetMaterial(v.Mat)
  565.         v.Mesh:Draw()      
  566.     end
  567.     cam.PopModelMatrix(vmat)
  568.    
  569. end
  570.  
  571. scripted_ents.Register( ENT, "lua_room" )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement