|
@@ -0,0 +1,177 @@
|
|
|
|
|
+local Bresenham = require("bresenham/bresenham")
|
|
|
|
|
+local Delaunay = require("delaunay/delaunay")
|
|
|
|
|
+local Point = Delaunay.Point
|
|
|
|
|
+local Map = require("Map")
|
|
|
|
|
+local Room = require("Room")
|
|
|
|
|
+
|
|
|
|
|
+local Node = require("Graph/Node")
|
|
|
|
|
+local Graph = require("Graph/Graph")
|
|
|
|
|
+local MST = require("Graph/MST")
|
|
|
|
|
+
|
|
|
|
|
+require("func")
|
|
|
|
|
+
|
|
|
|
|
+local Generator = {
|
|
|
|
|
+ _VERSION = "0",
|
|
|
|
|
+
|
|
|
|
|
+ DIMENSION=64,
|
|
|
|
|
+ NB_ROOMS = 400
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+function roundm(n, m) return math.floor(((n + m - 1)/m))*m end
|
|
|
|
|
+
|
|
|
|
|
+function getRandomPointInCircle(radius)
|
|
|
|
|
+ local t = 2*math.pi*math.random()
|
|
|
|
|
+ local u = math.random()+math.random()
|
|
|
|
|
+ local r = nil
|
|
|
|
|
+ if u > 1 then r = 2-u else r = u end
|
|
|
|
|
+ return radius*r*math.cos(t), radius*r*math.sin(t)
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+function trim_table(t, indices)
|
|
|
|
|
+ function reverse(tbl)
|
|
|
|
|
+ local r = {}
|
|
|
|
|
+ for i=1, math.floor(#tbl / 2) do
|
|
|
|
|
+ r[i], r[#tbl - i + 1] = tbl[#tbl - i + 1], tbl[i]
|
|
|
|
|
+ end
|
|
|
|
|
+ return r
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ -- We're reversing the indcies to avoid removing the wrong rooms by popping the items.
|
|
|
|
|
+ for _,i in pairs(reverse(indices)) do
|
|
|
|
|
+ table.remove(t, i)
|
|
|
|
|
+ end
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+-- Dirty and unoptimized room generation
|
|
|
|
|
+function generate_rooms()
|
|
|
|
|
+ local rooms = {}
|
|
|
|
|
+ for i=1, Generator.NB_ROOMS do
|
|
|
|
|
+ width,height = roundm(math.pow(math.random(), 2)*10+2,1), roundm(math.pow(math.random(), 2)*10+2,1)
|
|
|
|
|
+ local x,y= getRandomPointInCircle(16-math.max(width, height))
|
|
|
|
|
+ x = x+Generator.DIMENSION/2
|
|
|
|
|
+ y = y+Generator.DIMENSION/2
|
|
|
|
|
+ local r = Room(x, y, width, height)
|
|
|
|
|
+ table.insert(rooms, r)
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ local done = false
|
|
|
|
|
+ local pass = 0
|
|
|
|
|
+ while not done do
|
|
|
|
|
+ -- Repulsion calculation
|
|
|
|
|
+ for a_i, a in pairs(rooms) do
|
|
|
|
|
+ a.vx, a.vy = 0,0
|
|
|
|
|
+ for b_i, b in pairs(rooms) do
|
|
|
|
|
+ if (a_i ~= b_i) and a:intersects(b) then
|
|
|
|
|
+ local dx = a.x - b.x
|
|
|
|
|
+ local dy = a.y - b.y
|
|
|
|
|
+ local l = math.sqrt(dx*dx + dy*dy)
|
|
|
|
|
+ a.vx = a.vx + dx/l
|
|
|
|
|
+ a.vy = a.vy + dy/l
|
|
|
|
|
+ break
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ -- Repulsion applicaiton and room carving
|
|
|
|
|
+ for _, room in pairs(rooms) do
|
|
|
|
|
+ local l = math.sqrt(room.vx*room.vx + room.vy*room.vy)
|
|
|
|
|
+ if l >= 0.01 then
|
|
|
|
|
+ room.x = room.x + room.vx/l
|
|
|
|
|
+ room.y = room.y + room.vy/l
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ -- triming out of bounds rooms
|
|
|
|
|
+ for i=#rooms,1,-1 do
|
|
|
|
|
+ local room = rooms[i]
|
|
|
|
|
+ if room.x < 1 or room.y < 1 or room.x >= Generator.DIMENSION-room.width-1 or room.y >= Generator.DIMENSION-room.height-1 then
|
|
|
|
|
+ table.remove(rooms, i)
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ -- Exit check
|
|
|
|
|
+ done = true
|
|
|
|
|
+ for a_i, a in pairs(rooms) do
|
|
|
|
|
+ for b_i, b in pairs(rooms) do
|
|
|
|
|
+ if a_i ~= b_i and a:intersects(b) then
|
|
|
|
|
+ done = false
|
|
|
|
|
+ break
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+ if not done then break end
|
|
|
|
|
+ end
|
|
|
|
|
+ pass = pass+1
|
|
|
|
|
+ end
|
|
|
|
|
+ return rooms
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+function Generator.generate(seed)
|
|
|
|
|
+ math.randomseed(seed)
|
|
|
|
|
+
|
|
|
|
|
+ local rooms = generate_rooms()
|
|
|
|
|
+ -- Keeping the biggest rooms
|
|
|
|
|
+ local biggest_rooms = filter(function(r) return r.width >= 4 and r.height >= 4 end, rooms)
|
|
|
|
|
+
|
|
|
|
|
+ -- Generating their centers
|
|
|
|
|
+ local centers = map(function(r) return Point(r.x+r.width/2, r.y+r.height/2) end, biggest_rooms)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ local triangles = Delaunay.triangulate(unpack(centers))
|
|
|
|
|
+ local edges = {}
|
|
|
|
|
+ for i, triangle in ipairs(triangles) do
|
|
|
|
|
+ for _,edge in pairs({triangle.e1, triangle.e2, triangle.e3}) do
|
|
|
|
|
+ local found = false
|
|
|
|
|
+ for _,v in pairs(edges) do
|
|
|
|
|
+ if v == edge then
|
|
|
|
|
+ found = true
|
|
|
|
|
+ break
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+ if not found then
|
|
|
|
|
+ table.insert(edges, edge)
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ local graph = Graph(centers, edges)
|
|
|
|
|
+ local res = graph
|
|
|
|
|
+ if #edges > 3 then
|
|
|
|
|
+ res = MST.search(graph,
|
|
|
|
|
+ function(edge)
|
|
|
|
|
+ local dx = edge.p1.x - edge.p2.x
|
|
|
|
|
+ local dy = edge.p1.y - edge.p2.y
|
|
|
|
|
+ return math.sqrt(dx*dx+dy*dy)
|
|
|
|
|
+ end
|
|
|
|
|
+ )
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ local m = Map(Generator.DIMENSION, Generator.DIMENSION)
|
|
|
|
|
+ for _, r in pairs(biggest_rooms) do
|
|
|
|
|
+ m:carve(r)
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ for _,edge in pairs(res.edges) do
|
|
|
|
|
+ local vertices_ok = 0
|
|
|
|
|
+ for _,c in pairs(centers) do
|
|
|
|
|
+ if edge.p1.id ==c.id or edge.p2.id == c.id then
|
|
|
|
|
+ vertices_ok = vertices_ok + 1
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+ if vertices_ok == 2 then
|
|
|
|
|
+ Bresenham.los(math.floor(edge.p1.x), math.floor(edge.p1.y), math.floor(edge.p2.x), math.floor(edge.p2.y),
|
|
|
|
|
+ function(x, y)
|
|
|
|
|
+ m.tiles[y][x] = 0
|
|
|
|
|
+ return true
|
|
|
|
|
+ end
|
|
|
|
|
+ )
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+ return m
|
|
|
|
|
+end
|
|
|
|
|
+return Generator
|