#=============================================================================== # Roguelike Random Dungeon Generator #------------------------------------------------------------------------------- # Version: 2.0 # Author: cozziekuns (rmrk) # Last Date Updated: 17/9/2011 #=============================================================================== # Description: #------------------------------------------------------------------------------- # A random dungeon generator akin to that of games like Rogue or Pokemon Mystery # Dungeon. #=============================================================================== # Updates # ------------------------------------------------------------------------------ # o 16/07/2011 - Started Script # o 17/07/2011 - Updated Script to support black outlines and some autotile # features # o 15/09/2011 - Bugfix. # o 17/09/2011 - Major overhaul of the entire script. Now has fully functional # autotile support, and a much faster algorithm that can create a # 500 * 500 tile map with 1000 features in less than 10 seconds. #=============================================================================== # To-do List #------------------------------------------------------------------------------- # o Nothing! Suggest some features. #=============================================================================== # Instructions #------------------------------------------------------------------------------- # Copy and paste this script above ? Main Process but below ? Materials, and # edit the modules to your liking. Some difficult modules have links to the # instructions. #=============================================================================== # Maps #------------------------------------------------------------------------------- # Start editing at: # case id # when [id] - Replace [id] with your map id. # ROOM_MIN_WIDTH : Minimum width for a single "Room" # ROOM_MAX_WIDTH : Maximum width for a single "Room" # ROOM_MIN_HEIGHT : Minimum height for a single "Room" # ROOM_MAX_HEIGHT : Maximum height for a single "Room" # FEATURES : How many features you want to fit in the map # WALL_TILE : Tile of the wall # FLOOR_TILE : Tile of the floor # BLACK_OUTLINE : Do you want a black outline surrounding your random # dungeon (slow). # end #=============================================================================== module COZZIEKUNS module RDG def self.map_settings(id) case id when 1 room_min_width = 3 room_max_width = 6 room_min_height = 3 room_max_height = 6 features = 50 wall_tile = 0 floor_tile = 16 black_outline = false when 2 room_min_width = 4 room_max_width = 8 room_min_height = 4 room_max_height = 8 features = 1000 wall_tile = 6 floor_tile = 52 black_outline = false end return [room_min_width, room_max_width, room_min_height, room_max_height, features, wall_tile, floor_tile, black_outline].compact end end end #============================================================================== # ** Game_Map #============================================================================== class Game_Map alias coz_rdg_gm_setup setup def setup(*args) coz_rdg_gm_setup(*args) create_dungeon if not COZZIEKUNS::RDG.map_settings(@map_id).empty? end def create_dungeon set_variables fill_wall_tiles dig_random_room for i in 0...@features count = 0 loop do count += 1 choose_next_wall make_new_feature break if @can_make or count == 5 end end refine_tilemap set_player_and_events end def set_variables settings = COZZIEKUNS::RDG.map_settings(@map_id) @rmiw = settings[0] @rmaw = settings[1] @rmih = settings[2] @rmah = settings[3] @features = settings[4] @walls = [] @floor = [] @next_wall = [] @wall_tile = (settings[5] + 80) * 48 + 2048 @wall2_tile = (settings[5] + 88) * 48 + 2048 @floor_tile = (settings[6] + 128) + 1408 @black_outline = settings[7] @next_feature = 0 @can_make = false @player_transfered = false end def set_player_and_events for event in $game_map.events.values + [$game_player] loop do ax = @floor[rand(@floor.size)][0] ay = @floor[rand(@floor.size)][1] if passable_in_area?(ax - 1, ay - 1, event) event.moveto(ax, ay) break end end end end alias coz_rdg_gm_update update def update coz_rdg_gm_update unless @player_transfered or COZZIEKUNS::RDG.map_settings(@map_id).empty? @player_transfered = true set_player_and_events end end def passable_in_area?(x, y, char, width = 3, height = 3) for i in x...x + width; for j in y...y + height return false if not char.passable?(i, j) end; end return true end def fill_wall_tiles for i in 0...width; for j in 0...height @map.data[i, j, 0] = @wall_tile end; end end def dig_random_room x = [rand(width) + 1, width - @rmaw - 1].min y = [rand(height) + 1, height - @rmah - 1].min dig_room(x, y) end def dig_room(x, y, direction = 2) width = rand(@rmiw) + @rmaw - @rmiw + 1 height = rand(@rmih) + @rmah - @rmih + 1 for i in 0...width for j in 0...height case direction when 0; new_x = x + j; new_y = y + i when 1; new_x = x - i; new_y = y + j when 2; new_x = x + i; new_y = y + j when 3; new_x = x + j; new_y = y - i end @map.data[new_x, new_y, 0] = @floor_tile @floor.push([new_x, new_y]) @walls.push([new_x - 1, new_y, 1]) if new_x == x @walls.push([new_x + 1, new_y, 2]) if new_x == x + width - 1 @walls.push([new_x, new_y - 1, 3]) if new_y == y @walls.push([new_x, new_y + 1, 0]) if new_y == y + height - 1 end end @next_feature = 1 end def dig_corridor(x, y, direction) j = 0 width = rand(@rmiw) + @rmaw - @rmiw + 1 height = 0 for i in 0...width case direction when 0; new_x = x + j; new_y = y + i when 1; new_x = x - i; new_y = y + j when 2; new_x = x + i; new_y = y + j when 3; new_x = x + j; new_y = y - i end @map.data[new_x, new_y, 0] = @floor_tile @floor.push([new_x, new_y]) @walls.push([new_x - 1, new_y, 1]) if new_x == x @walls.push([new_x + 1, new_y, 2]) if new_x == x + width - 1 @walls.push([new_x, new_y - 1, 3]) if new_y == y @walls.push([new_x, new_y + 1, 0]) if new_y == y + height - 1 end case direction when 0; @next_wall = [x + height, y + width, 0] when 1; @next_wall = [x - width, y + height, 1] when 2; @next_wall = [x + width, y + height, 2] when 3; @next_wall = [x + height, y - width, 3] end @next_feature = 0 end def choose_next_wall; @next_wall = @walls[rand(@walls.size)]; end def make_new_feature direction = rand(4) @can_make = scan_area(@next_wall[0], @next_wall[1], @next_wall[2]) return if not @can_make @walls.delete(@next_wall) dig_corridor(@next_wall[0], @next_wall[1], @next_wall[2]) @can_make = scan_area(@next_wall[0], @next_wall[1], @next_wall[2]) dig_room(@next_wall[0], @next_wall[1], @next_wall[2]) if @can_make @next_feature = 1 end def scan_area(x, y, direction) case @next_feature when 0 for i in 0..@rmaw + 1; for j in 0..@rmah + 1 case direction when 0; return false if passable?(x + j, y + i) or !valid?(x + j, y + i) when 1; return false if passable?(x - i, y + j) or !valid?(x - i, y + j) when 2; return false if passable?(x + i, y + j) or !valid?(x + i, y + j) when 3; return false if passable?(x + j, y - i) or !valid?(x + j, y - i) end end; end when 1 for i in 0..@rmaw + 1; for j in -2..2 case direction when 0; return false if passable?(x + j, y + i) or !valid?(x + j, y + i) when 1; return false if passable?(x - i, y + j) or !valid?(x - i, y + j) when 2; return false if passable?(x + i, y + j) or !valid?(x + i, y + j) when 3; return false if passable?(x + j, y - i) or !valid?(x + j, y - i) end end; end end return true end def refine_tilemap for point in @floor next if passable?(point[0], point[1] - 1) @map.data[point[0], point[1] - 1, 0] = @wall2_tile end for i in 0...width; for j in 0...height next if @map.data[i, j, 0] == @floor_tile type = @map.data[i, j, 0] == @wall2_tile ? 1 : 0 @map.data[i, j, 0] = rdg_tilemap_id(i, j, type) end; end return if not @black_outline for i in 0...width; for j in 0...height next if @floor.include?([i, j]) if (@map.data[i, j, 0] - 2048) % 48 == 0 @map.data[i, j, 0] = 0 end end; end end def rdg_tilemap_id(x, y, type) data = @map.data base = @map.data[x, y, 0] return base if x == 0 or x == width - 1 or y == 0 or y == width - 1 case type when 0 count = 0 count += 1 if (data[x - 1, y, 0] - 2048) / 48 != (base - 2048) / 48 count += 2 if (data[x, y - 1, 0] - 2048) / 48 != (base - 2048) / 48 count += 4 if (data[x + 1, y, 0] - 2048) / 48 != (base - 2048) / 48 count += 8 if (data[x, y + 1, 0] - 2048) / 48 != (base - 2048) / 48 id = case count when 0 then check_corners(x, y, base) when 1 then 16 + ((check_corners(x, y, base, [2, 4])) / 2) when 2 then 20 + ((check_corners(x, y, base, [4, 8])) / 4) when 3 then 34 + ((check_corners(x, y, base, [4])) / 4) when 4 then 24 + ([0,8,1,9].index(check_corners(x, y, base, [1, 8]))) when 5 then 32 when 6 then 36 + ((check_corners(x, y, base, [8])) / 8) when 7 then 42 when 8 then 28 + check_corners(x, y, base, [1, 2]) when 9 then 40 + ((check_corners(x, y, base, [2])) / 2) when 10 then 33 when 11 then 43 when 12 then 38 + check_corners(x, y, base, [1]) else 31 + count end when 1 count = 0 count += 1 if passable?(x - 1, y) count += 4 if passable?(x + 1, y) id = count + 10 end return base + id end def check_corners(x, y, base, corners = [1, 2, 4, 8]) count = 0 data = @map.data count += 1 if corners.include?(1) and (data[x - 1, y - 1, 0] - 2048) / 48 != (base - 2048) / 48 count += 2 if corners.include?(2) and (data[x + 1, y - 1, 0] - 2048) / 48 != (base - 2048) / 48 count += 4 if corners.include?(4) and (data[x + 1, y + 1, 0] - 2048) / 48 != (base - 2048) / 48 count += 8 if corners.include?(8) and (data[x - 1, y + 1, 0] - 2048) / 48 != (base - 2048) / 48 return count end end