#===============================================================================
# â–¼ Script Information
#===============================================================================
# Name: Dungeon Reuse System
# Author: Dhobby
# Version: 1.00
# Updated: 6/23/2012
#===============================================================================
# â–¼ Instructions
#===============================================================================
# â—¦ This script is not plug and play. It just provides you with some script
# calls that can be called by your events. This script does nothing if it is not
# setup properly but there is more than one way to properly use it. More
# functionality can be achieved the more clever you are about setting up maps.
# Using this script only involves placing events that call methods on your maps.
# It will be confusing at first but is quite easy once you get the hang of it.
# â—¦ Read the author's notes for known quirks about the script.
# â—¦ The $dungeons global variable is a hash that contains every dungeon that has
# been created so far. This information is preserved between sessions.
# â—¦ If you want to modify an individual dungeon's properties and you know the
# name of the dungeon simply type $dungeon[name] followed by:
# Refer to the Dungeon class comments below for greater detail on how to use
# each one.
# .level_sequence = array
# .exit_x = integer
# .exit_y = integer
# .exit_map = integer
# .endless = boolean
# .active = boolean
# .name = string
# .current_level = integer
# .came_from = integer
# .continue = boolean
# .generate_level_sequence(name, exit_x, exit_y, exit_map)
# .reroll levels()
# .transfer_player()
# .teleport_to_exit()
# .to_string()
# â—¦ The following are methods you can use in game events to handle interactions
# between the player and dungeons.
# Refer to the Game_Interpreter class comments below for greater detail on how
# to use each one.
# .get_dungeon(name)
# .get_active_dungeon()
# .set_active_dungeon(dungeon)
# .enter_dungeon(name, reroll)
# .print_info()
# .increase_level(number)
# .decrease_level(number)
# .go_to_level(number)
# .teleport_check(number)
# â—¦ Maps that are to be used in reusable dungeons need to be setup. The
# information is easiest to manage when there is at most only one exit and one
# entrance in each level. It is possible to have multiple exits and entrances
# but you will need to account for these cases yourself either by adding more
# methods to this script or using more events. Instead of using the traditional
# transfer player event you will instead need to use events that call special
# transfer methods such as increase_level and decrease_level. In addition you
# will need to put an event at each starting position (one for each entrance and
# exit on the map) that calls teleport_check. This will be more clear when you
# take a look at how I have arranged events in the demo.
# â—¦ Use enter_dungeon when trying to move the player inside a dungeon. Using the
# traditional transfer player will produce some strange effects because maps are
# often reused.
#===============================================================================
# â–¼ Author's Notes
#===============================================================================
# â—¦ Restricting the first and last levels of a dungeon has no effect on user
# defined dungeons. You can insert MAP_FIRSTS or MAP_LASTS in the appropriate
# indices to achieve the same effect.
# â—¦ Do not ever have more than one dungeon active at any time. The best way to
# avoid this is to set dungeons active only by using the set_dungeon_active
# method.
# â—¦ Calling the enter_dungeon method two times in a row in the same event will
# only transfer the player to the first dungeon.
# â—¦ The player's start position is determined using events that have been placed
# on the map. You must set them in order for the player to appear correctly.
# came_from = 0 means the player went downstairs
# came_from = 1 means the player went upstairs
# You can use different numbers and handle them differently but you should
# remain consistent to avoid headaches.
# â—¦ If your dungeons have events that use the erase event command please do not
# use Map ID: 001 in your dungeon. The first map is used as a transitional map
# when moving the player between levels. If the first map is part of your
# dungeon and is repeated sequentially in a dungeon level sequence, events that
# were erased will not reset properly.
# â—¦ Since the player has to enter a transitional map when changing levels the
# default transfer procedures were not visually pleasing. As such the player is
# now invisible during transfers and only becomes visible again when the
# transfer is complete. In addition transfers are now instant.
# â—¦ This is my first script and it is not as user friendly as I would like it to
# be so I apologize for that. I tested as much as I could but there may be
# subtle bugs that I miss. Please report them to me if you have the time.
# Thanks.
#===============================================================================
# â–¼ DSS - Used for storing static variables that do not change during run time.
#===============================================================================
# â–¼ Editable portion below.
#===============================================================================
module DSS # Dungeon System Settings
#=============================================================================
# Arrays containing maps that can be used for random levels. In most dungeons
# the first and last levels are unique and should not be included in the map
# pool. The first levels sometimes has a different type of entrance such as a
# cave opening. The last level only has an entrance but no way to leave except
# via the entrance.
#=============================================================================
# General purpose levels.
MAP_POOL = [4, 5, 6, 7]
# Maps that can only appear as the first level.
MAP_FIRSTS = [3]
# Maps taht can only appear as the last level.
MAP_LASTS = [10]
#=============================================================================
# Hash for storing pre-defined dungeons. Each entry has a string to represent
# the name of the dungeon mapped to an array. Within the array it contains an
# array or integer at each index. If an index contains an array it represents
# the pool of maps that can be used for that level. If an index contains an
# integer it means to insert a number of random levels drawn from the map pool
# equal to the integer. The first index should always contain the map id and
# coordinates of the dungeon entrance.
#=============================================================================
DUNGEONS =
{
# Name of dungeon => Array
"example" => [
[2, 34, 38], # Entrance [Map ID, X Position, Y Position].
MAP_FIRSTS, # Level 1.
10, # 10 random levels.
[5,6,7,8,9,],
MAP_LASTS,
],
"example2" => [
[2, 37, 38], # Entrance [Map ID, X Position, Y Position].
MAP_FIRSTS,
],
}
#=============================================================================
# Transfer the player to a new map instantly.
#=============================================================================
INSTANT_TRANSFER = true
#=============================================================================
# Remember the last level the player was on and return the player to that
# level when the same dungeon is re-entered.
#=============================================================================
CONTINUE = true
#=============================================================================
# Continue to add random levels when the end of the level sequence is reached.
# This is just the default value. This value can be set for each individual
# dungeon.
#=============================================================================
ENDLESS = true
#=============================================================================
# If this is true, random dungeons will have their first level chosen from the
# map pool of first level maps.
#=============================================================================
RESTRICT_FIRST = true
#=============================================================================
# If this is true, random dungeons will have their last level chosen from the
# map pool of last level maps. This also requires that the dungeon is not
# endless.
#=============================================================================
RESTRICT_LAST = true
#=============================================================================
# Specifies the maximum number of levels that a random dungeon can start with.
# This does not stop you from adding levels over this number later. This also
# means that if the dungeon is endless it will keep adding levels when the
# player advances past the last level.
#=============================================================================
MAX_START_MAPS = 15
end
#===============================================================================
# â–¼ Editing past this line is not recommended.
#===============================================================================
#===============================================================================
# â– Dungeon - Used to store level sequences and other relevant data unique to
# each dungeon.
#===============================================================================
class Dungeon
#=============================================================================
# Accessors.
#=============================================================================
attr_accessor :level_sequence
attr_accessor :exit_x
attr_accessor :exit_y
attr_accessor :exit_map
attr_accessor :endless
attr_accessor :active
attr_accessor :name
attr_accessor :current_level
attr_accessor :came_from
attr_accessor :continue
#=============================================================================
# Initialize object.
#=============================================================================
def initialize()
# This is the order in which maps should appear when the player increases or
# decreases the current level.
@level_sequence = []
# This is the x and y position and map where the player will appear when
# this dungeon is exited.
@exit_x = 0
@exit_y = 0
@exit_map = 0
# If this is true, more maps will be added when the player increases the
# current level above or equal to the size of the level sequence array.
@endless = DSS::ENDLESS
# Name of the dungeon.
@name = ""
# If this is true it means the player is currently traversing through the
# level sequence of this dungeon.
@active = false
# Stores the current level of this dungeon that the player is in.
@current_level = -1
# Stores where the player entered the level from. This can be used to
# determine where the player starts on the map.
@came_from = 0
# Specifies whether or not this dungeon should allow the player to continue
# from where he left off.
@continue = DSS::CONTINUE
end
#=============================================================================
# Create a level sequence for this dungeon. The exit x and y coordinate and
# exit map parameters can be left out but this is not advised when using this
# method on randomly generated dungeons.
#=============================================================================
def generate_level_sequence(name, exit_x = 0, exit_y = 0, exit_map= 0)
dungeon = DSS::DUNGEONS[name] # Fetch dungeon definition.
map_pool = DSS::MAP_POOL # Fetch map pool.
# Set the name.
@name = name
# If dungeon definition exists create the dungeon according to the
# specifications (Psuedo-random dungeons).
if not dungeon == nil
# First entry represents the exit location.
@exit_map = dungeon[0][0]
@exit_x = dungeon[0][1]
@exit_y = dungeon[0][2]
# Create the level sequence.
size = dungeon.size()
for i in 1...size
if dungeon[i].is_a? Integer # Check if the entry is an integer.
for j in 1..dungeon[i]
# Push a random value from the map pool.
@level_sequence.push(map_pool.sample)
end
else
# Push a random value from the array.
@level_sequence.push(dungeon[i].sample)
end
end
# If the user did not define this dungeon explicitly, create a completely
# random dungeon.
else
# Get the direction that the player is facing.
direction = $game_player.direction
# Determine the exit location based on player's current direction.
if direction == 2 # Down.
exit_y -= 1
elsif direction == 4 # Left.
exit_x += 1
elsif direction == 6 # Right.
exit_x -= 1
else # Up.
exit_y += 1
end
# Set the exit location.
@exit_map = exit_map
@exit_x = exit_x
@exit_y = exit_y
# Create the level sequence.
size = (1..DSS::MAX_START_MAPS).to_a().sample
for i in 1..size
# Push a random value from the map pool.
@level_sequence.push(map_pool.sample)
end
# Replace the first level if it is restricted.
if DSS::RESTRICT_FIRST
@level_sequence[0] = DSS::MAP_FIRSTS.sample
end
# Replace the last level if it is restricted and the dungeon is not
# endless.
if DSS::RESTRICT_LAST and not DSS::ENDLESS
@level_sequence[size - 1] = DSS::MAP_LASTS.sample
end
end
end
#=============================================================================
# Recreate the level sequence.
#=============================================================================
def reroll_levels()
@current_level = -1
@level_sequence = []
x = @exit_x
y = @exit_y
map = @exit_map
generate_level_sequence(@name)
# Keep the original exit location.
@exit_x = x
@exit_y = y
@exit_map = map
end
#=============================================================================
# Transfers player to the map corresponding to the current level.
#=============================================================================
def transfer_player(map_id = 0, x = 0, y = 0, direction = 0)
# Peform an instant transfer.
if map_id == 0
map_id = @level_sequence[@current_level]
end
if direction == 0
direction = $game_player.direction # Maintain current direction.
end
# Player must be removed from the current map or else erased events do not
# reset properly.
$game_player.transparent = DSS::INSTANT_TRANSFER
$game_player.reserve_transfer(1, 0, 0, 0)
$game_player.perform_transfer()
# Transfer player.
$game_player.reserve_transfer(map_id, x, y, direction)
$game_player.perform_transfer()
end
#=============================================================================
# Transfers and / or teleport the player to the exit location.
#=============================================================================
def teleport_to_exit()
direction = $game_player.direction
$game_player.reserve_transfer(@exit_map, @exit_x, @exit_y, direction)
# Reset the current level if the dungeon doesn't allow the player to
# continue.
if not @continue
@current_level = -1
end
@active = false
end
#=============================================================================
# Convert all the data stored in this dungeon into a string.
#=============================================================================
def to_string()
string = "Name => " + @name.to_s + "\n"
string += "Size => " + @level_sequence.size.to_s + "\n"
string += "Exit Map => " + @exit_map.to_s + "\n"
string += "Exit X => " + @exit_x.to_s + "\n"
string += "Exit Y => " + @exit_y.to_s + "\n"
string += "Endless => " + @endless.to_s + "\n"
string += "Active => " + @active.to_s + "\n"
string += "Level Sequence => " + @level_sequence.to_s + "\n"
string += "Current Level => " + @current_level.to_s + "\n"
string += "Current Map => " + @level_sequence[@current_level].to_s + "\n"
string += "**************************************************************\n"
return string
end
end
#===============================================================================
# â– DataManager - Used for saving and loading information needed by the Dungeon
# system.
#===============================================================================
class << DataManager
#=============================================================================
# Aliased Methods.
#=============================================================================
alias original_create_game_objects create_game_objects
alias original_extract_save_contents extract_save_contents
#=============================================================================
# Create game objects.
#=============================================================================
def create_game_objects()
# Run original method.
original_create_game_objects()
# Additional initializaion.
$dungeons = {} # Hash for storing dungeon objects.
end
#=============================================================================
# Create save contents.
#=============================================================================
def make_save_contents
# Original contents of the method below.
contents = {}
contents[:system] = $game_system
contents[:timer] = $game_timer
contents[:message] = $game_message
contents[:switches] = $game_switches
contents[:variables] = $game_variables
contents[:self_switches] = $game_self_switches
contents[:actors] = $game_actors
contents[:party] = $game_party
contents[:troop] = $game_troop
contents[:map] = $game_map
contents[:player] = $game_player
# Insert custom save contents here.
contents[:dungeons] = $dungeons
# Do not touch the line below this.
contents
end
#=============================================================================
# Extract save contents.
#=============================================================================
def extract_save_contents(contents)
# Run original method.
original_extract_save_contents(contents)
# Extract custom save contents.
$dungeons = contents[:dungeons]
end
end
#===============================================================================
# â– Game_Interpreter - Used to define new script functions that can be used by
# game events.
#===============================================================================
class Game_Interpreter
#=============================================================================
# Get a specific dungeon. Nil is returned if the dungeon is not found.
#=============================================================================
def get_dungeon(name)
return $dungeons[name]
end
#=============================================================================
# Get the active dungeon. Nil is returned if no dungeon is active.
#=============================================================================
def get_active_dungeon()
$dungeons.each_key do |name_key|
if $dungeons[name_key].active
return $dungeons[name_key]
end
end
return nil
end
#=============================================================================
# Set a dungeon as active. In doing so all other dungeons are set to inactive.
#=============================================================================
def set_active_dungeon(dungeon)
$dungeons.each_key do |name_key|
$dungeons[name_key].active = false
end
dungeon.active = true
end
#=============================================================================
# Enter a dungeon. This method should be called by the event that represents
# the entrance to the dungeon.
#=============================================================================
def enter_dungeon(name, reroll = false)
# Check if the player is still in the map with the event that called this
# method. If a player tries to enter multiple dungeons with the same event
# thsi can occur. If this occurs abort the method.
event = $game_map.events[@event_id]
if event == nil
return
end
dungeon = get_dungeon(name)
# If the dungeon has not been created yet, create it.
if dungeon == nil
dungeon = Dungeon.new
# Pass on the location of the event that called this method.
x = event.x
y = event.y
dungeon.generate_level_sequence(name, x, y, @map_id)
$dungeons[name] = dungeon
end
# Reroll the dungeon's level sequence before entering.
if reroll
dungeon.reroll_levels()
end
# Set the dungeon active and transfer the player.
set_active_dungeon(dungeon)
if dungeon.current_level < 0
dungeon.current_level = 0
end
dungeon.came_from = 0 # Entering a dungeon always counts as going down.
dungeon.transfer_player()
print_info() # For debugging ###############################################
end
#=============================================================================
# Print information to the console. This is only used for testing.
#=============================================================================
def print_info()
if get_active_dungeon() == nil
print "Active Dungeon => NONE\n"
print "**************************************************************\n"
return
end
print "Active Dungeon => " + get_active_dungeon().name + "\n"
print $dungeons[get_active_dungeon().name].to_string
end
#=============================================================================
# Increase the current level of the active dungeon.
#=============================================================================
def increase_level(number = 1)
dungeon = get_active_dungeon()
if not dungeon == nil
dungeon.current_level += number
dungeon.came_from = 0 # Went down.
# If the dungeon is endless and the player tries to increase the current
# level while on the last level of the level sequence, append a random
# level.
if dungeon.current_level >= dungeon.level_sequence.size()
if DSS::ENDLESS
dungeon.level_sequence.push(DSS::MAP_POOL.sample)
else
return
end
end
dungeon.transfer_player()
end
print_info() # For debugging ###############################################
end
#=============================================================================
# Decrease the current level of the active dungeon.
#=============================================================================
def decrease_level(number = 1)
dungeon = get_active_dungeon()
if not dungeon == nil
dungeon.current_level -= number
dungeon.came_from = 1 # Went up.
if dungeon.current_level >= 0
# Transfer the player to the previous level.
dungeon.transfer_player()
else
# If the player was on the first level teleport the player to the exit.
dungeon.teleport_to_exit()
end
end
print_info() # For debugging ###############################################
end
#=============================================================================
# Set the current level of the active dungeon.
#=============================================================================
def go_to_level(number)
dungeon = get_active_dungeon()
if not dungeon == nil
dungeon.current_level = number
dungeon.transfer_player() # NOT TESTED
end
print_info() # For debugging ###############################################
end
#=============================================================================
# If the player entered the level using the specified method, teleport the
# player to the event that called this method.
#=============================================================================
def teleport_check(number)
dungeon = get_active_dungeon()
if dungeon.came_from == number
event = $game_map.events[@event_id]
x = event.x
y = event.y
direction = $game_player.direction
$game_player.reserve_transfer(@map_id, x, y, direction)
end
end
end
#===============================================================================
# â– Scene_Map - Player transfers were modified to be instant.
#===============================================================================
class Scene_Map < Scene_Base
#=============================================================================
# Aliased Methods.
#=============================================================================
alias original_update_transfer_player update_transfer_player
#=============================================================================
# Player transfers are now instant. It also forces the player to become
# visible everytime the player tranfers.
#=============================================================================
def update_transfer_player
return unless $game_player.transfer?
if DSS::INSTANT_TRANSFER
@spriteset.dispose # Dispose of sprite set
$game_player.perform_transfer # Execute player transfer
$game_map.autoplay # Automatically switch BGM and BGS
$game_map.update
@spriteset = Spriteset_Map.new # Recreate sprite set
Input.update
@map_name_window.open # Open location window.
$game_player.transparent = false # Make sure the player is visible
else
original_update_transfer_player()
end
end
end