Submit Your Article


 
RPG Maker

Welcome Guest ( Log In | Register )


  Games Resources RPG Maker VX RPG Maker XP Scripts Tutorials Downloads

 
Reply to this topicStart new topic
> Random Dungeon Generator - NEW v1.0
timm1980
post Jul 15 2011, 02:33 PM
Post #1


Level 1
Group Icon

Group: Member
Posts: 5
Type: None
RM Skill: Undisclosed




Random Dungeon Generator v1.0
Author: timm1980 (aka tkirch)


Introduction

This is my first script that I'm posting here, so bear with me, and please forgive my relative newness to the process.

Using this requires not only a script, but one important event, and a few special maps. See the example project for all the details.

Basically, the idea is, you make a script call when you're about to enter a dungeon, and the dungeon will be randomly generated based upon parameters you specify: width, height, depth, and seed. seed is what determines the effects of the random number generator. So a 5x5x3 dungeon with seed 0 will always be the same, but a 5x5x3 dungeon with any other seed value will be very different.

Give it a try and let me know what you think!

Features

Two different types of random dungeons can be created.
Zelda-style:
* A "maze" of individual rooms, forming a three dimensional structure
* Each room is it's own mini-map, a part of the greater dungeon
* Events, and other elements can be placed on cells to only appear in the "far point" (furthest distance from entrance) or in random cells (by using the RDZ_SPECIAL_VALUE variable to control whether or not the event is shown)
* 16 Different cells are used, for each possible combination of paths top/bottom/left/right
* 0 = no paths, 1 = bottom, 2 = left, 3 = bottom/left, 4 = top, 5 = top/bottom, 6 = bottom/left, 7 = top/bottom/left, 8 = right, 9 = right/bottom, 10 = right/left, 11 = right/left/bottom, 12 = right/top, 13 = right/top/bottom, 14 = right/top/left, 15 = right/left/top/bottom
* Each of the cells must be the same size, but any size can be used (and these can be edited right within RPG Maker VX!)
* Also note that the X coordinate of the top/bottom entry point from each cell must be the same across all cells, ditto for the Y coordinate of the left/right entry point
* Because only a single cell is loaded at once as the game map, this doesn't use a lot of system resources... thus the overall dungeon implied internally can effectively be quite large (in fact, the script imposes no particular limit!)
* Do note, though, that larger dungeons will take more time to generate... to be precise, the generation time is roughly linear with the number of cells in the dungeon, e.g. length * width * depth

Flat-map format, which is currently limited to a single floor, but the entire dungeon exists on a single flat map

* The single-floor dungeon is still constructed in the same maze-like manner, but it is all assembled into a single map
* Cells (which are all rectangular blocks of tiles, 5x5 in my example project) are all cut from a single Map created in RMVX


Screenshots

(Coming soon!)

How to Use

I HIGHLY recommend looking at the demo, because the nature of the maps and events that must be precreated for this to work well are more than can be adequately described in text. (Despite my mini novel above)

Demo

http://dl.dropbox.com/u/1460424/RandomDungeon_v1.zip

Script

Full Script

CODE
### Values that may need to be modified

# For a Zelda-style dungeon, these are the locations (x,y) on each cell
# to where the player should be teleported when entering from the:
# Bottom, Left, Top, Right, Upstairs, Downstairs
RDZ_POS_XY = [[8, 11], [1, 7], [8, 1], [15, 7], [8, 7], [8, 7]]

# These are the 16 Map IDs to use to refer to each of the 16 possible
# cells to display (0...15)  Each map should have events on it (which
# should be controlled by switches) for stairs up and down
RDZ_MAP_ID = [18, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]

# Describes which three variables are used to store the "entrance position"
# (position on the world map or other map where the player is just before
# entering the random dungeon)  Before entering the dungeon, the in-game
# event should store MapID, PlayerX, PlayerY to these three variables
RDZ_ENTRANCE_POS = [1, 2, 3]

# Describes which three variables are used to store the "next position"
# where the player will teleport to.  The events already setup on the
# example map cells do this already, but these three variables must be
# specifically reserved for this purpose.  They are MapID, X, Y, like above.
RDZ_NEXT_POS = [4, 5, 6]

# The script reports back (in variables, which can be accessed by events)
# the direction of the last move, and the current X,Y,Z location of the
# player within the random dungeon
# Special value is a value 0...65535 assigned to the cell randomly at
# creation time (useful for placing random events only to appear occasionally)
RDZ_LAST_MOVE = 7
RDZ_CURRENT_Z = 8
RDZ_CURRENT_Y = 9
RDZ_CURRENT_X = 10
RDZ_SPECIAL_VALUE = 11

# Designate two switches (which should be used by the stairs events
# mentioned above) that are used by the script to report back which set(s)
# of stairs should be enabled on each cell
RDZ_STAIR_SWITCH = [1, 2]

# Designate two switches (which can be optionally used by any special
# events) that are used by the script to report back whether the current
# cell is the "far point" of the dungeon (further distance from entrance of
# any cell), and whether or not it has a special designation
RDZ_FAR_POINT = 3

# For a flat-floor style random dungeon, these three variables indicate
# the MapID, X, Y to which the event should transfer the player after
# calling the appropriate scripts to create the random dungeon
RDF_NEXT_POS = [4, 5, 6]

# The event ID of the "exit dungeon" event on a flat-map style
# dungeon.  This is needed so that the script can place the event
# appropriately after assembling the map
RDF_EXIT_EVENT_ID = 4
RDF_STAIRS_UP_EVENT_ID = [1, 6, 7]
RDF_STAIRS_DOWN_EVENT_ID = [2, 8, 9]
RDF_SPECIAL_EVENT_ID = 3

# The default MAP_ID to be used as the source of tiling when
# assembling a floor-style random dungeon
RDF_DEFAULT_TILE_MAP_ID = 2

# (x,y) location (relative to upper left of a cell of tiles)
# where the stairs and any chests/random-event should be placed
RDF_STAIRS_LOCATION = [3, 2]
RDF_CHEST_LOCATION = [1, 2]

# A fraction representing the proportion of upper layer (Tileset B...E)
# tiles to copy; higher number = less copied (1/x)
RDF_EMBELLISHMENT_COPY = 7

### End of modification Section


# The following are overrides/modifications to the built-in default
# classes, to allow us to do some of what is needed with setting up
# maps to hold a randomly generated dungeon.

class Spriteset_Map
  def set_map_data(data)
    @tilemap.map_data = data
  end
end

class Scene_Map
  def set_map_data(data)
    @spriteset.set_map_data(data)
  end
end

class Game_Event
  def set_map_id(map_id)    
    @map_id = map_id if @event.name.include?("$rand")
  end
end

class Game_Interpreter
  alias tkirch_rd_command_123 command_123
  def command_123
    if @original_event_id > 0
      key = [$game_map.random_map_id, @original_event_id, @params[0]]
      $game_self_switches[key] = (@params[1] == 0)
    end
    $game_map.need_refresh = true
    return true
  end

  alias tkirch_rd_command_111 command_111
  def command_111
    result = false
    case @params[0]
    when 0  # Switch
      result = ($game_switches[@params[1]] == (@params[2] == 0))
    when 1  # Variable
      value1 = $game_variables[@params[1]]
      if @params[2] == 0
        value2 = @params[3]
      else
        value2 = $game_variables[@params[3]]
      end
      case @params[4]
      when 0  # value1 is equal to value2
        result = (value1 == value2)
      when 1  # value1 is greater than or equal to value2
        result = (value1 >= value2)
      when 2  # value1 is less than or equal to value2
        result = (value1 <= value2)
      when 3  # value1 is greater than value2
        result = (value1 > value2)
      when 4  # value1 is less than value2
        result = (value1 < value2)
      when 5  # value1 is not equal to value2
        result = (value1 != value2)
      end
    when 2  # Self switch
      if @original_event_id > 0
        key = [$game_map.random_map_id, @original_event_id, @params[1]]
        if @params[2] == 0
          result = ($game_self_switches[key] == true)
        else
          result = ($game_self_switches[key] != true)
        end
      end
    when 3  # Timer
      if $game_system.timer_working
        sec = $game_system.timer / Graphics.frame_rate
        if @params[2] == 0
          result = (sec >= @params[1])
        else
          result = (sec <= @params[1])
        end
      end
    when 4  # Actor
      actor = $game_actors[@params[1]]
      if actor != nil
        case @params[2]
        when 0  # in party
          result = ($game_party.members.include?(actor))
        when 1  # name
          result = (actor.name == @params[3])
        when 2  # skill
          result = (actor.skill_learn?($data_skills[@params[3]]))
        when 3  # weapon
          result = (actor.weapons.include?($data_weapons[@params[3]]))
        when 4  # armor
          result = (actor.armors.include?($data_armors[@params[3]]))
        when 5  # state
          result = (actor.state?(@params[3]))
        end
      end
    when 5  # Enemy
      enemy = $game_troop.members[@params[1]]
      if enemy != nil
        case @params[2]
        when 0  # appear
          result = (enemy.exist?)
        when 1  # state
          result = (enemy.state?(@params[3]))
        end
      end
    when 6  # Character
      character = get_character(@params[1])
      if character != nil
        result = (character.direction == @params[2])
      end
    when 7  # Gold
      if @params[2] == 0
        result = ($game_party.gold >= @params[1])
      else
        result = ($game_party.gold <= @params[1])
      end
    when 8  # Item
      result = $game_party.has_item?($data_items[@params[1]])
    when 9  # Weapon
      result = $game_party.has_item?($data_weapons[@params[1]], @params[2])
    when 10  # Armor
      result = $game_party.has_item?($data_armors[@params[1]], @params[2])
    when 11  # Button
      result = Input.press?(@params[1])
    when 12  # Script
      result = eval(@params[1])
    when 13  # Vehicle
      result = ($game_player.vehicle_type == @params[1])
    end
    @branch[@indent] = result     # Store determination results in hash
    if @branch[@indent] == true
      @branch.delete(@indent)
      return true
    end
    return command_skip
  end

end

class Scene_File
  alias tkirch_rd_write_save_data write_save_data
  def write_save_data(file)
    tkirch_rd_write_save_data(file)
    if $game_random_dungeon != nil
      Marshal.dump($game_random_dungeon, file)
    end
  end
  
  alias tkirch_rd_read_save_data read_save_data
  def read_save_data(file)
    tkirch_rd_read_save_data(file)
    begin
      $game_random_dungeon = Marshal.load(file)
    rescue
      
    end
  end
  
end

class Game_Map
  def set_random_id(id)
    @random_map_id = id
  end
  
  def random_map_id
    if @random_map_id == nil
      @random_map_id = @map_id
    end
    return @random_map_id
  end

  alias tkirch_rd_setup setup
  def setup(map_id)
    @random_map_id = map_id
    tkirch_rd_setup(map_id)
  end
  
  def set_map_data(width, height, data)
    @map.width = width
    @map.height = height
    @map.data = data
  end
  
  def setup_rdz_events(random_map_id)
    for i in @events.keys
      @events[i].set_map_id(random_map_id)
    end
  end
  
  def setup_rd_events(key_map_id, escape, floor, tile_width, tile_height)
    stairsUp = RDF_STAIRS_UP_EVENT_ID.clone
    stairsDown = RDF_STAIRS_DOWN_EVENT_ID.clone
    @events = {}
    @events[RDF_EXIT_EVENT_ID] = Game_Event.new(key_map_id, @map.events[RDF_EXIT_EVENT_ID])
    @events[RDF_EXIT_EVENT_ID].moveto(escape[0], escape[1])
    empty_positions = {}
    for yy in 0...floor.size
      for xx in 0...floor[yy].size
        if floor[yy][xx] & 16 == 16
          event_id = stairsUp.delete_at(0)
          @events[event_id] = Game_Event.new(key_map_id, @map.events[event_id])
          @events[event_id].moveto(xx * tile_width + RDF_STAIRS_LOCATION[0], yy * tile_height + RDF_STAIRS_LOCATION[1])
        elsif floor[yy][xx] & 32 == 32
          event_id = stairsDown.delete_at(0)
          @events[event_id] = Game_Event.new(key_map_id, @map.events[event_id])
          @events[event_id].moveto(xx * tile_width + RDF_STAIRS_LOCATION[0], yy * tile_height + RDF_STAIRS_LOCATION[1])
        elsif floor[yy][xx] & 64 == 64
          @events[RDF_SPECIAL_EVENT_ID] = Game_Event.new(key_map_id, @map.events[RDF_SPECIAL_EVENT_ID])
          @events[RDF_SPECIAL_EVENT_ID].moveto(xx * tile_width + RDF_CHEST_LOCATION[0], yy * tile_height + RDF_CHEST_LOCATION[1])
          @events[RDF_SPECIAL_EVENT_ID].refresh
        elsif floor[yy][xx] & 15 > 0
          empty_positions[floor[yy][xx] / 256] = [xx, yy]
        end
      end
    end
    
    for event in @map.events.values
      if event.name.include?("$rand") and empty_positions.size > 0
        data_key = empty_positions.keys.sort[0]
        location = empty_positions[data_key]
        xx = location[0]
        yy = location[1]
        @events[event.id] = Game_Event.new(key_map_id, event)
        @events[event.id].moveto(xx * tile_width + RDF_CHEST_LOCATION[0], yy * tile_height + RDF_CHEST_LOCATION[1])
        @events[event.id].refresh
        empty_positions.delete(data_key)
      end
    end
  end
  
  def generateFromVariables
    $game_random_dungeon = RDF.new($game_variables[14], $game_variables[14], $game_variables[15], $game_variables[13], 2)
  end
end

class Scene_Title
  alias tkirch_rd_create_game_objects create_game_objects
  def create_game_objects
    tkirch_rd_create_game_objects
    $game_random_dungeon = nil
  end
end

# The base class for creating a random dungeon layout
# Basically, it's a 3-dimensional array [z][y][x] with a single
# integer describing each "cell" of the dungeon
# In a Zelda-style dungeon, each cell is a screen
# In a flat-style dungeon, each cell is a rectangular area of tiles
# in the larger created map (in the example created, each cell is 5x5 tiles
# but they can be basically any size)
#
# The random number is 24 bits in length. The lower 8 bits describe the
# nature of the cell (see in code below), the upper 16 bits are a random
# value that can be used to determine random, but fixed display properties
# (intended for things like cosmetic decorations, etc, not yet implemented)
class Random_Dungeon_Base
  attr_accessor :width
  attr_accessor :height
  attr_accessor :depth
  attr_accessor :cells

  # These constants describe the bitmask used by the lower 8 bits of the
  # cell description value; they indicate if there's an opening to the bottom,
  # left, top, right; if there's a stairway up or down, and a "special" value,
  # indicating that the cell is the furthest one from the entrance to the
  # dungeon
  BT = 1
  LT = 2
  TP = 4
  RT = 8
  UP = 16
  DW = 32
  SP = 64
  FN = 128

  # Initializer, just sets up the array, etc
  def initialize(width, height, depth)
    @width = width
    @height = height
    @depth = depth
    @cells = Array.new(@depth) { Array.new(@height) { Array.new(@width, 0) } }
  end

  # Make the random dungeon
  # seed is the value to determine "which" random dungeon to generate
  # cutProb = probability that a cell will have an exit in any given direction
  # joinProb = probability that a cell will have an exit that reconnects to an
  #    already-explored portion of the dungeon
  # sProb = probability of a cell having an up or down staircase
  # sJoinProb = probability a cell has a staircase that reconnects to an
  #    already-explored portion of the dungeon (e.g. redundant staircase)
  # maxS = max number of staircases descending from any single floor
  # Leaving out an in-depth discussion of the internals of how this method
  # works, it will suffice to say that it basically executes a breath-first
  # search, starting from the entrance, and continuing until no new paths
  # are (randomly selected to be) created
  def make(seed = 0, cutProb = 0.5, joinProb = 0.2, sProb = 0.15, sJoinProb = 0.05, maxS = 3)
    oldseed = srand(seed)
    queue = []
    startZ = 0
    startY = @height - 1
    startX = @width / 2
    @cells[startZ][startY][startX] = BT
    queue << [startX, startY, startZ, 0]
    queue << [startX, startY, startZ, 0]
    queue << [startX, startY, startZ, 0]
    farP = [startX, startY, startZ]
    farS = 1
    stCount = Array.new(@depth, 0)
    while queue.length > 0
      curPos = queue.delete_at(0)
      curX = curPos[0]
      curY = curPos[1]
      curZ = curPos[2]
      curS = curPos[3]
      if curS > farS
        farP = [curX, curY, curZ]
        farS = curS
      end
      if curY < @height - 1
        modify = false
        if @cells[curZ][curY + 1][curX] > 0
          modify = true if rand() < joinProb          
        else
          if rand() < cutProb
            modify = true
            queue << [curX, curY + 1, curZ, curS + 1]
          end
        end
        if modify
          @cells[curZ][curY][curX] |= BT
          @cells[curZ][curY + 1][curX] |= TP
        end
      end
      if curX > 0
        modify = false
        if @cells[curZ][curY][curX - 1] > 0
          modify = true if rand() < joinProb  
        else
          if rand() < cutProb
            modify = true
            queue << [curX - 1, curY, curZ, curS + 1]
          end
        end
        if modify
          @cells[curZ][curY][curX] |= LT
          @cells[curZ][curY][curX - 1] |= RT
        end
      end
      if curY > 0
        modify = false
        if @cells[curZ][curY - 1][curX] > 0
          modify = true if rand() < joinProb          
        else
          if rand() < cutProb
            modify = true
            queue << [curX, curY - 1, curZ, curS + 1]
          end
        end
        if modify
          @cells[curZ][curY][curX] |= TP
          @cells[curZ][curY - 1][curX] |= BT
        end
      end
      if curX < @width - 1
        modify = false
        if @cells[curZ][curY][curX + 1] > 0
          modify = true if rand() < joinProb          
        else
          if rand() < cutProb
            modify = true
            queue << [curX + 1, curY, curZ, curS + 1]
          end
        end
        if modify
          @cells[curZ][curY][curX] |= RT
          @cells[curZ][curY][curX + 1] |= LT
        end
      end
      if curZ > 0 && stCount[curZ - 1] < maxS && (@cells[curZ][curY][curX] & DW == 0)
        modify = false
        if @cells[curZ - 1][curY][curX] > 0
          modify = true if rand() < sJoinProb          
        else
          if rand() < sProb
            modify = true
            queue << [curX, curY, curZ - 1, curS + 1]
          end
        end
        if modify
          @cells[curZ][curY][curX] |= UP
          @cells[curZ - 1][curY][curX] |= DW
          stCount[curZ - 1] = stCount[curZ - 1] + 1
        end
      end
      if curZ < @depth - 1 && stCount[curZ] < maxS && (@cells[curZ][curY][curX] & UP == 0)
        modify = false
        if @cells[curZ + 1][curY][curX] > 0
          modify = true if rand() < sJoinProb          
        else
          if rand() < sProb
            modify = true
            queue << [curX, curY, curZ + 1, curS + 1]
          end
        end
        if modify
          @cells[curZ][curY][curX] |= DW
          @cells[curZ + 1][curY][curX] |= UP
          stCount[curZ] = stCount[curZ] + 1
        end
      end
    end
    @cells[farP[2]][farP[1]][farP[0]] |= SP
    @cells.each { |level| level.each { |row| row.each_index { |i| row[i] |= (256 * rand(65536)) } } }
    srand(oldseed)
  end

end


# This is the instance of the class that creates a Zelda-style random dungeon
# Initialize with RDZ.new(height, width, depth, seed)
class RDZ < Random_Dungeon_Base

  attr_accessor :curX
  attr_accessor :curY
  attr_accessor :curZ

  def initialize(height, width, depth, seed)
    super(height, width, depth)
    make(seed)
    @curX = @width / 2
    @curY = @height - 1
    @curZ = 0
    @lastMove = 0
    setVars
  end

  # The next six methods are already called by the example-tiles
  # The "tell" the random dungeon that we want to go in a certain
  # direction, which sets up the variables that tell the game
  # where to next move
  def goRight
    @curX += 1
    @lastMove = 1
    setVars
  end
  def goLeft
    @curX -= 1
    @lastMove = 3
    setVars
  end
  def goTop
    @curY -= 1
    @lastMove = 0
    setVars
  end
  def goBottom
    @curY += 1    
    @lastMove = 2
    setVars
  end
  def goUp
    @curZ -= 1
    @lastMove = 4
    setVars
  end
  def goDown
    @curZ += 1
    @lastMove = 5
    setVars
  end
  
  # Set some game variables based upon the "state" of (our position in) the random dungeon
  def setVars
    if curY == @height
      $game_variables[RDZ_NEXT_POS[0]] = $game_variables[RDZ_ENTRANCE_POS[0]]
      $game_variables[RDZ_NEXT_POS[1]] = $game_variables[RDZ_ENTRANCE_POS[1]]
      $game_variables[RDZ_NEXT_POS[2]] = $game_variables[RDZ_ENTRANCE_POS[2]]
      return
    end
    cell = @cells[curZ][curY][curX]
    $game_variables[RDZ_NEXT_POS[0]] = RDZ_MAP_ID[cell & 15]
    $game_variables[RDZ_NEXT_POS[1]] = RDZ_POS_XY[@lastMove][0]
    $game_variables[RDZ_NEXT_POS[2]] = RDZ_POS_XY[@lastMove][1]
    $game_switches[RDZ_STAIR_SWITCH[0]] = false
    $game_switches[RDZ_STAIR_SWITCH[1]] = false
    $game_switches[RDZ_STAIR_SWITCH[0]] = true if (cell & UP) == UP
    $game_switches[RDZ_STAIR_SWITCH[1]] = true if (cell & DW) == DW
    $game_switches[RDZ_FAR_POINT] = true if (cell & SP) == SP
    $game_variables[RDZ_LAST_MOVE] = @lastMove
    $game_variables[RDZ_CURRENT_Z] = @curZ
    $game_variables[RDZ_CURRENT_Y] = @curY
    $game_variables[RDZ_CURRENT_X] = @curX
    $game_variables[RDZ_SPECIAL_VALUE] = cell / 256
  end

  def setRandomMapId
    rmap_id = [@width, @height, @depth, @seed, @curX, @curY, @curZ]
    $game_map.set_random_id(rmap_id)
    $game_map.setup_rdz_events(rmap_id)
    $game_map.refresh
  end
  
end

class RDF < Random_Dungeon_Base
  def initialize(height, width, depth, seed, tileMapId = 0)
    super(height, width, depth)
    make(seed)
    @seed = seed
    @tile_map_id = tileMapId
    @tile_map_id = RDF_DEFAULT_TILE_MAP_ID if @tile_map_id == 0
    @tiling_map = load_data(sprintf("Data/Map%03d.rvdata", @tile_map_id))
    @curZ = 0
    @tile_width = @tiling_map.width / 4 - 1
    @tile_height = @tiling_map.height / 4 - 1
    @map_width = @tile_width * @width
    @map_height = @tile_height * @height
    @map_data = Array.new(@depth)
    @map_data.each_index { |z| fillLayer(z) }
    $game_variables[RDF_NEXT_POS[0]] = @tile_map_id
    $game_variables[RDF_NEXT_POS[1]] = (@width / 2) * @tile_width + (@tile_width / 2)
    $game_variables[RDF_NEXT_POS[2]] = @map_height - 2
  end
  
  def saveCurrentPosition
    $game_variables[RDF_NEXT_POS[0]] = @tile_map_id
    $game_variables[RDF_NEXT_POS[1]] = $game_player.x
    $game_variables[RDF_NEXT_POS[2]] = $game_player.y
    $game_map.setup(@tile_map_id)
  end

  def goDownStairs
    @curZ += 1
    showCurrentLayer
  end
  
  def goUpStairs
    @curZ -= 1
    showCurrentLayer
  end

  def showCurrentLayer
    key = [@width, @height, @depth, @seed, @curZ]
    escape = [(@width / 2) * @tile_width + (@tile_width / 2), @map_height - 1]
    $game_map.set_map_data(@map_width, @map_height, @map_data[@curZ])
    $game_map.set_random_id(key)
    $game_map.setup_rd_events(key, escape, @cells[@curZ], @tile_width, @tile_height)
    $scene.set_map_data(@map_data[@curZ])
  end

  def fillLayer(z)
    @map_data[z] = Table.new(@map_width, @map_height, 3)
    @cells[z].each_index { |y| fillRow(z, y) }
  end

  def fillRow(z, y)
    @cells[z][y].each_index { |x| copyTile(x, y, z, @cells[z][y][x] & 15, @cells[z][y][x] / 256) }
  end

  def copyTile(x, y, z, tileNum, rval)
    tilex = (tileNum % 4) * (@tile_width + 1)
    tiley = (tileNum / 4) * (@tile_height + 1)
    mapx = x * @tile_width
    mapy = y * @tile_height
    a = 16807
    r = rval % 65536
    c = 13
    m = 2147483647
    for xx in 0...@tile_width
      for yy in 0...@tile_height
        @map_data[z][mapx + xx, mapy + yy, 0] = @tiling_map.data[tilex + xx, tiley + yy, 0]
        #@map_data[z][mapx + xx, mapy + yy, 1] = @tiling_map.data[tilex + xx, tiley + yy, 1]
        @map_data[z][mapx + xx, mapy + yy, 2] = @tiling_map.data[tilex + xx, tiley + yy, 2] if r % RDF_EMBELLISHMENT_COPY == 0
        r = (a * r + c) % m
      end
    end
  end

end



Credit and Thanks

None of this script comes from anyone else; the idea for it was loosely borrowed from both Dragon Quest 9, and the original Legend of Zelda, however.

Authors Notes

There is no arbitrary limit on how large of a dungeon can be created; larger dungeons will be slower to create and load, and may approach the limits of what RMVX can handle well, however.

Currently, I know this won't work right if you save a game while inside of a random dungeon.

Likely Future Features to Include

* Ability to Save/Load while in a random-dungeon (either Zelda or flat style)
* Flat-style dungeons will multiple floors
* Flat-style dungeons will randomly placed treasure chests or other events
* Flat-style dungeons automatically copy only some random layer two map features (I'm thinking for embellishments like moss, skeletons, etc, so that each cell of the finished map looks a bit different, despite being created from only 16 cells)
* Any other ideas that are suggested that seem feasible and worthwhile?

This post has been edited by timm1980: Jul 20 2011, 06:45 PM
Go to the top of the page
 
+Quote Post
   
Pharonix
post Jul 19 2011, 05:08 PM
Post #2


Eventer. Gamer. Writer.
Group Icon

Group: Revolutionary
Posts: 155
Type: Event Designer
RM Skill: Intermediate
Rev Points: 25




I like this, but I see some issues that I must address

There is the error on loading a game saved in a random dungeon, like you said.

The main issue however, is that it is easy to get lost in the second one - the one with transfers. This is because it makes it almost impossible to traverse. Unless I'm missing something.

I was however, looking for something like this to create a LOZ-esque lost woods map.
And Very nice job man.


__________________________

CURRENT WORKS
DEMON BLADE - RPGVXA
SHINIGAMI - ~12 Pages - 3 chapters complete, 1 in progress.
---------------------------------
OTHER WORKS
INCANTA-corrupted.
INCANTA REDUX - RPGVX - On Hold
---------------------------------
LITERARY WORKS

Longer Works
ANGEL OF DEATH - Short Story ~ 4 Pages.
SHINIGAMI - ~12 Pages - 3 chapters complete, 1 in progress.
DEMON BLADE - Book/Novel?- 34 pages - On Hold.
FERAL - Short Story, Length: 6 pages], 2nd person Narrative. -R3 Writing Competition #2 - First-Place
DARKSPAWN - Book - 3 Pages On Hold
RELGEA CHRONICLE - Book - 118 pages
DRAKENGHOUL - book - 36 handwritten pages

Poems
I KNOW - Poem - 30 Lines

Song Lyrics
End of Days - Song- 44 Lines
Kids Killing Kids - Song - 94 Lines




-If you want this sig in another language, move to a country that speaks it.-

-Lv 13 Thread Killer




My R3 Writing Corner



My Wordpress


Relgea Chronicle

X-M-O Story Quoting.
QUOTE (X-M-O @ Jun 19 2012, 02:45 AM) *
QUOTE (Pharonix)
so what's going on in this thread?

QUOTE (kayden997)
Redd's back and the first thing he does is...

QUOTE (Pharonix)
pick my mom up in 15
...*sigh*

QUOTE (kayden997)
You know it's legit!

QUOTE (Pharonix)
Then again, I wrecked the last one...........

QUOTE (Tsutanai)
Oh ok you can have a pink frosted sprinkled doughnut

QUOTE (Pharonix)
I hate not having a car......
I miss my Alero...

QUOTE (Tsutanai)
you suck >:(


Go to the top of the page
 
+Quote Post
   
timm1980
post Jul 19 2011, 09:06 PM
Post #3


Level 1
Group Icon

Group: Member
Posts: 5
Type: None
RM Skill: Undisclosed




QUOTE (Pharonix @ Jul 19 2011, 06:08 PM) *
I like this, but I see some issues that I must address

There is the error on loading a game saved in a random dungeon, like you said.

The main issue however, is that it is easy to get lost in the second one - the one with transfers. This is because it makes it almost impossible to traverse. Unless I'm missing something.

I was however, looking for something like this to create a LOZ-esque lost woods map.
And Very nice job man.


WIthin the next day or two, I should be ready to post an updated version, which fixes the save issue, allows multiple floors in a flat-style dungeon (the one without traversing), and several other improvements.

The zelda-style maps, with transfers from room to room, I agree, are very difficult to traverse. I wonder if adding in an auto-mapping feature of some kind might be worth looking into.. hmmm...

That said, I personally prefer the flat style, as it's more like what I expect in this style of RPG. If there's interest in the zelda-style, however, I'm happy to look into doing that as well.

Thanks for looking at it!



This post has been edited by timm1980: Jul 19 2011, 09:07 PM
Go to the top of the page
 
+Quote Post
   
timm1980
post Jul 20 2011, 06:46 PM
Post #4


Level 1
Group Icon

Group: Member
Posts: 5
Type: None
RM Skill: Undisclosed




NEW version posted!
Go to the top of the page
 
+Quote Post
   
Helios
post Jul 23 2011, 06:39 AM
Post #5


Level 4
Group Icon

Group: Member
Posts: 54
Type: None
RM Skill: Undisclosed




You could allow users to create multiple version of the same map junction, and the game randomly choose one of them when creating maps.

Placing events (especially fixed ones like chest/rock/switch etc) randomly will also help.


__________________________
ERROR: NO ERROR DETECTED
Go to the top of the page
 
+Quote Post
   
timm1980
post Jul 23 2011, 08:23 PM
Post #6


Level 1
Group Icon

Group: Member
Posts: 5
Type: None
RM Skill: Undisclosed




QUOTE (Helios @ Jul 23 2011, 07:39 AM) *
You could allow users to create multiple version of the same map junction, and the game randomly choose one of them when creating maps.

Placing events (especially fixed ones like chest/rock/switch etc) randomly will also help.


The way the latest version works, if you create an event with $rand in the name, it will randomly pick a cell in which to place it. Any Tileset B-E tiles are randomly used (everything from Tileset A is used in the final map)

I definitely like the suggestion about multiple different junctions, and choosing them randomly. Wouldn't be too hard to implement, and would add some nice variety.
Go to the top of the page
 
+Quote Post
   
Helios
post Aug 14 2011, 07:34 PM
Post #7


Level 4
Group Icon

Group: Member
Posts: 54
Type: None
RM Skill: Undisclosed




Some random thoughts while trying out the demo::

QUOTE
# The event ID of the "exit dungeon" event on a flat-map style
# dungeon. This is needed so that the script can place the event
# appropriately after assembling the map
RDF_EXIT_EVENT_ID = 4
RDF_STAIRS_UP_EVENT_ID = [1, 6, 7]
RDF_STAIRS_DOWN_EVENT_ID = [2, 8, 9]
RDF_SPECIAL_EVENT_ID = 3


Better use something else, like key words in comment or event name as flag... event ID is inconvenient.

QUOTE
# (x,y) location (relative to upper left of a cell of tiles)
# where the stairs and any chests/random-event should be placed
RDF_STAIRS_LOCATION = [3, 2]
RDF_CHEST_LOCATION = [1, 2]


So every event's position in the cell is fixed? and so do the max number of event, which is always one? Not so random IMHO...

This post has been edited by Helios: Aug 14 2011, 07:49 PM


__________________________
ERROR: NO ERROR DETECTED
Go to the top of the page
 
+Quote Post
   

Reply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:

 

Lo-Fi Version Time is now: 20th May 2013 - 09:29 AM
RPG RPG Revolution is an Privacy Policy and Legal
eXTReMe Tracker