Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local ENT = {}
- ENT.Type = "anim"
- ENT.Base = "base_anim"
- ENT.Spawnable = true
- ENT.AdminSpawnable = true
- ENT.PrintName = "Lua Room"
- local MAT_FLOOR = Material("hunter/myplastic")
- local MAT_CEILING = Material("hunter/myplastic")
- local MAT_WALL = Material("hunter/myplastic")
- local MAT_DOORWAY = Material("hunter/myplastic")
- -- Mapped as
- -- F
- -- L R
- -- B
- local DATA_LEFT_SIDE = 1
- local DATA_FRONT_SIDE = 2
- local DATA_RIGHT_SIDE = 3
- local DATA_BACK_SIDE = 4
- local DATA_FLOOR = 5
- local DATA_CEILING = 6
- -- +x = FWD
- -- +y = LEFT
- local _Angle = Angle(0, 0, 0)
- local SEGMENT_DIRECTION =
- {
- [DATA_LEFT_SIDE] = (-_Angle:Right()):Angle(),
- [DATA_FRONT_SIDE] = (_Angle:Forward()):Angle(),
- [DATA_RIGHT_SIDE] = (_Angle:Right()):Angle(),
- [DATA_BACK_SIDE] = (-_Angle:Forward()):Angle(),
- [DATA_FLOOR] = (_Angle:Up()):Angle(),
- [DATA_CEILING] = (-_Angle:Up()):Angle(),
- }
- local WALL_SEGMENT_W = 128
- local WALL_SEGMENT_H = 128
- local DOOR_SEGMENT_W = 48
- local DOOR_SEGMENT_H = 108
- local DATA_ENTRY_WALL = 1
- local DATA_ENTRY_DOOR = 2
- local DATA_ENTRY_FLOOR = 3
- local DATA_ENTRY_CEILING = 4
- function ENT:SetupDataTables()
- self:NetworkVar("Int", 0, "RoomCycle")
- self:NetworkVar("Int", 1, "RoomSeed")
- self:NetworkVar("Int", 2, "RoomWidth")
- self:NetworkVar("Int", 3, "RoomHeight")
- self:NetworkVar("Float", 0, "RoomPosX")
- self:NetworkVar("Float", 1, "RoomPosY")
- self:NetworkVar("Float", 2, "RoomPosZ")
- self:NetworkVar("Float", 3, "RoomAngX")
- self:NetworkVar("Float", 4, "RoomAngY")
- self:NetworkVar("Float", 5, "RoomAngZ")
- end
- function ENT:GetRoomPos()
- return Vector(self:GetRoomPosX(), self:GetRoomPosY(), self:GetRoomPosZ())
- end
- function ENT:SetRoomPos(pos)
- self:SetRoomPosX(pos.x)
- self:SetRoomPosY(pos.y)
- self:SetRoomPosZ(pos.z)
- end
- function ENT:GetRoomAng()
- return Angle(self:GetRoomAngX(), self:GetRoomAngY(), self:GetRoomAngZ())
- end
- function ENT:SetRoomAng(ang)
- self:SetRoomAngX(ang.x)
- self:SetRoomAngY(ang.y)
- self:SetRoomAngZ(ang.z)
- end
- function ENT:Initialize()
- -- Data
- self.RoomData = self.RoomData or {}
- self.RoomData[DATA_LEFT_SIDE] = self.RoomData[DATA_LEFT_SIDE] or {}
- self.RoomData[DATA_RIGHT_SIDE] = self.RoomData[DATA_RIGHT_SIDE] or {}
- self.RoomData[DATA_BACK_SIDE] = self.RoomData[DATA_BACK_SIDE] or {}
- self.RoomData[DATA_FRONT_SIDE] = self.RoomData[DATA_FRONT_SIDE] or {}
- self.RoomData[DATA_FLOOR] = self.RoomData[DATA_FLOOR] or {}
- self.RoomData[DATA_CEILING] = self.RoomData[DATA_CEILING] or {}
- -- Meshes.
- self.Objects = self.Objects or {}
- if CLIENT then
- self.RoomCycle = -1
- else
- self:SetRoomCycle(-1)
- end
- self:SetModel("models/props_combine/breenglobe.mdl")
- if CLIENT then
- self:SetRenderBounds(Vector(-2000, -2000, -2000), Vector(2000, 2000, 2000))
- else
- self:CreateRoom(1, 10, 10)
- end
- end
- function ENT:OnReloaded()
- if SERVER then
- self:CreateRoom(self:GetRoomSeed(), self:GetRoomWidth(), self:GetRoomHeight())
- end
- end
- function ENT:AddQuad(verts, pos, w, h, ang)
- local mat = Matrix()
- mat:SetTranslation(Vector(0, 0, 0))
- mat:SetAngles(ang)
- --pos = mat:__mul(pos)
- -- FIXME: Scale this shit properly.
- local uScale = 1
- local vScale = 1
- local newVerts = {
- -- Front side.
- { pos = pos + mat:__mul(Vector( 0, 0, 0 )), u = 1 * uScale, v = 1 * vScale },
- { pos = pos + mat:__mul(Vector( 0, w, 0 )), u = 1 * uScale, v = 0 * vScale },
- { pos = pos + mat:__mul(Vector( 0, w, h )), u = 0 * uScale, v = 0 * vScale },
- { pos = pos + mat:__mul(Vector( 0, w, h )), u = 1 * uScale, v = 1 * vScale },
- { pos = pos + mat:__mul(Vector( 0, 0, h )), u = 0 * uScale, v = 1 * vScale },
- { pos = pos + mat:__mul(Vector( 0, 0, 0 )), u = 0 * uScale, v = 0 * vScale },
- -- Back side.
- { pos = pos + mat:__mul(Vector( 0, w, h )), u = 0 * uScale, v = 0 * vScale },
- { pos = pos + mat:__mul(Vector( 0, w, 0 )), u = 1 * uScale, v = 0 * vScale },
- { pos = pos + mat:__mul(Vector( 0, 0, 0 )), u = 1 * uScale, v = 1 * vScale },
- { pos = pos + mat:__mul(Vector( 0, 0, 0 )), u = 0 * uScale, v = 0 * vScale },
- { pos = pos + mat:__mul(Vector( 0, 0, h )), u = 0 * uScale, v = 1 * vScale },
- { pos = pos + mat:__mul(Vector( 0, w, h )), u = 1 * uScale, v = 1 * vScale },
- }
- for _,v in pairs(newVerts) do
- table.insert(verts, v)
- end
- end
- function ENT:CreateWallSegment(pos, ang)
- local verts = {}
- self:AddQuad(verts, pos, WALL_SEGMENT_W, WALL_SEGMENT_H, ang)
- local wall = {}
- wall.Verts = verts
- wall.Width = WALL_SEGMENT_W
- wall.Height = WALL_SEGMENT_H
- wall.Type = DATA_ENTRY_WALL
- wall.Mat = MAT_WALL
- if CLIENT then
- local obj = Mesh()
- obj:BuildFromTriangles(verts)
- wall.Mesh = obj
- end
- table.insert(self.Objects, wall)
- return wall
- end
- function ENT:CreateDoorSegment(pos, ang)
- local verts = {}
- -- Door segment has a small gap fill above door entry
- -- Left and right side wall.
- local wallSize = WALL_SEGMENT_W - DOOR_SEGMENT_W
- local wallSizeLeft = wallSize / 2
- local wallSizeRight = wallSize / 2
- local doorGapHeight = WALL_SEGMENT_H - DOOR_SEGMENT_H
- local doorGapZ = DOOR_SEGMENT_H
- local p = Vector(pos)
- -- Left wall
- self:AddQuad(verts, p, wallSizeLeft, WALL_SEGMENT_H, ang)
- p = p - (ang:Right() * wallSizeLeft)
- -- Gap
- self:AddQuad(verts, p + Vector(0, 0, doorGapZ), DOOR_SEGMENT_W, doorGapHeight, ang)
- p = p - (ang:Right() * DOOR_SEGMENT_W)
- -- Right wall
- self:AddQuad(verts, p, wallSizeLeft, WALL_SEGMENT_H, ang)
- --pos = pos + (ang:Right() * wallSizeRight)
- local door = {}
- door.Verts = verts
- door.Width = WALL_SEGMENT_W
- door.Height = DOOR_SEGMENT_H
- door.Type = DATA_ENTRY_DOOR
- door.Mat = MAT_DOORWAY
- if CLIENT then
- local obj = Mesh()
- obj:BuildFromTriangles(verts)
- door.Mesh = obj
- end
- table.insert(self.Objects, door)
- return door
- end
- function ENT:CreateFloorSegment(pos, ang, sizeX, sizeY)
- local verts = {}
- self:AddQuad(verts, pos, sizeY, sizeX, ang)
- local floor = {}
- floor.Verts = verts
- floor.Width = sizeX
- floor.Height = sizeY
- floor.Type = DATA_ENTRY_FLOOR
- floor.Mat = MAT_FLOOR
- if CLIENT then
- local obj = Mesh()
- obj:BuildFromTriangles(verts)
- floor.Mesh = obj
- end
- table.insert(self.Objects, floor)
- return floor
- end
- function ENT:CreateCeilingSegment(pos, ang, sizeX, sizeY)
- local verts = {}
- self:AddQuad(verts, pos + Vector(0, 0, WALL_SEGMENT_H), sizeY, sizeX, ang)
- local ceiling = {}
- ceiling.Verts = verts
- ceiling.Width = sizeX
- ceiling.Height = sizeY
- ceiling.Type = DATA_ENTRY_CEILING
- ceiling.Mat = MAT_CEILING
- if CLIENT then
- local obj = Mesh()
- obj:BuildFromTriangles(verts)
- ceiling.Mesh = obj
- end
- table.insert(self.Objects, ceiling)
- return ceiling
- end
- function ENT:CreateEntry(v, pos, ang, sizeX, sizeY)
- if v == DATA_ENTRY_WALL then
- return self:CreateWallSegment(pos, ang, sizeX, sizeY)
- elseif v == DATA_ENTRY_DOOR then
- return self:CreateDoorSegment(pos, ang, sizeX, sizeY)
- elseif v == DATA_ENTRY_FLOOR then
- return self:CreateFloorSegment(pos, ang, sizeX, sizeY)
- elseif v == DATA_ENTRY_CEILING then
- return self:CreateCeilingSegment(pos, ang, sizeX, sizeY)
- end
- return nil
- end
- function ENT:CreateMesh()
- --PrintTable(self.RoomData)
- -- Back side.
- local sizeY = 0
- do
- local pos = Vector(0, 0, 0)
- local data = self.RoomData[DATA_BACK_SIDE]
- local ang = Angle(SEGMENT_DIRECTION[DATA_BACK_SIDE])
- for _,v in pairs(data) do
- local obj = self:CreateEntry(v, pos, ang, sizeX, sizeY)
- sizeY = sizeY + obj.Width
- pos = pos + (_Angle:Right() * obj.Width)
- end
- end
- -- Left side.
- local sizeX = 0
- do
- local pos = Vector(WALL_SEGMENT_W, 0, 0)
- local data = self.RoomData[DATA_LEFT_SIDE]
- local ang = Angle(SEGMENT_DIRECTION[DATA_LEFT_SIDE])
- for _,v in pairs(data) do
- local obj = self:CreateEntry(v, pos, ang, sizeX, sizeY)
- sizeX = sizeX + obj.Width
- pos = pos + (_Angle:Forward() * obj.Width)
- end
- end
- -- Right side.
- do
- local pos = Vector(0, -sizeY, 0)
- local data = self.RoomData[DATA_RIGHT_SIDE]
- local ang = Angle(SEGMENT_DIRECTION[DATA_RIGHT_SIDE])
- for _,v in pairs(data) do
- local obj = self:CreateEntry(v, pos, ang, sizeX, sizeY)
- pos = pos + (_Angle:Forward() * obj.Width)
- end
- end
- -- Front side.
- do
- local pos = Vector(sizeX, -WALL_SEGMENT_W, 0)
- local data = self.RoomData[DATA_FRONT_SIDE]
- local ang = Angle(SEGMENT_DIRECTION[DATA_FRONT_SIDE])
- for _,v in pairs(data) do
- local obj = self:CreateEntry(v, pos, ang)
- pos = pos + (_Angle:Right() * obj.Width)
- end
- end
- -- Floor
- do
- local pos = Vector(sizeX, -sizeY, 0)
- local data = self.RoomData[DATA_FLOOR]
- local ang = Angle(SEGMENT_DIRECTION[DATA_FLOOR])
- for _,v in pairs(data) do
- self:CreateEntry(v, pos, ang, sizeX, sizeY)
- end
- end
- -- Ceiling
- do
- local pos = Vector(0, -sizeY, 0)
- local data = self.RoomData[DATA_CEILING]
- local ang = Angle(SEGMENT_DIRECTION[DATA_CEILING])
- for _,v in pairs(data) do
- self:CreateEntry(v, pos, ang, sizeX, sizeY)
- end
- end
- end
- function ENT:ComputeBounds()
- if CLIENT then
- --return
- end
- local mins = Vector(999999, 999999, 9999999)
- local maxs = Vector(0, 0, 0)
- for _,v in pairs(self.Objects) do
- if v.Verts == nil then
- continue
- end
- for _, vert in pairs(v.Verts) do
- mins.x = math.min(vert.pos.x, mins.x)
- mins.y = math.min(vert.pos.y, mins.y)
- mins.z = math.min(vert.pos.z, mins.z)
- maxs.x = math.max(vert.pos.x, maxs.x)
- maxs.y = math.max(vert.pos.y, maxs.y)
- maxs.z = math.max(vert.pos.z, maxs.z)
- end
- end
- print(mins, maxs)
- self:SetCollisionBounds(mins, maxs)
- end
- function ENT:CreatePhysics()
- if CLIENT then
- --return
- end
- local verts = {}
- for _,v in pairs(self.Objects) do
- if v.Verts == nil then
- continue
- end
- for _, vert in pairs(v.Verts) do
- table.insert(verts, vert)
- end
- end
- self:PhysicsFromMesh(verts)
- self:SetMoveType(MOVETYPE_VPHYSICS)
- self:SetSolid(SOLID_VPHYSICS)
- self:EnableCustomCollisions(true)
- local phys = self:GetPhysicsObject()
- if IsValid(phys) then
- phys:EnableMotion(false)
- end
- end
- function ENT:CreateRoom(seed, maxSegmentsW, maxSegmentsH)
- if maxSegmentsW == nil then
- maxSegmentsW = 3
- end
- if maxSegmentsH == nil then
- maxSegmentsH = 5
- end
- if seed == nil then
- seed = 1
- end
- if SERVER then
- self:SetRoomSeed(seed)
- self:SetRoomWidth(maxSegmentsW)
- self:SetRoomHeight(maxSegmentsH)
- self:SetRoomCycle(self:GetRoomCycle() + 1)
- end
- self.Objects = {}
- self.RoomData = {}
- self.RoomData[DATA_LEFT_SIDE] = {}
- self.RoomData[DATA_RIGHT_SIDE] = {}
- self.RoomData[DATA_BACK_SIDE] = {}
- self.RoomData[DATA_FRONT_SIDE] = {}
- self.RoomData[DATA_FLOOR] = {}
- self.RoomData[DATA_CEILING] = {}
- math.randomseed(seed)
- -- Walls
- do
- -- Note this is represented in 2d coordinates from a top view.
- local segmentsHeight = math.random(2, maxSegmentsH)
- local segmentsWidth = math.random(2, maxSegmentsW)
- -- Begin with the back of the room.
- for i = 1, segmentsWidth do
- local data = self.RoomData[DATA_BACK_SIDE]
- table.insert(data, DATA_ENTRY_WALL)
- end
- -- Front has equal amount.
- for i = 1, segmentsWidth do
- local data = self.RoomData[DATA_FRONT_SIDE]
- table.insert(data, DATA_ENTRY_WALL)
- end
- -- Left side.
- for i = 1, segmentsHeight do
- local data = self.RoomData[DATA_LEFT_SIDE]
- table.insert(data, DATA_ENTRY_WALL)
- end
- -- Right side.
- for i = 1, segmentsHeight do
- local data = self.RoomData[DATA_RIGHT_SIDE]
- table.insert(data, DATA_ENTRY_WALL)
- end
- -- One floor
- for i = 1, 1 do
- local data = self.RoomData[DATA_FLOOR]
- table.insert(data, DATA_ENTRY_FLOOR)
- end
- -- One ceiling
- for i = 1, 1 do
- local data = self.RoomData[DATA_CEILING]
- table.insert(data, DATA_ENTRY_CEILING)
- end
- end
- -- Doors
- -- TODO: Conditionally.
- do
- for _,v in pairs(self.RoomData) do
- if #v == 0 then
- continue
- end
- local selected = math.random(1, #v)
- if v[selected] == DATA_ENTRY_WALL then
- -- Turn into door.
- v[selected] = DATA_ENTRY_DOOR
- end
- end
- end
- --PrintTable(self.RoomData)
- self:CreateMesh()
- self:ComputeBounds()
- self:CreatePhysics()
- self:ComputeBounds()
- end
- function ENT:Think()
- local phys = self:GetPhysicsObject()
- if CLIENT then
- self:SetNextClientThink(CurTime())
- local serverCycle = self:GetRoomCycle()
- if self.RoomCycle ~= serverCycle then
- self.RoomCycle = serverCycle
- local seed = self:GetRoomSeed()
- local roomW = self:GetRoomWidth()
- local roomH = self:GetRoomHeight()
- self:CreateRoom(seed, roomW, roomH)
- end
- if IsValid(phys) then
- local newPos = LerpVector(FrameTime() * 20, phys:GetPos(), self:GetRoomPos())
- local newAng = LerpAngle(FrameTime() * 20, phys:GetAngles(), self:GetRoomAng())
- phys:SetPos(newPos)
- phys:SetAngles(newAng)
- --phys:EnableMotion(false)
- end
- else
- self:NextThink(CurTime())
- --self:CreateRoom(CurTime(), 10, 10)
- if IsValid(phys) then
- self:SetRoomPos(phys:GetPos())
- self:SetRoomAng(phys:GetAngles())
- --phys:EnableMotion(false)
- end
- end
- return true
- end
- function ENT:Draw()
- local vmat = Matrix()
- vmat:SetTranslation(self:GetPos())
- vmat:SetAngles(self:GetAngles())
- cam.PushModelMatrix(vmat)
- for _,v in pairs(self.Objects) do
- if v.Mesh == nil then
- continue
- end
- render.SetMaterial(v.Mat)
- v.Mesh:Draw()
- end
- cam.PopModelMatrix(vmat)
- end
- scripted_ents.Register( ENT, "lua_room" )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement