class RogueGenerator

Public Class Methods

new(width=nil, height=nil, opts=Hash.new) click to toggle source
Calls superclass method Map::new
# File lib/delve/generator/rogue.rb, line 5
def initialize(width=nil, height=nil, opts=Hash.new)
  super width, height

  @options = {
    :cell_width => 3,
    :cell_height => 3,
  }

  opts.keys.each do |key|
    @options[key] = opts[key]
  end

  @options[:room_width] ||= calculate_room_size width, @options[:cell_width]
  @options[:room_height] ||= calculate_room_size height, @options[:cell_height]
end

Public Instance Methods

generate() { |x, y, map[y]| ... } click to toggle source
# File lib/delve/generator/rogue.rb, line 21
def generate
  @map = fill 1
  @rooms = Array.new
  @connected_cells = Array.new

  init_rooms
  connect_rooms
  connect_unconnected_rooms
  create_rooms
  create_corridors

  if block_given?
    (0..@map.length-1).each do |x|
      (0..@map[0].length-1).each do |y|
        yield x, y, @map[x][y]
      end
    end
  end
end

Private Instance Methods

calculate_room_size(size, cell) click to toggle source
# File lib/delve/generator/rogue.rb, line 46
def calculate_room_size(size, cell)
  max = ((size/cell) * 0.8).floor
  min = ((size/cell) * 0.25).floor
  min = 2 if min < 2
  max = 2 if max < 2
  [min, max]
end
connect_rooms() click to toggle source
# File lib/delve/generator/rogue.rb, line 71
def connect_rooms
  cgx = random_int 0, @options[:cell_width]-1
  cgy = random_int 0, @options[:cell_height]-1

  found = false

  loop do

    dir_to_check = [0, 2, 4, 6]
    
    loop do
      found = false
      idx = dir_to_check.sample
      break if idx.nil?
      dir_to_check.delete idx

      new_cgx = determine_ncgx(idx)
      ncgx = cgx + new_cgx[:x]
      ncgy = cgx + new_cgx[:y]

      next if ncgx < 0 or ncgx >= @options[:cell_width]-1
      next if ncgy < 0 or ncgy >= @options[:cell_height]-1

      room = @rooms[cgx][cgy]

      if room[:connections].length > 0
        if room[:connections][0][0] == ncgx and room[:connections][0][1] == ncgy
          break
        end
      end

      begin
        other_room = @rooms[ncgx][ncgy]
      rescue
        raise "ncgx: #{ncgx}, ncgy: #{ncgy}, rooms: #{@rooms.length}"
      end

      if other_room and other_room[:connections].length == 0
        other_room[:connections] << [cgx, cgy]

        @connected_cells << [ncgx, ncgy]
        cgx = ncgx
        cgy = ncgy
        found = true
      end

      break if dir_to_check.length <= 0 || found
    end

    break if dir_to_check.length <= 0
  end
end
connect_unconnected_rooms() click to toggle source
# File lib/delve/generator/rogue.rb, line 132
def connect_unconnected_rooms
  cw = @options[:cell_width]
  ch = @options[:cell_height]

  (0..@options[:cell_width]-1).each do |i|
    (0..@options[:cell_height]-1).each do |j|
      room = @rooms[i][j]

      if room[:connections].length == 0
        directions = [0, 2, 4, 6]
        valid_room = false
        other_room = nil

        loop do

          dir_idx = directions.sample
          break if dir_idx.nil?
          directions.delete dir_idx

          ncgx = determine_ncgx dir_idx
          new_i = i + ncgx[:x]
          new_j = j + ncgx[:y]

          if new_i < 0 or new_i >= cw or new_j < 0 or new_j >= ch
            next
          end

          other_room = @rooms[new_i][new_j]

          valid_room = true

          if other_room[:connections].length == 0
            break
          end

          (0..other_room[:connections].length-1).each do |k|
            if other_room[:connections][k][0] == i and other_room[:connections][k][1] == j
              valid_room = false
              break
            end
          end

          break if valid_room
          break if directions.length == 0
        end

        room[:connections] << [other_room[:cell_x], other_room[:cell_y]] if valid_room
      end
    end
  end
end
create_corridors() click to toggle source
# File lib/delve/generator/rogue.rb, line 340
def create_corridors
  cw = @options[:cell_width]
  ch = @options[:cell_height]
  room, connection, other_room, wall, other_wall = nil

  (0..cw - 1).each do |i|
    (0..ch - 1).each do |j|
      room = @rooms[i][j]

      room[:connections].each do |connection|
        other_room = @rooms[connection[0]][connection[1]]

        if other_room[:cell_x] > room[:cell_x]
          wall = 2
          other_wall = 4
        elsif other_room[:cell_x] < room[:cell_x]
          wall = 4
          other_wall = 2
        elsif other_room[:cell_y] > room[:cell_y]
          wall = 3
          other_wall = 1
        elsif other_room[:cell_y] < room[:cell_y]
          wall = 1
          other_wall = 3
        end
        
        draw_corridor get_wall_position(room, wall), get_wall_position(other_room, other_wall)
      end
    end
  end
end
create_rooms() click to toggle source
# File lib/delve/generator/rogue.rb, line 184
def create_rooms
  w = @width
  h = @height

  cw = @options[:cell_width]
  ch = @options[:cell_height]

  cwp = (w / cw).floor
  chp = (h / ch).floor

  roomw, roomh, sx, sy, tx, ty, other_room = nil

  room_width = @options[:room_width]
  room_height = @options[:room_height]

  (0..cw-1).each do |i|
    (0..ch-1).each do |j|
      sx = cwp * i
      sy = chp * j

      sx = 1 if sx == 0
      sy = 1 if sy == 0

      roomw = random_int room_width[0], room_width[1]
      roomh = random_int room_height[0], room_height[1]

      if j > 0
        other_room = @rooms[i][j-1]
        while (sy - (other_room[:y] + other_room[:height]) < 3)
          sy += 1
        end
      end
      if i > 0
        other_room = @rooms[i-1][j]
        while (sx - (other_room[:x] + other_room[:width]) < 3)
          sx += 1
        end
      end

      sx_offset = ((random_int 0, cwp-roomw) / 2).round
      sy_offset = ((random_int 0, chp-roomh) / 2).round

      while sx + sx_offset + roomw >= w
        if sx_offset > 0
          sx_offset -= 1
        else
          roomw -= 1
        end
      end

      while sy + sy_offset + roomh >= h
        if sy_offset > 0
          sy_offset -= 1
        else
          roomh -= 1
        end
      end

      sx = sx + sx_offset
      sy = sy + sy_offset

      @rooms[i][j][:x] = sx
      @rooms[i][j][:y] = sy
      @rooms[i][j][:width] = roomw
      @rooms[i][j][:height] = roomh

      (sx..sx + roomw - 1).each do |ii|
        (sy..sy + roomh - 1).each do |jj|
          @map[ii][jj] = 0
        end
      end
    end
  end
end
determine_ncgx(idx) click to toggle source
# File lib/delve/generator/rogue.rb, line 124
def determine_ncgx(idx)
  return { :x => 0, :y => -1 } if idx == 0
  return { :x => 1, :y => 0 } if idx == 2
  return { :x => 0, :y => 1 } if idx == 4
  return { :x => -1, :y => 0 } if idx == 6
  raise "Error determining ncgx with #{idx}."
end
directions(v) click to toggle source
# File lib/delve/generator/rogue.rb, line 372
def directions(v)
  dirs = {
    :four => [
      [ 0, -1],
      [ 1,  0],
      [ 0,  1],
      [-1,  0]
    ],
    :eight => [
      [ 0, -1],
      [ 1, -1],
      [ 1,  0],
      [ 1,  1],
      [ 0,  1],
      [-1,  1],
      [-1,  0],
      [-1, -1]
    ],
    :six => [
      [-1, -1],
      [ 1, -1],
      [ 2,  0],
      [ 1,  1],
      [-1,  1],
      [-2,  0]
    ]
  }

  dirs[v]
end
draw_corridor(start_pos, end_pos) click to toggle source
# File lib/delve/generator/rogue.rb, line 291
def draw_corridor(start_pos, end_pos)
  x_offset = end_pos[0] - start_pos[0]
  y_offset = end_pos[1] - start_pos[1]

  xpos = start_pos[0]
  ypos = start_pos[1]

  temp_dist, xdir, ydir = nil

  move = nil
  moves = Array.new

  xabs = x_offset.abs
  yabs = y_offset.abs

  percent = rand
  first_half = percent
  second_half = 1 - percent

  xdir = x_offset > 0 ? 2 : 6
  ydir = y_offset > 0 ? 4 : 0

  if xabs < yabs
    temp_dist = (yabs * first_half).ceil
    moves << [ydir, temp_dist]
    moves << [xdir, xabs]
    temp_dist = (yabs * second_half).floor
    moves << [ydir, temp_dist]
  else
    temp_dist = (xabs * first_half).ceil
    moves << [xdir, temp_dist]
    moves << [ydir, yabs]
    temp_dist = (xabs * second_half).floor
    moves << [xdir, temp_dist]
  end

  @map[xpos][ypos] = 0;

  while moves.length > 0
    move = moves.pop
    while move[1] > 0
      xpos += directions(:eight)[move[0]][0]
      ypos += directions(:eight)[move[0]][1]
      @map[xpos][ypos] = 0
      move[1] = move[1] - 1
    end
  end
end
get_wall_position(room, direction) click to toggle source
# File lib/delve/generator/rogue.rb, line 259
def get_wall_position(room, direction)
  rx = nil
  ry = nil
  door = nil

  if direction == 1 || direction == 3
    rx = random_int(room[:x] + 1, room[:x] + room[:width] - 2)
    if direction == 1
      ry = room[:y] - 2
      door = ry + 1
    else
      ry = room[:y] + room[:height] + 1
      door = ry - 1
    end

    @map[rx][door] = 2 
  elsif direction == 2 || direction == 4
    ry = random_int(room[:y] + 1, room[:y] + room[:height] - 2)
    if direction == 2
      rx = room[:x] + room[:width] + 1
      door = rx - 1
    else
      rx = room[:x] - 2
      door = rx + 1
    end

    @map[door][ry] = 2
  end

  [rx, ry]
end
init_rooms() click to toggle source
# File lib/delve/generator/rogue.rb, line 54
def init_rooms
  (0..@options[:cell_width]-1).each do |i|
    @rooms << Array.new
    (0..@options[:cell_height]-1).each do |j|
      @rooms[i] << {
        :x => 0,
        :y => 0,
        :width => 0,
        :height => 0,
        :connections => Array.new,
        :cell_x => i,
        :cell_y => j
      }
    end
  end
end
random_int(min, max) click to toggle source
# File lib/delve/generator/rogue.rb, line 42
def random_int(min, max)
  (rand * (max - min + 1)).floor + min
end