RMRK is retiring.
Registration is disabled. The site will remain online, but eventually become a read-only archive. More information.

RMRK.net has nothing to do with Blockchains, Cryptocurrency or NFTs. We have been around since the early 2000s, but there is a new group using the RMRK name that deals with those things. We have nothing to do with them.
NFTs are a scam, and if somebody is trying to persuade you to buy or invest in crypto/blockchain/NFT content, please turn them down and save your money. See this video for more information.
Roguelike Random Dungeon Generator

0 Members and 1 Guest are viewing this topic.

*****
Rep:
Level 84
This text is way too personal.
Bronze - GIAW 11 (Hard)Silver - GIAW Halloween
Roguelike Random Dungeon Generator
Version: 2.0a
Author: cozziekuns
Date: November 4, 2011

Version History


  • <Version 2.0a> 2011.11.04 - Bugfix.
  • <Version 2.0> 2011.09.17 - 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.
  • <Version 1.0b> 2011.09.15 - Bugfix.
  • <Version 1.0a> 2011.07.16 - Updated Script to support black outlines and some autotile features.
  • <Version 1.0> 2011.07.16 - Original Release

Planned Future Versions

  • None. Suggest something.

Description


A random dungeon generator akin to that of games like Rogue or Pokemon Mystery Dungeon.

Features

  • Randomly generates a different map each time the player enters the area.
  • Randomly relocates events and the player.
  • Is always solvable (so long as you make an exit).

Screenshots

Example of a 50 * 50 dungeon made using this generator.

Instructions

See Script.

TileA4 ID's (Wall Tiles) start from 0 and end at 48, going in ascending order. 0 selects the top row grey brick wall, 1 selects the top row orange brick wall, 16 selects the wooden column, etc. Do not use the tiles 8 - 15, 24 - 31 or 40 - 47. The concept might seem hard at first, but you'll get used to it. If someone whose better than me at explaining can explain this, they are more than welcome.

TileA5 ID's (Floor Tiles) work in a similar fashion, starting from 0 and ending at 127, going in descending order.

Script


Code: [Select]
#===============================================================================
# Roguelike Random Dungeon Generator
#-------------------------------------------------------------------------------
# Version: 2.0a
# Author: cozziekuns (rmrk)
# Last Date Updated: 4/11/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 = 200
        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 = 75
        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)
      if passable?(point[0], point[1] - 2)
        @map.data[point[0], point[1] - 1, 0] = @floor_tile
      else
        @map.data[point[0], point[1] - 1, 0] = @wall2_tile
      end
    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 rescue false
      count += 2 if (data[x, y - 1, 0] - 2048) / 48 != (base - 2048) / 48 rescue false
      count += 4 if (data[x + 1, y, 0] - 2048) / 48 != (base - 2048) / 48 rescue false
      count += 8 if (data[x, y + 1, 0] - 2048) / 48 != (base - 2048) / 48 rescue false
      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 rescue false
    count += 2 if corners.include?(2) and (data[x + 1, y - 1, 0] - 2048) / 48 != (base - 2048) / 48 rescue false
    count += 4 if corners.include?(4) and (data[x + 1, y + 1, 0] - 2048) / 48 != (base - 2048) / 48 rescue false
    count += 8 if corners.include?(8) and (data[x - 1, y + 1, 0] - 2048) / 48 != (base - 2048) / 48 rescue false
    return count
  end
 
end

Credit


  • cozziekuns

Thanks


Support


Just post down below.

Known Compatibility Issues

None as of yet, though I imagine there would be some.
« Last Edit: November 05, 2011, 12:23:27 AM by cozziekuns »

*
Rep:
Level 82
GIAW 14: 1st Place (Easy Mode)2013 Project of the Year2013 Best RPG Maker User (Programming)2013 Most Promising ProjectParticipant - GIAW 11Bronze - GIAW 10
Neat! But I'm still sitting at the introduction screen waiting for it to finish my 500x500 random dungeon.  >:D

Good stuff, going to fiddle around with it.
« Last Edit: July 17, 2011, 05:21:04 AM by Exhydra »

UPDATED 05-29-14


IS YOUR PROJECT OPTIMIZED?
UPDATED 07/04/15 - v2.5

RPG MAKER TOOLBOX
UPDATED 07/04/15 - v1.5

*****
my name is Timothy what's yours
Rep:
Level 79
Hello
2014 Most Missed Member2014 Zero to Hero2014 Best IRC Quote2012 Zero To HeroSecret Santa 2012 ParticipantContestant - GIAW 9For frequently finding and reporting spam and spam bots2011 Zero to Hero
Your placing of the return in the initialize method of Game_Map is needed, but still risky. There will be compatibility issues even if the other script aliases that method because the method will stop unless it's included in the array.

It's pretty dang cool though, and the code is about as good as it can get, that is, until MA comes along and remakes the entire script without requesting credit.
I'm loving your clever code of working out if a tile is passable. Top notch work, good lad.
it's like a metaphor or something i don't know

*
Rep:
Level 82
GIAW 14: 1st Place (Easy Mode)2013 Project of the Year2013 Best RPG Maker User (Programming)2013 Most Promising ProjectParticipant - GIAW 11Bronze - GIAW 10
The script still hasn't finished building my 500x500 random dungeon ... I think it died. Oh well!  :D

UPDATED 05-29-14


IS YOUR PROJECT OPTIMIZED?
UPDATED 07/04/15 - v2.5

RPG MAKER TOOLBOX
UPDATED 07/04/15 - v1.5

*****
my name is Timothy what's yours
Rep:
Level 79
Hello
2014 Most Missed Member2014 Zero to Hero2014 Best IRC Quote2012 Zero To HeroSecret Santa 2012 ParticipantContestant - GIAW 9For frequently finding and reporting spam and spam bots2011 Zero to Hero
The only people wanting to make a 500x500 map with this script are either incredibly stupid, want to test the script or want to make their players suffer.
it's like a metaphor or something i don't know

*
Rep:
Level 82
GIAW 14: 1st Place (Easy Mode)2013 Project of the Year2013 Best RPG Maker User (Programming)2013 Most Promising ProjectParticipant - GIAW 11Bronze - GIAW 10
Just being silly, really. I wanted to see if it would work at all. If I use the built-in dungeon generator for RMVX for a 500x500 map, the program outright crashes.

UPDATED 05-29-14


IS YOUR PROJECT OPTIMIZED?
UPDATED 07/04/15 - v2.5

RPG MAKER TOOLBOX
UPDATED 07/04/15 - v1.5

********
Hungry
Rep:
Level 96
Mawbeast
2013 Best ArtistParticipant - GIAW 11Secret Santa 2013 ParticipantFor the great victory in the Breakfast War.2012 Best Game Creator (Non-RM Programs)~Bronze - GIAW 9Project of the Month winner for August 2008Project of the Month winner for December 20092011 Best Game Creator (Non RM)Gold - GIAW Halloween
Have you considered allowing the user to premake some rooms to be included, or specify some NPC or Event to be on the map somewhere?  Like quest stuff?

Also as far as an algorithm goes, you could cut down the number of wall tiles needed by having black space between the rooms where there's only wall, and just putting the wall outlining the actual playable area.  In short, generate the path, then generate walls around the path.

FCF3a A+ C- D H- M P+ R T W- Z- Sf RLCT a cmn+++ d++ e++ f h+++ iw+++ j+ p sf+
Follow my project: MBlok | Find me on: Bandcamp | Twitter | Patreon

*****
my name is Timothy what's yours
Rep:
Level 79
Hello
2014 Most Missed Member2014 Zero to Hero2014 Best IRC Quote2012 Zero To HeroSecret Santa 2012 ParticipantContestant - GIAW 9For frequently finding and reporting spam and spam bots2011 Zero to Hero
Or have an option to do so. I know I prefer my dungeons with only an outline and black everything outside the dungeon rooms.
it's like a metaphor or something i don't know

*****
Rep:
Level 84
This text is way too personal.
Bronze - GIAW 11 (Hard)Silver - GIAW Halloween
Thanks for your support guys. I tried to incorporate everyone's ideas in the new version.

I'm not too happy with my current black outline, so if anyone has ideas on how to improve on that, it would be much appreciated. I might work on letting the user premake stuff later; it shouldn't be too hard.

***
Rep:
Level 81
it's time to poke
Great script, cozziekuns; I didn't really expect you to expand on this project further (after we discussed it in 2010), so seeing this thread after a random visit to my old stomping ground is a nice surprise.


*
Rep:
Level 97
2014 Most Unsung Member2014 Best RPG Maker User - Engine2013 Best RPG Maker User (Scripting)2012 Most Mature Member2012 Favorite Staff Member2012 Best RPG Maker User (Scripting)2012 Best MemberSecret Santa 2012 ParticipantProject of the Month winner for July 20092011 Best Veteran2011 Favourite Staff Member2011 Most Mature Member2011 Best RPG Maker User (Scripting)2011 Best Use of Avatar and Signature Space2010 Most Mature Member2010 Favourite Staff Member
Cool - I'll take a look at this soon :)

***
Rep:
Level 74
I'm baaack!
Great Script. I think the simplicity of it makes it even better!

I'll try to use this in my next game. (depending on what kind of game I make)

*
Rep: +0/-0Level 67
RMRK Junior
I very recently posted my own Random Dungeon Generator on a few other boards, you might enjoy looking at my scripts to get a feel for how I'm doing them.  I'll be looking at yours as well.

http://www.rpgmakervx.net/index.php?showtopic=47533

*
Rep:
Level 84
I know this is quite an old topic but I am having a problem with the script.
The dungeon generates fine randomly the first time around, but whenever I try to transfer the player to the map a second time all of the events and the player are left off the map as they are placed in the editor.

*****
Rep:
Level 84
This text is way too personal.
Bronze - GIAW 11 (Hard)Silver - GIAW Halloween
Thank you for identifying that problem and fixed. I'm was planning to overhaul this script anyways, and it will go through some huge changes soon.

*****
Rep:
Level 84
This text is way too personal.
Bronze - GIAW 11 (Hard)Silver - GIAW Halloween
Double post but whatever, I updated the script so it should run a lot more smoothly than it did before, and it also has fully functional autotile support.

**
Rep: +0/-0Level 68
RMRK Junior
I might've missed something in the script but can I add events? Treasure chests, NPCs, save points, shops, etc?

**
Rep: +0/-0Level 82
Meow?
Some suggestions:

Adjustable distance from map edge
Adjustable wall height - for those who use Mack charachip, the default ceiling is too low.

And apologize if it sounds like nitpicking, but all those empty corridors just feel weird.

*****
Rep:
Level 84
This text is way too personal.
Bronze - GIAW 11 (Hard)Silver - GIAW Halloween
Adjustable wall height is definitely a possibility.  I'll probably add that into the algorithm sometime.

Also:

Quote
Randomly relocates events and the player.

So yeah, just paste your events into the map and they will automatically be relocated.
« Last Edit: October 07, 2011, 03:14:23 AM by cozziekuns »

**
Rep: +0/-0Level 82
Meow?
EDIT:

I just figured out that the most fitting battle system for this script, the "Omegazion's Roguelike Battle System", will sometimes cause the program to hang up when entering new random dungeon. What a shame.
« Last Edit: October 28, 2011, 08:27:28 PM by Helios »

*
Rep: +0/-0Level 64
RMRK Junior
Just created an account for this purpose:
I had to use RPG Maker VX for a college course, and I modified this script heavily into something for myself.  I probably won't stick with the program, but the script is complete enough that I thought I'd pass it on to you guys.
Enjoy.

Code: [Select]
#!/usr/bin/ruby
#===============================================================================
# Roguelike Random Dungeon Generator
#-------------------------------------------------------------------------------
# Version: 2.1
# Forked By: Taylor C. Richberger
# Original Author: cozziekuns (rmrk)
# Last Date Updated: 02 November, 2011
#===============================================================================
# Description:
#-------------------------------------------------------------------------------
# A random dungeon generator akin to that of Roguelikes
#===============================================================================
# Use:
#-------------------------------------------------------------------------------
# -Top left tile on the map (tile 0, 0) is the floor tile
# -Next tile to the right (tile 1, 0) is the wall tile (be careful and only
# use a useful wall tile.  This rule is more relaxed for a floating-style
# dungeon).  For most wall tiles (using W or O as the type), you want to
# use the tile that shows the TOP of the wall.
# Experiment to get a desirable result.
# -Events are randomly placed in map, and then player is placed on top of
# whatever event is titled ENTRANCE.
# -NO EVENT ON A RANDOMLY GENERATED DUNGEON MAY MOVE THE PLAYER TO IT'S OWN
# MAP.  THIS WILL CAUSE PROBLEMS.
# -Map seed information is saved based on the save slot.
# Saved as "Save[filenumber].seeds". Because of this, any map that you
# want to be saved NEEDS a unique
# -Give the map some space.  If it is just big enough, the generator will
# take a long time, and if it is too small, it will enter an infinite loop
# without crashing.  It is reccommended to use a map at least 100x100 in
# size.
# -Player will automatically be transferred to targeted event from another
# map's event.  This is useful for multi-level random dungeons.
# -Map name influences dungeon.
# As long as map name starts with DUNGEON, the generator expects to see
# the format:
# DUNGEON-[roomminsize]-[roommaxsize]-[features]-[type]-[s level]-[s passes]-[name]
# roomminsize: Minimum room size, varies.
# roommaxsize: Maximum room size, varies.
# features: Approximate hallway count.
# type: Determines the type of dungeon.
# F is floating
# W is full walls
# O is walls with an empty outline
# S is for short or level walls (like water or tables).
# s level: Levels of smoothing, from 0 to 10.  This is not glitch-
# free, but generally behaves well as long as you don't
# go crazy with it.  You may specify this value as 0 to
# disable smoothing.
# s passes: passes for smoothing, may be any integer.  Like the
# previous value, this is not entirely glitch free.
# Experiment with different values of smoothing levels and
# passes to get different results.  You may specify this
# value as 0 to disable smoothing.
# name: A unique name. May not contain hyphens.  This is used for
# generating the same map every time, as a sort of pseudo
# map-save system.  Name this variable "RAND" (without the quotes)
# in order to have it randomly generate every time.  This variable
# MUST BE PRESENT, or the game will crash
# ex:  DUNGEON-03-05-5-S-4-1-Town, DUNGEON-03-05-5-W-0-0-Crypt, or DUNGEON-05-08-20-F-2-3-RAND
#
# Without beginning with DUNGEON, the map is loaded as default
#===============================================================================
# Latest updates:
#-------------------------------------------------------------------------------
# - Small bug fix.  Exits were still being randomized.
#===============================================================================
# Future goals:
#-------------------------------------------------------------------------------
# - Make sure event named EXIT is placed far from player
# - Possibly allow for true handling of an enemy named BOSS
#===============================================================================


# adds an event reader to Game_Event. This is needed for the Dungeon Generator
class Game_Event
attr_reader :event
end
# adds a map reader to Game_Map.
class Game_Map
attr_reader :map
def name
map_infos = load_data("Data/MapInfos.rvdata")
name = map_infos[@map_id].name
name.gsub!(/\\N\[([0-9]+)\]/i) { $game_actors[$1.to_i].name }
return name
end
end

# creates seed array for new game, and loads seed file for old game
class Scene_Title
def command_new_game
confirm_player_location
Sound.play_decision
$seeds = Array.new(Array.new())
$game_party.setup_starting_members            # Initial party
$game_map.setup($data_system.start_map_id)    # Initial map position
$game_player.moveto($data_system.start_x, $data_system.start_y)
$game_player.refresh
$scene = Scene_Map.new
RPG::BGM.fade(1500)
close_command_window
Graphics.fadeout(60)
Graphics.wait(40)
Graphics.frame_count = 0
RPG::BGM.stop
$game_map.autoplay
end
end

class Scene_File
def do_save
file = File.open(@savefile_windows[@index].filename, "wb")
write_save_data(file)

outSeeds = File.open(File.basename(file.path(), File.extname(file.path())) + ".seeds", "w")
file.close()
if (!$seeds.empty?)
for i in $seeds
outSeeds.puts(i[0] + " " + i[1].to_s())
end
end
outSeeds.close()

return_scene
end
def do_load
file = File.open(@savefile_windows[@index].filename, "rb")
read_save_data(file)

$seeds = Array.new()
inSeeds = File.open(File.basename(file.path(), File.extname(file.path())) + ".seeds", "r")
file.close()
inSeeds.each_line do |line|
$seeds << [line.split(" ")[0], line.split(" ")[1]]
end
inSeeds.close()

$scene = Scene_Map.new
RPG::BGM.fade(1500)
Graphics.fadeout(60)
Graphics.wait(40)
@last_bgm.play
@last_bgs.play
end
end

module RDG
def self.map_settings(room_min, room_max, feat, type, smooth, passes, name)
room_min_width = room_min
room_max_width = room_max
room_min_height = room_min
room_max_height = room_max
features = feat
short = (type == "S")
black_outline = (type == "O")
floating = (type == "F")
smoothLevels = smooth
smoothPasses = passes
mapName = name.to_s()
return [room_min_width, room_max_width, room_min_height, room_max_height, features, black_outline, floating, short, smoothLevels, smoothPasses, mapName].compact
end
end

#==============================================================================
# ** Game_Map
#==============================================================================

class Game_Map

alias old_setup setup
def setup(*args)
srand(Time.now().to_i())
old_setup(*args)
if ($game_map.name().split("-")[0] == "DUNGEON")
create_dungeon
end
end

def create_dungeon
set_variables()
process_seed()
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() is commented out because it is called upon update() anyway,
#+and this behavior caused problems with the entrance and exit events staying put.
#set_player_and_events()
end

def set_variables
settings = RDG.map_settings($game_map.name().split("-")[1].to_i(), $game_map.name().split("-")[2].to_i(), $game_map.name().split("-")[3].to_i(), $game_map.name().split("-")[4], $game_map.name().split("-")[5].to_i(), $game_map.name().split("-")[6].to_i(), $game_map.name().split("-")[7])
@black_outline = settings[5]
@floating = settings[6]
@short = settings[7]
@rmiw = settings[0]
@rmaw = settings[1]
@rmih = settings[2]
@rmah = settings[3]
@features = settings[4]
@walls = []
@floor = []
@next_wall = []
@smoothLevel = settings[8]
@smoothPasses = settings[9]
@mapName = settings[10]
if (!@floating)
@wall_tile = @map.data[1, 0, 0] - (@map.data[1, 0, 0] % 48) - 16
@wall2_tile = @wall_tile + 384
else
@wall_tile = @map.data[1, 0, 0]
end
@floor_tile = @map.data[0, 0, 0]
@next_feature = 0
@can_make = false
@player_transfered = false
end

def process_seed()
# If the name is not RAND, find or save seed
if (@mapName != "RAND")
found = false
if (!$seeds.empty?)
for i in $seeds
# Set seed for map if found
if (i[0] == @mapName)
found = true
srand(i[1].to_i())
end
end
end
# Save seed for map if not found
if (!found)
newSeed = Time.now().to_i()
$seeds << [@mapName, newSeed]
srand(newSeed)

for i in $seeds
# Set seed for map if found
if (i[0] == @mapName)
found = true
srand(i[1].to_i())
end
end
end
end
end

def set_player_and_events
# Sets the placement event for transferring between maps
placementEvent = "NULL"
for event in $game_map.events.values
if (($game_player.x == event.x) and ($game_player.y == event.y))
placementEvent = event.event.name
end
end

# Places player, entrance, and exit only, so that they are the same each time
for event in $game_map.events.values
if ((event.event.name == "ENTRANCE") or (event.event.name == "EXIT") or (event.event.name == "CONST"))
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

# Places all other enemies randomly
srand(Time.now().to_i())
for event in $game_map.events.values
if ((event.event.name == "ENTRANCE") or (event.event.name == "CONST") or (event.event.name == "EXIT"))
next
else
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

# Places player on event titled "ENTRANCE"
for event in $game_map.events.values
if (placementEvent == "NULL")
if (event.event.name == "ENTRANCE")
$game_player.moveto(event.x, event.y)
end
elsif (event.event.name == placementEvent)
$game_player.moveto(event.x, event.y)
end
end
end

alias old_update update
def update
old_update
if ($game_map.name[0..6] == "DUNGEON")
unless @player_transfered
@player_transfered = true
set_player_and_events
end
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
        if (@floating)
          @map.data[i, j, 0] = 0
        else
          @map.data[i, j, 0] = @wall_tile
        end
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 i in 1..@smoothPasses
smoothingArray = Array.new()
for point in @floor
if (rand(10) < @smoothLevel)
if (!passable?(point[0] + 1, point[1]))
smoothingArray.push([point[0] + 1, point[1]])
end
end
if (rand(10) < @smoothLevel)
if (!passable?(point[0] - 1, point[1]))
smoothingArray.push([point[0] - 1, point[1]])
end
end
if (rand(10) < @smoothLevel)
if (!passable?(point[0], point[1] + 1))
smoothingArray.push([point[0], point[1] + 1])
end
end
if (rand(10) < @smoothLevel)
if (!passable?(point[0], point[1] - 1))
smoothingArray.push([point[0], point[1] - 1])
end
end
end
smoothingArray.uniq!()

for i in smoothingArray
@map.data[i[0], i[1]] = @floor_tile
@floor.push([i[0], i[1]])
@walls.delete([i[0], i[1]])
end

if ((not @floating) and (not @short))
deleteArray = Array.new()

for i in @floor
if (!passable?(i[0], i[1] + 1) and passable?(i[0], i[1] + 2))
deleteArray.push([i[0], i[1] + 1])
end
end

deleteArray.uniq!()

for i in deleteArray
@walls.delete(i)
@floor.push(i)
@map.data[i[0], i[1]] = @floor_tile
end
end
end

if (@floating)
for point in @floor
next if passable?(point[0], point[1] + 1)
@map.data[point[0], point[1] + 1, 0] = @wall_tile
end
else
if (!@short)
for point in @floor
next if passable?(point[0], point[1] - 1)
@map.data[point[0], point[1] - 1, 0] = @wall2_tile
end
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
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
check_corners(x, y, base)
when 1
16 + ((check_corners(x, y, base, [2, 4])) / 2)
when 2
20 + ((check_corners(x, y, base, [4, 8])) / 4)
when 3
34 + ((check_corners(x, y, base, [4])) / 4)
when 4
24 + ([0,8,1,9].index(check_corners(x, y, base, [1, 8])))
when 5
32
when 6
36 + ((check_corners(x, y, base, [8])) / 8)
when 7
42
when 8
28 + check_corners(x, y, base, [1, 2])
when 9
40 + ((check_corners(x, y, base, [2])) / 2)
when 10
33
when 11
43
when 12
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

One last thing.  The generator works in a very specific manner (based mostly on the events in the map, the top two tiles, and the map name).  Make sure you read the entire header before you attempt to use this script.

Also, I don't know how licensing issues work with RPGVX scripts, so just in case, I relinquish any ownership I might have of all of my modifications of this RDG script to cozziekuns.  Feel free to use as much of it as you want without requiring my permission.  I think this is only fair as it is a modification of your script in the first place.

Latest Edit:  Updated the script.  It was still randomizing the placement of the EXIT event.
« Last Edit: November 02, 2011, 09:30:23 PM by Agonnazar »

***
Rep:
Level 77
RMRK Junior
Error. Doesn't seem to be compatibility related...

*****
Rep:
Level 84
This text is way too personal.
Bronze - GIAW 11 (Hard)Silver - GIAW Halloween
Interesting. Any idea how you got that error? How could I recreate it?

Also Agonnazzr, I'm perfectly fine with you altering the script, releasing it and taking partial, if not full credit. My version's kinda bad anyways; needs some more cleaning up.

***
Rep:
Level 77
RMRK Junior
I simply walked into an area affected by the script and got that.

*****
Rep:
Level 84
This text is way too personal.
Bronze - GIAW 11 (Hard)Silver - GIAW Halloween
I'd have to see your script configurations and/or possibly your project. Your map size might also be doing it, but I can't seem to recreate the error.

***
Rep:
Level 77
RMRK Junior
Could be the fog or parallax script I'm using.

*****
Rep:
Level 84
This text is way too personal.
Bronze - GIAW 11 (Hard)Silver - GIAW Halloween
What script would that be?

***
Rep:
Level 77
RMRK Junior
MA's Parallax script and Falcao's Fog script. The map is 170x130.

***
Rep:
Level 77
RMRK Junior
Tried a blank project and it's not a script conflict because that was the only script I used.

*****
Rep:
Level 84
This text is way too personal.
Bronze - GIAW 11 (Hard)Silver - GIAW Halloween
Thanks for finding out that major bug. Fixed.

***
Rep:
Level 77
RMRK Junior
It works now, but it seems to be messing up the walls and putting events in inaccessible places. For the latter, you could just tell it to check wether or not the tile is passable

*****
Rep:
Level 84
This text is way too personal.
Bronze - GIAW 11 (Hard)Silver - GIAW Halloween
Intrigue. See if the updated version helps. Sorry for all the inconvenience, I should've noticed these things earlier.

EDIT: It is edited, just not a new version.

***
Rep:
Level 74
I'm baaack!
Is there a way to make the dungeon generate the first time the player enters the map, and stay the same every other time the player enters the map. Just so it makes sense. I do like the current version though.

*****
Rep:
Level 84
This text is way too personal.
Bronze - GIAW 11 (Hard)Silver - GIAW Halloween
Sorry I didn't see this earlier. In most Roguelikes, the map changes every time you enter, so the lazy side of me wants to keep it like that. But I guess I could add an option if I have time.

**
Rep: +0/-0Level 83
it doesnt work for me... when i entered a random map it just black screen
okay now i get the problem on my side is that im persistent in making a random map using minimum and maximum width or height the same... example is 3,3 min/max width and height... i also noticed that i think using 0 for wall also help in that black screen i dunno why... floor is not okay for 0 either... so at least you need 1 for any values and i noticed exceeding either floor or wall to 9 will cause that blackscreen again... there is also another problem... about exiting said dungeon... here is an example of "infinite universe"... make 2 events that both send you to the same map over and over... so i made my own and i place my character on top of either ladders... but here is the glitch... the map doesnt change at all, and so does the placement of the event. and whats interesting is when you warp your character it will warp directly to what coordinate you made in the map creation inside VX... so the character wont end up in front of the ladder used... it will warp the player as is... and it will cause to warp players to an wall..

okay so i finally got it to work but there seems to be another thorn in the rose... each map i make it has a limitation of 3 evens only.... effin i cant make a batallion and horde of mobs man....


ah i get it.... it seems like placing event as is doesnt work as what you want it be... how to place event work like this...

placing them must have a spacing equal to the maximum width and height you assing in the configs....
« Last Edit: February 11, 2012, 01:02:06 PM by fatapi_shadramon »