# Class to produce random map layouts
# based on this code: http://www.roguebasin.com/index.php?title=Dungeon_builder_written_in_Python
# Original author: Steve Wallace
# Ruby-version author: DeadElf79
# e-mail me deadelf@gmail.com if you found error
class DungeonMap
# Initialize
#
def initialize
@room_list=[]
@cor_list=[]
end
# Generate random layout of rooms, corridors and
# other features
# This method can be modified to accept arguments for
# values of failed, and percentile of features.
#
def make_map(xs, ys, fail, b1, mrooms)
# Create first room
@xsize = xs
@ysize = ys
# initialize map to all walls
@mapArr= []
@ysize.times{
@mapArr<<Array.new(@xsize,1)
}
w,l,t=make_room
while @room_list.size==0
x=rand(@xsize-1-w)+1
y=rand(@ysize-1-l)+1
p=place_room(l,w,x,y,@xsize,@ysize,6,0)
end
failed=0
while failed<fail # The lower the value that failed<, the smaller the dungeon
choose_room=rand(@room_list.size)
ex,ey,ex2,ey2,et=make_exit(choose_room)
feature=rand(100)
if feature<b1 # Begin feature choosing (more features to be added here)
w,l,t=make_corridor
else
w,l,t=make_room
end
room_done=place_room(l,w,ex2,ey2,@xsize,@ysize,t,et)
case room_done
when 0 # If placement failed increase possibility map is full
failed+=1
when 2 # If Possibility of linking rooms
if @mapArr[ey2][ex2]==0
if rand(100)<7
make_portal(ex,ey)
end
failed+=1
end
else # Otherwise, link up the 2 rooms
make_portal(ex,ey)
failed=0
if t<5
tc=[@room_list.size-1,ex2,ey2,t]
@cor_list<<tc
join_corridor(@room_list.size-1,ex2,ey2,t,50)
end
end
failed=fail if @room_list.size==mrooms
end
final_joins
@mapArr
end
# Randomly produce room size
#
def make_room
rtype=5
rwide=rand(8)+3
rlong=rand(8)+3
return rtype,rwide,rlong
end
# Randomly produce corridor length and heading
#
def make_corridor
clength=rand(18)+3
heading=rand(3)
case heading
when 0 # North
wd=1
lg=-clength
when 1 # East
wd=clength
lg=1
when 2 # South
wd=1
lg=clength
when 3 # West
wd=-clength
lg=1
end
return wd,lg,heading
end
# Place feature if enough space and return:
# 0 - if no space
# 1 - add room
# 2 - linking rooms
def place_room(ll,ww,xposs,yposs,xsize,ysize,rty,ext)
# Arrange for heading
xpos=xposs
ypos=yposs
if ll<0 then
ypos+=ll+1
ll=ll.abs
end
if ww<0 then
xpos+=ww+1
ww=ww.abs
end
# Make offset if type is room
if rty==5 then
if ext==(0||2) then
offset=rand(ww)
xpos-=offset
else
offset=rand(ll)
ypos-=offset
end
end
# Then check if there is space
if (ww+xpos+1>xsize-1)||(ll+ypos+1>ysize)
return 0
elsif xpos<1 or ypos<1
return 0
else
ll.times{|j|
ww.times{|k|
return 2 if @mapArr[(ypos-1)+j][(xpos-1)+k]!=1
}
}
end
# If there is space, add to list of rooms
temp=[ll,ww,xpos,ypos]
@room_list<<temp
(ll+2).times{|j|# Then build walls
(ww+2).times{|k|
@mapArr[(ypos-1)+j][(xpos-1)+k]=2
}
}
ll.times{|j|# Then build floor
ww.times{|k|
@mapArr[ypos+j][xpos+k]=0
}
}
return 1
end
# Pick random wall and random point along that wall
#
def make_exit(rn)
room=@room_list[rn]
rx,ry,rx2,ry2,rw=0,0,0,0,0
loop do
rw=rand(3)
case rw
when 0 # North wall
rx=rand(room[1])+room[2]
ry=room[3]-1
rx2=rx
ry2=ry-1
when 1 # East wall
ry=rand(room[0])+room[3]
rx=room[2]+room[1]
rx2=rx+1
ry2=ry
when 2 # South wall
rx=rand(room[1])+room[2]
ry=room[3]+room[0]
rx2=rx
ry2=ry+1
when 3 # West wall
ry=rand(room[0])+room[3]
rx=room[2]-1
rx2=rx-1
ry2=ry
end
break if @mapArr[ry][rx]==2 # If space is a wall, exit
end
return rx,ry,rx2,ry2,rw
end
# Create doors in walls
#
def make_portal(px,py)
ptype=rand(100)
if ptype>90 # Secret door
@mapArr[py][px]=5
elsif ptype>75 # Closed door
@mapArr[py][px]=4
elsif ptype>40 # Open door
@mapArr[py][px]=3
else # Hole in the wall door
@mapArr[py][px]=0
end
end
# Check corridor endpoint and make an exit if it links to another room
#
def join_corridor(cno,xp,yp,ed,psb)
cArea=@room_list[cno]
if xp!=cArea[2] or yp!=cArea[3] # Find the corridor endpoint
endx=xp-(cArea[1]-1)
endy=yp-(cArea[0]-1)
else
endx=xp+(cArea[1]-1)
endy=xp+(cArea[0]-1)
end
check_exit=[]
case ed
when 0 # North corridor
if endx>1
coords=[endx-2,endy,endx-1,endy]
check_exit<<coords
end
if endy>1
coords=[endx,endy-2,endx,endy-1]
check_exit<<coords
end
if endx<@xsize-2
coords=[endx+2,endy,endx+1,endy]
check_exit<<coords
end
when 1 # East corridor
if endy>1
coords=[endx,endy-2,endx,endy-1]
check_exit<<coords
end
if endx<@xsize-2
coords=[endx+2,endy,endx+1,endy]
check_exit<<coords
end
if endy<@ysize-2
coords=[endx,endy+2,endx,endy+1]
check_exit<<coords
end
when 2 # South corridor
if endx<@xsize-2
coords=[endx+2,endy,endx+1,endy]
check_exit<<coords
end
if endy<@ysize-2
coords=[endx,endy+2,endx,endy+1]
check_exit<<coords
end
if endx>1
coords=[endx-2,endy,endx-1,endy]
check_exit<<coords
end
when 3 # West corridor
if endx>1
coords=[endx-2,endy,endx-1,endy]
check_exit<<coords
end
if endy>1
coords=[endx,endy-2,endx,endy-1]
check_exit<<coords
end
if endy<@ysize-2
coords=[endx,endy+2,endx,endy+1]
check_exit<<coords
end
end
for xxx,yyy,xxx1,yyy1 in check_exit # Loop through possible exits
if @mapArr[yyy][xxx]==0 # If joins to a room
if rand(100)<psb # Possibility of linking rooms
make_portal(xxx1,yyy1)
end
end
end
end
# Final stage, loop through all the corridors to see if any can be joined to other rooms
#
def final_joins
@cor_list.each{|x|
join_corridor(x[0],x[1],x[2],x[3],10)
}
end
end
# TEST ZONE
begin
MAPWIDTH=40
MAPHEIGHT=25
FAILS=110
B1=20
MAPROOMS=20
dung=DungeonMap.new
map=dung.make_map(MAPWIDTH,MAPHEIGHT,FAILS,B1,MAPROOMS)
tilemap=[]
MAPHEIGHT.times{
tilemap<<Array.new(MAPWIDTH,0)
}
MAPHEIGHT.times{|y|
MAPWIDTH.times{|x|
case map[y][x]
when 0
tilemap[y][x]=\'.\'
when 1
tilemap[y][x]=\' \'
when 2
tilemap[y][x]=\'#\'
when 3,4,5
tilemap[y][x]=\'=\'
end
}
}
MAPHEIGHT.times{|y|
puts tilemap[y].to_s
}
end