#===============================================================================
# Custom Resolution
# Authors: ForeverZer0, KK20
# Version: 0.96
# Date: 6.1.2013
#===============================================================================
#
# Introduction:
#
# My (ForeverZer0's) goal in creating this script was to create a system that
# allowed the user to set the screen size to something other than 640 x 480,
# but not have make huge sacrifices in compatibility and performance. Although
# the script is not simply Plug-and-Play, it is about as close as one can
# achieve with a script of this nature.
#
# Instructions:
#
# - Place the "screenshot.dll" from Fantasist's Transition Pack script, which
# can be found here: http://www.sendspace.com/file/yjd54h in your game folder
# - Place this script above main, below default scripts.
# - In my experience, unchecking "Reduce Screen Flickering" actually helps the
# screen not to flicker. Open menu with F1 while playing and set this to what
# you get the best results with.
#
# Features:
#
# - Totally re-written Tilemap and Plane class. Both classes were written to
# display the map across any screen size automatically. The Tilemap class
# can stand as an entirely separate script. More information about it can
# be found here:
#
# - Every possible autotile graphic (48 per autotile) will be cached for the
# next time that tile is used which equates to faster loading times.
# - Autotile animation has been made as efficient as possible, with a system
# that stores their coodinates, but only updates them if visible on screen.
# This greatly reduces the number of iterations at each update.
# - System creates an external file to save pre-cached data priorities and
# autotiles. This will decrease any loading times even more, and only takes a
# second, depending on the number of maps you have.
# - User defined autotile animation speed. Can change with script calls.
# - Automatic re-sizing of Bitmaps and Viewports that are 640 x 480 to the
# defined resolution, unless explicitely over-ridden in the method call.
# The graphics themselves will not be resized, but any existing scripts that
# use the normal screen size will already be configured to display different
# sizes of graphics for transitions, battlebacks, pictures, fogs, etc.
# - Option to have a log file output each time the game is ran, which can alert
# you to possible errors with map sizes, etc.
#
# Issues/Bugs/Possible Bugs:
#
# - Graphic related scripts and your graphics will need to be customized to
# fit the new screen size, so this script is not for everyone.
# - Normal transitions using graphics cannot be used. With the exception of
# a standard fade, like that used when no graphic is defined will be used.
# Aside from that, only special transitions from Transition Pack can be
# used. The script, and its variations, can be found here:
# - Smooth scrolling scripts may need edits to work with the new Tilemap. The
# best way to solve the problem is changing any decimal numbers into
# integers found within that script (for example, change 16.0 to 16). The
# overall quality of the effect may be deminished somewhat.
#
#
# *** For the latest updates and notes, please visit the script's page here:
#
#
#
# Credits/Thanks:
# - ForeverZer0, for script.
# - Creators of the Transition Pack and Screenshot.dll
# - Selwyn, for base resolution script
# - KK20, for Version 0.94 and above and the Tilemap class
#
#===============================================================================
# CONFIGURATION
#===============================================================================
SCREEN = [640,480]###[1024, 576]
# Define the resolution of the game screen. These values can be anything
# within reason. Centering, viewports, etc. will all be taken care of, but it
# is recommended that you use values divisible by 32 for best results.
UPDATE_COUNT = 8
# Define the number of frames between autotile updates. The lower the number,
# the faster the animations cycle. This can be changed in-game with the
# following script call: $game_map.autotile_speed = SPEED
PRE_CACHE_DATA = true
# The pre-cached file is mandatory for the script to work. As long as this is
# true, the data will be created each time the game is test-played. This is
# not always neccessary, only when maps are altered, so you can disable it to
# help speed up game start-up, and it will use the last created file.
RESOLUTION_LOG = true
# This will create a log in the Game directory each time the game is ran in
# DEBUG mode, which will list possible errors with map sizes, etc.
#===============================================================================
# ** Resolution
#===============================================================================
class Resolution
attr_reader :version
def initialize
# Define version.
@version = 0.93
# Set instance variables for calling basic Win32 functions.
ini = Win32API.new('kernel32', 'GetPrivateProfileString','PPPPLP', 'L')
title = "\0" * 256
ini.call('Game', 'Title', '', title, 256, '.\\Game.ini')
title.delete!("\0")
@window = Win32API.new('user32', 'FindWindow', 'PP', 'I').call('RGSS Player', title)
set_window_long = Win32API.new('user32', 'SetWindowLong', 'LIL', 'L')
set_window_pos = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')
@metrics = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')
# Set default size, displaying error if size is larger than the hardware.
default_size = self.size
if default_size[0] < SCREEN[0] || default_size[1] < SCREEN[1]
print("\"#{title}\" requires a minimum screen resolution of [#{SCREEN[0]} x #{SCREEN[1]}]\r\n\r\n" +
"\tYour Resolution: [#{default_size[0]} x #{default_size[1]}]")
exit
end
# Apply resolution change.
x = (@metrics.call(0) - SCREEN[0]) / 2
y = (@metrics.call(1) - SCREEN[1]) / 2
set_window_long.call(@window, -16, 0x14CA0000)
set_window_pos.call(@window, 0, x, y, SCREEN[0] + 6, SCREEN[1] + 26, 0)
@window = Win32API.new('user32', 'FindWindow', 'PP', 'I').call('RGSS Player', title)
end
#--------------------------------------------------------------------------
def size
# Returns the screen size of the machine.
return [@metrics.call(0), @metrics.call(1)]
end
#--------------------------------------------------------------------------
def snapshot(filename = 'Data/snap', quality = 0)
# FILENAME = Filename that the picture will be saved as.
# FILETYPE = 0 = High Quality 1 = Low Quality
@screen = Win32API.new('screenshot.dll', 'Screenshot', 'LLLLPLL', '')
@screen.call(0, 0, SCREEN[0], SCREEN[1], filename, @window, quality)
end
#--------------------------------------------------------------------------
end
#===============================================================================
# ** Integer
#===============================================================================
class Integer
def gcd(num)
# Returns the greatest common denominator of self and num.
min, max = self.abs, num.abs
while min > 0
tmp = min
min = max % min
max = tmp
end
return max
end
def lcm(num)
# Returns the lowest common multiple of self and num.
return [self, num].include?(0) ? 0 : (self / self.gcd(num) * num).abs
end
end
#===============================================================================
# ** Graphics
#===============================================================================
module Graphics
class << self
alias zer0_graphics_transition transition
end
def self.transition(duration = 8, *args)
# Call default transition if no instance of the resolution is defined.
if $resolution == nil
zer0_graphics_transition(duration, *args)
else
# Skip this section and instantly transition graphics if duration is 0.
if duration > 0
# Take a snapshot of the the screen, overlaying screen with graphic.
$resolution.snapshot
zer0_graphics_transition(0)
# Create screen instance
sprite = Sprite.new(Viewport.new(0, 0, SCREEN[0], SCREEN[1]))
sprite.bitmap = Bitmap.new('Data/snap')
# Use a simple fade if transition is not defined.
fade = 255 / duration
duration.times { sprite.opacity -= fade ; update }
# Dispose sprite and delete snapshot file.
[sprite, sprite.bitmap].each {|obj| obj.dispose }
File.delete('Data/snap')
end
zer0_graphics_transition(0)
end
end
end
#===============================================================================
# ** RPG::Cache
#===============================================================================
module RPG::Cache
AUTO_INDEX = [
[27,28,33,34], [5,28,33,34], [27,6,33,34], [5,6,33,34],
[27,28,33,12], [5,28,33,12], [27,6,33,12], [5,6,33,12],
[27,28,11,34], [5,28,11,34], [27,6,11,34], [5,6,11,34],
[27,28,11,12], [5,28,11,12], [27,6,11,12], [5,6,11,12],
[25,26,31,32], [25,6,31,32], [25,26,31,12], [25,6,31,12],
[15,16,21,22], [15,16,21,12], [15,16,11,22], [15,16,11,12],
[29,30,35,36], [29,30,11,36], [5,30,35,36], [5,30,11,36],
[39,40,45,46], [5,40,45,46], [39,6,45,46], [5,6,45,46],
[25,30,31,36], [15,16,45,46], [13,14,19,20], [13,14,19,12],
[17,18,23,24], [17,18,11,24], [41,42,47,48], [5,42,47,48],
[37,38,43,44], [37,6,43,44], [13,18,19,24], [13,14,43,44],
[37,42,43,48], [17,18,47,48], [13,18,43,48], [1,2,7,8]
]
def self.autotile(filename)
key = "Graphics/Autotiles/#{filename}"
if !@cache.include?(key) || @cache[key].disposed?
# Cache the autotile graphic.
@cache[key] = (filename == '') ? Bitmap.new(128, 96) : Bitmap.new(key)
# Cache each configuration of this autotile.
new_bm = self.format_autotiles(@cache[key], filename)
@cache[key].dispose
@cache[key] = new_bm
end
return @cache[key]
end
def self.format_autotiles(bitmap, filename)
if bitmap.height > 32
frames = bitmap.width / 96
template = Bitmap.new(256*frames,192)
# Create a bitmap to use as a template for creation.
(0..frames-1).each{|frame|
(0...6).each {|i| (0...8).each {|j| AUTO_INDEX[8*i+j].each {|number|
number -= 1
x, y = 16 * (number % 6), 16 * (number / 6)
rect = Rect.new(x + (frame * 96), y, 16, 16)
template.blt((32 * j + x % 32) + (frame * 256), 32 * i + y % 32, bitmap, rect)
}}}}
return template
else
return bitmap
end
end
end
#===============================================================================
# ** Tilemap
#===============================================================================
class Tilemap
attr_reader :map_data, :ox, :oy, :viewport
attr_accessor :tileset, :autotiles, :priorities
def initialize(viewport)
# Initialize instance variables to store required data.
@viewport, @autotiles, @tile_sprites, @ox, @oy = viewport, [], [], 0, 0
@current_frame, @total_frames = [], []
@tilemap_drawn = false
@ox_oy_set = [false, false]
# Get priority data for this tileset from instance of Game_Map.
@priorities = $game_map.priorities
# Holds all the Sprite instances of animating tiles (keys based on tile's ID)
@animating_tiles = {}
end
#-----------------------------------------------------------------------------
# Initialize all tile sprites. Draws three sprites per (x,y).
#-----------------------------------------------------------------------------
def init_tiles
# Determine how many frames of animation this autotile has
for i in 0..6
bm = @autotiles[i]
if bm.nil?
@total_frames = 1
elsif bm.height > 32
@total_frames[i] = bm.width / 256
else
@total_frames[i] = bm.width / 32
end
@current_frame[i] = 0
end
# Turn on flag that the tilemap sprites have been initialized
@tilemap_drawn = true
# Create a sprite and viewport to use for each priority level.
(0...((SCREEN[0]/32+2) * (SCREEN[1]/32+2))*3).each{|i|
@tile_sprites[i/3] = [] if @tile_sprites[i/3].nil?
@tile_sprites[i/3][i%3] = Sprite.new(@viewport)
# Shorter and easier to work with for below
tile = @tile_sprites[i/3][i%3]
# Assign tile's respective ID value
tile.tile_sprite_id = i
# Draw sprite at index location (ex. ID 0 should always be the top-left sprite)
tile.x = (i % ((SCREEN[0]/32+2)*3) / 3 * 32) - 32 + (@ox % 32)
tile.y = (i / ((SCREEN[0]/32+2)*3) * 32) - 32 + (@oy % 32)
map_x, map_y = (tile.x+@ox)/32, (tile.y+@oy)/32
# If the tile happens to be drawn along the outside borders of the map
if map_x < 0 || map_x >= $game_map.width || map_y < 0 || map_y >= $game_map.height
tile.z = 0
tile.bitmap = RPG::Cache.picture('')
tile.src_rect.set(0,0,0,0)
else # Tile is actually on the map
tile_id = @map_data[map_x,map_y,i%3]
if @priorities[tile_id] == 0
tile.z == 0
else
tile.z = tile.y + @priorities[tile_id] * 32 + 32
end
# No tile exists here
if tile_id == 0
tile.bitmap = RPG::Cache.picture('')#@tileset
tile.src_rect.set(0,0,0,0)
elsif tile_id >= 384 # non-autotile
tile.bitmap = @tileset
tile.src_rect.set(((tile_id - 384) % 8)*32,((tile_id - 384) / 8)*32, 32, 32)
else # autotile
tile.bitmap = @autotiles[tile_id/48-1]
tile.src_rect.set(((tile_id % 48) % 8)*32,((tile_id % 48) / 8)*32, 32, 32)
@animating_tiles[i] = tile if tile.bitmap.width > 256
end
end
}
# Sprite ID located at top left corner (ranges from 0..map_width * map_height
@corner_index = 0
end
#-----------------------------------------------------------------------------
# Makes update to ox and oy. Sprites out of range will be moved based on these
# two values.
#-----------------------------------------------------------------------------
def ox=(ox)
#
unless @tilemap_drawn
@ox = ox
@ox_oy_set[0] = true
return
end
return if @ox == ox
# Shift all tiles left or right by the difference
shift = @ox - ox
@tile_sprites.each {|set| set.each{|tile| tile.x += shift }}
@ox = ox
# Determine if columns need to be shifted
col_num = @corner_index
return unless @tile_sprites[col_num][0].x <= -49 || @tile_sprites[col_num][0].x >= -17
modTileId = ((SCREEN[0]+64)*(SCREEN[1]+64))/1024
# If new ox is greater than old ox
if shift < 0
# Move all sprites in left column to the right side and change bitmaps
# and z-values
(0...(SCREEN[1]/32+2)).each{|n|
j = ((SCREEN[0]/32+2) * n + col_num) % modTileId
@tile_sprites[j].each_index{|i|
tile = @tile_sprites[j][i]
@animating_tiles.delete(tile.tile_sprite_id)
tile.x += 64 + SCREEN[0]
map_x, map_y = (tile.x+@ox)/32, (tile.y+@oy)/32
tile_id = @map_data[map_x,map_y,i]
if tile_id.nil?
tile.z = [map_y * 32, 0].max
tile.bitmap = RPG::Cache.picture('')
tile.src_rect.set(0,0,0,0)
next
else
if @priorities[tile_id] == 0
tile.z = 0
else
tile.z = 32 + (tile.y/32) * 32 + @priorities[tile_id] * 32
end
end
if tile_id == 0
tile.bitmap = RPG::Cache.picture('')
tile.src_rect.set(0,0,0,0)
elsif tile_id >= 384
tile.bitmap = @tileset
tile.src_rect.set(((tile_id - 384) % 8) * 32,((tile_id - 384) / 8) *32, 32, 32)
else
auto_id = tile_id/48-1
tile.bitmap = @autotiles[auto_id]
tile.src_rect.set(((tile_id % 48) % 8)*32 + @current_frame[auto_id] * 256,((tile_id % 48) / 8)*32, 32, 32)
@animating_tiles[tile.tile_sprite_id] = tile if @total_frames[auto_id] > 1
end
}
}
# New corner should be the tile immediately right of the previous tile
col_num /= SCREEN[0]/32+2
col_num *= SCREEN[0]/32+2
@corner_index = (@corner_index + 1) % (SCREEN[0]/32+2) + col_num
else
# Shift right column to the left
# Gets the right column
row_index = col_num / (SCREEN[0]/32+2)
row_index *= (SCREEN[0]/32+2)
col_num = (@corner_index - 1) % (SCREEN[0]/32+2) + row_index
(0...(SCREEN[1]/32+2)).each{|n|
j = ((SCREEN[0]/32+2) * n + col_num) % modTileId
@tile_sprites[j].each_index{|i|
tile = @tile_sprites[j][i]
@animating_tiles.delete(tile.tile_sprite_id)
tile.x -= 64 + SCREEN[0]
map_x, map_y = (tile.x+@ox)/32, (tile.y+@oy)/32
tile_id = @map_data[map_x,map_y,i]
if tile_id.nil?
tile.z = [map_y * 32, 0].max
tile.bitmap = @tileset
tile.src_rect.set(0,0,0,0)
next
else
if @priorities[tile_id] == 0
tile.z = 0
else
tile.z = 32 + (tile.y/32) * 32 + @priorities[tile_id] * 32
end
end
if tile_id == 0
tile.bitmap = RPG::Cache.picture('')
tile.src_rect.set(0,0,0,0)
elsif tile_id >= 384
tile.bitmap = @tileset
tile.src_rect.set(((tile_id - 384) % 8)*32,((tile_id - 384) / 8)*32, 32, 32)
else
auto_id = tile_id/48-1
tile.bitmap = @autotiles[auto_id]
tile.src_rect.set(((tile_id % 48) % 8)*32 + @current_frame[auto_id] * 256,((tile_id % 48) / 8)*32, 32, 32)
@animating_tiles[tile.tile_sprite_id] = tile if @total_frames[auto_id] > 1
end
}
}
col_num /= SCREEN[0]/32+2
col_num *= SCREEN[0]/32+2
@corner_index = (@corner_index - 1) % (SCREEN[0]/32+2) + col_num
end
# puts @corner_index
end
#-----------------------------------------------------------------------------
def oy=(oy)
#
unless @tilemap_drawn
@oy = oy
@ox_oy_set[1] = true
return
end
return if @oy == oy
# Shift all tiles up or down by the difference, and change z-value
shift = @oy - oy
@tile_sprites.each {|set| set.each{|tile| tile.y += shift; tile.z += shift unless tile.z == 0 }}
@oy = oy
# Determine if rows need to be shifted
row_num = @corner_index
return unless @tile_sprites[row_num][0].y <= -49 || @tile_sprites[row_num][0].y >= -17
# Needed for resetting the new corner index much later.
modTileId = ((SCREEN[0]+64)*(SCREEN[1]+64))/1024
# If new oy is greater than old oy
if shift < 0
row_num /= SCREEN[0]/32+2
row_num *= SCREEN[0]/32+2
# Move all sprites in top row to the bottom side and change bitmaps
# and z-values
(0...(SCREEN[0]/32+2)).each{|n|
# Run through each triad of sprites from left to right
j = n + row_num
@tile_sprites[j].each_index{|i|
# Get each individual tile on each layer
tile = @tile_sprites[j][i]
@animating_tiles.delete(tile.tile_sprite_id)
tile.y += 64 + SCREEN[1]
# Determine what map coordinate this tile now resides at...
map_x, map_y = (tile.x+@ox)/32, (tile.y+@oy)/32
# ...and get its tile_id
tile_id = @map_data[map_x,map_y,i]
# If no tile exists here (effectively out of array bounds)
if tile_id.nil?
tile.z = [map_y * 32, 0].max
tile.bitmap = RPG::Cache.picture('')
tile.src_rect.set(0,0,0,0)
next
else # Tile exists. Figure out its z-coordinate based on priority
if @priorities[tile_id] == 0
tile.z = 0
else
tile.z = 32 + (tile.y/32) * 32 + @priorities[tile_id] * 32
end
end
# If empty tile
if tile_id == 0
tile.bitmap = RPG::Cache.picture('')
tile.src_rect.set(0,0,0,0)
# If not an autotile
elsif tile_id >= 384
tile.bitmap = @tileset
tile.src_rect.set(((tile_id - 384) % 8) * 32,((tile_id - 384) / 8) *32, 32, 32)
else # Autotile
auto_id = tile_id/48-1
tile.bitmap = @autotiles[auto_id]
tile.src_rect.set(((tile_id % 48) % 8)*32 + @current_frame[auto_id] * 256,((tile_id % 48) / 8)*32, 32, 32)
@animating_tiles[tile.tile_sprite_id] = tile if @total_frames[auto_id] > 1
end
}
}
@corner_index = (@corner_index + (SCREEN[0]/32+2)) % modTileId
else
row_num = (@corner_index - (SCREEN[0]/32+2)) % modTileId
row_num /= SCREEN[0]/32+2
row_num *= SCREEN[0]/32+2
(0...(SCREEN[0]/32+2)).each{|n|
# Run through each triad of sprites from left to right
j = n + row_num
@tile_sprites[j].each_index{|i|
# Get each individual tile on each layer
tile = @tile_sprites[j][i]
@animating_tiles.delete(tile.tile_sprite_id)
tile.y -= 64 + SCREEN[1]
# Determine what map coordinate this tile now resides at...
map_x, map_y = (tile.x+@ox)/32, (tile.y+@oy)/32
# ...and get its tile_id
tile_id = @map_data[map_x,map_y,i]
# If no tile exists here (effectively out of array bounds)
if tile_id.nil?
tile.z = [map_y * 32, 0].max
tile.bitmap = RPG::Cache.picture('')
tile.src_rect.set(0,0,0,0)
next
else # Tile exists. Figure out its z-coordinate based on priority
if @priorities[tile_id] == 0
tile.z = 0
else
tile.z = 32 + (tile.y/32) * 32 + @priorities[tile_id] * 32
end
end
# If empty tile
if tile_id == 0
tile.bitmap = RPG::Cache.picture('')
tile.src_rect.set(0,0,0,0)
# If not an autotile
elsif tile_id >= 384
tile.bitmap = @tileset
tile.src_rect.set(((tile_id - 384) % 8) * 32,((tile_id - 384) / 8) *32, 32, 32)
else # Autotile
auto_id = tile_id/48-1
tile.bitmap = @autotiles[auto_id]
tile.src_rect.set(((tile_id % 48) % 8)*32 + @current_frame[auto_id] * 256,((tile_id % 48) / 8)*32, 32, 32)
@animating_tiles[tile.tile_sprite_id] = tile if @total_frames[auto_id] > 1
end
}
}
@corner_index = (@corner_index - (SCREEN[0]/32+2)) % modTileId
end
# puts @corner_index
end
#-----------------------------------------------------------------------------
# Dispose all the tile sprites
#-----------------------------------------------------------------------------
def dispose
# Dispose all of the sprites
@tile_sprites.each {|set| set.each{|tile| tile.dispose }}
@tile_sprites.clear
@animating_tiles.clear
end
#-----------------------------------------------------------------------------
# Set map data
#-----------------------------------------------------------------------------
def map_data=(data)
# Set the map data to an instance variable.
@map_data = data
@animating_tiles.clear
# Initialize tiles if not created. Else, dispose old bitmaps and set new ones.
if @tile_sprites == []
#init_tiles
else
# Clear any sprites' bitmaps if it exists, or create new ones.
@tile_sprites.each {|set| set.each_index{|i|
tile = set[i]
tile.bitmap.dispose
map_x, map_y = tile.x/32, tile.y/32
if map_x < 0 || map_x >= SCREEN[0]/32 || map_y < 0 || map_y >= SCREEN[1]/32
tile.z = [map_y * 32, 0].max
tile.bitmap = @tileset
else
tile_id = @map_data[map_x,map_y,i]
tile.z = map_y * 32 + @priorities[tile_id] * 32
if tile_id >= 384
tile.bitmap = @tileset
tile.src_rect.set((tile_id - 384 % 8)*32,(tile_id - 384 / 8)*32, 32, 32)
else
auto_id = tile_id/48-1
tile.bitmap = @autotiles[auto_id]
tile.src_rect.set(((tile_id % 48) % 8)*32 + @current_frame[auto_id] * 256,((tile_id % 48) / 8)*32, 32, 32)
@animating_tiles[tile.tile_sprite_id] = tile
end
end
}}
end
end
#-----------------------------------------------------------------------------
# Update the tile sprites; make changes to the map_data and update autotiles
#-----------------------------------------------------------------------------
def update
if Input.trigger?(Input::SHIFT)
list = []
list.push(@corner_index)
@tile_sprites.each{|set| list.push(set[0].y)}
p list
end
# Can't update anything if the ox and oy have not yet been set
return if @ox_oy_set != [true, true]
# If the tilemap sprites have not been initialized, GO DO IT
if !@tilemap_drawn
init_tiles
end
# If made any changes to $game_map.data, the proper graphics will be drawn
if @map_data.table_changes != nil
@map_data.table_changes.each{|item|
x,y,z,tile_id = item
# Make actual change to table
@map_data[x,y,z] = tile_id
# If this changed tile is visible on screen
if x >= @ox/32 - 1 and x <= (@ox+SCREEN[0])/32 and
y >= @oy/32 - 1 and y <= (@oy+SCREEN[1])/32
# Locate which tile sprite is at this location
x_dif = x - (@ox/32 - 1)
y_dif = y - (@oy/32 - 1)
sprite_id = @corner_index % (SCREEN[0]/32+2)
sprite_id += x_dif
sprite_id %= (SCREEN[0]/32+2)
sprite_id += (SCREEN[0]/32+2) * (@corner_index/(SCREEN[0]/32+2))
sprite_id += y_dif * (SCREEN[0]/32+2)
sprite_id %= ((SCREEN[0]+64)*(SCREEN[1]+64))/1024
p [@ox,@oy,x_dif,y_dif]
tile = @tile_sprites[sprite_id][z]
@animating_tiles.delete(tile.tile_sprite_id)
#Figure out its z-coordinate based on priority
if @priorities[tile_id] == 0
tile.z = 0
else
tile.z = 32 + (tile.y/32) * 32 + @priorities[tile_id] * 32
end
# If empty tile
if tile_id == 0
tile.bitmap = RPG::Cache.picture('')
tile.src_rect.set(0,0,0,0)
# If not an autotile
elsif tile_id >= 384
tile.bitmap = @tileset
tile.src_rect.set(((tile_id - 384) % 8) * 32,((tile_id - 384) / 8) *32, 32, 32)
else # Autotile
auto_id = tile_id/48-1
tile.bitmap = @autotiles[auto_id]
tile.src_rect.set(((tile_id % 48) % 8)*32 + @current_frame[auto_id] * 256,((tile_id % 48) / 8)*32, 32, 32)
@animating_tiles[tile.tile_sprite_id] = tile if @total_frames[auto_id] > 1
end
end
}
@map_data.table_changes = nil
end
# Update the sprites.
if Graphics.frame_count % $game_map.autotile_speed == 0
# Increase current frame of tile by one, looping by width.
for i in 0..6
@current_frame[i] = (@current_frame[i] + 1) % @total_frames[i]
end
@animating_tiles.each_value{|tile|
frames = tile.bitmap.width
tile.src_rect.set((tile.src_rect.x + 256) % frames, tile.src_rect.y, 32, 32)
}
end
end
end
#===============================================================================
# Game_Map
#===============================================================================
class Game_Map
attr_reader :tile_size, :autotile_speed, :autotile_data, :priority_data
alias zer0_load_autotile_data_init initialize
def initialize
# Call original method.
zer0_load_autotile_data_init
# Store the screen dimensions in tiles to save on calculations later.
@tile_size = [SCREEN[0], SCREEN[1]].collect {|n| (n / 32.0).ceil }
@autotile_speed = UPDATE_COUNT
end
alias zer0_map_edge_setup setup
def setup(map_id)
# Call original method.
zer0_map_edge_setup(map_id)
# Find the displayed area of the map in tiles. No calcualting every step.
@map_edge = [self.width - @tile_size[0], self.height - @tile_size[1]]
@map_edge.collect! {|size| size * 128 }
end
def scroll_down(distance)
# Find point that the map edge meets the screen edge, using custom size.
@display_y = [@display_y + distance, @map_edge[1]].min
end
def scroll_right(distance)
# Find point that the map edge meets the screen edge, using custom size.
@display_x = [@display_x + distance, @map_edge[0]].min
#p @display_x
end
def autotile_speed=(speed)
# Keep the speed above 0 to prevent the ZeroDivision Error.
@autotile_speed = speed
@autotile_speed = 1 if @autotile_speed < 1
end
alias get_map_data data
def data
# For the Tilemap class to recognize that tile graphics need changing
@map.data.make_changes = true
get_map_data
end
end
=begin
#===============================================================================
# ** Game_Character
#===============================================================================
class Game_Character
def screen_z(height = 0)
if @always_on_top
# Return high Z value if always on top flag is present.
return 999
elsif height != nil && height > 32
# Iterate through map characters to their positions relative to this one.
characters = $game_map.events.values
characters += [$game_player] unless self.is_a?(Game_Player)
# Find and set any character that is one tile above this one.
above, z = characters.find {|chr| chr.x == @x && chr.y == @y - 1 }, 0
if above != nil
# If found, adjust value by this one's Z, and the other's.
z = (above.screen_z(48) >= 32 ? 33 : 31)
end
# Check for Blizz-ABS and adjust coordinates for the pixel-rate.
if $BlizzABS == nil
x = ((@x / $game_system.pixel_rate) / 2.0).to_i
y = ((@y / $game_system.pixel_rate) / 2.0).to_i
return $game_map.priority_data[x, y] + z
else
return $game_map.priority_data[@x, @y] + z
end
end
return 0
end
end
=end
#===============================================================================
# ** Game_Player
#===============================================================================
class Game_Player
CENTER_X = ((SCREEN[0] / 2) - 16) * 4 # Center screen x-coordinate * 4
CENTER_Y = ((SCREEN[1] / 2) - 16) * 4 # Center screen y-coordinate * 4
def center(x, y)
# Recalculate the screen center based on the new resolution.
max_x = ($game_map.width - $game_map.tile_size[0]) * 128
max_y = ($game_map.height - $game_map.tile_size[1]) * 128
$game_map.display_x = [0, [x * 128 - CENTER_X, max_x].min].max
$game_map.display_y = [0, [y * 128 - CENTER_Y, max_y].min].max
end
end
#===============================================================================
# ** Sprite
#===============================================================================
class Sprite
attr_accessor :tile_sprite_id
alias tile_sprite_id_init initialize
def initialize(view = nil)
# No defined ID
@tile_sprite_id = nil
# Call original method.
tile_sprite_id_init(view)
end
end
#===============================================================================
# ** Viewport
#===============================================================================
class Viewport
alias zer0_viewport_resize_init initialize
def initialize(x=0, y=0, width=SCREEN[0], height=SCREEN[1], override=false)
if x.is_a?(Rect)
# If first argument is a Rectangle, just use it as the argument.
zer0_viewport_resize_init(x)
elsif [x, y, width, height] == [0, 0, 640, 480] && !override
# Resize fullscreen viewport, unless explicitly overridden.
zer0_viewport_resize_init(Rect.new(0, 0, SCREEN[0], SCREEN[1]))
else
# Call method normally.
zer0_viewport_resize_init(Rect.new(x, y, width, height))
end
end
def resize(*args)
# Resize the viewport. Can call with (X, Y, WIDTH, HEIGHT) or (RECT).
self.rect = args[0].is_a?(Rect) ? args[0] : Rect.new(*args)
end
end
#===============================================================================
# ** Bitmap
#===============================================================================
class Bitmap
alias zer0_resolution_resize_init initialize
def initialize(width = 32, height = 32, override = false)
if width.is_a?(String)
# Call the filename if the first argument is a String.
zer0_resolution_resize_init(width)
elsif [width, height] == [640, 480] && !override
# Resize fullscreen bitmap unless explicitly overridden.
zer0_resolution_resize_init(SCREEN[0], SCREEN[1])
else
# Call method normally.
zer0_resolution_resize_init(width, height)
end
end
end
#===============================================================================
# Table
#===============================================================================
class Table
attr_accessor :make_changes, :table_changes
alias set_method []=
def []=(x,y=nil,z=nil,v=nil)
# If making changes to game_map.data
if @make_changes
@table_changes = [] if @table_changes.nil?
@table_changes.push([x,y,z,v])
@make_changes = false
end
# Call original method
if z == nil
set_method(x,y)
elsif v == nil
set_method(x,y,z)
else
set_method(x,y,z,v)
end
end
end
=begin
#===============================================================================
# ** Sprite
#===============================================================================
# Added ID variable for tile sprites
class Sprite
attr_accessor :tile_sprite_id
alias zer0_sprite_resize_init initialize
def initialize(view = nil)
# No defined ID
@tile_sprite_id = nil
# Unless viewport is defined, use the new default viewport size.
view = Viewport.new(0, 0, SCREEN[0], SCREEN[1]) if view == nil
# Call original method.
zer0_sprite_resize_init(view)
end
end
#===============================================================================
# ** Plane
#===============================================================================
class Plane < Sprite
def z=(z)
# Change the Z value of the viewport, not the sprite.
super(z * 1000)
end
def ox=(ox)
return if @bitmap == nil
# Have viewport stay in loop on X-axis.
super(ox % @bitmap.width)
end
def oy=(oy)
return if @bitmap == nil
# Have viewport stay in loop on Y-axis.
super(oy % @bitmap.height)
end
def bitmap
# Return the single bitmap, before it was tiled.
return @bitmap
end
def bitmap=(tile)
@bitmap = tile
# Bug fix for changing panoramas
return if tile.nil?
# Calculate the number of tiles it takes to span screen in both directions.
xx = 1 + (SCREEN[0].to_f / tile.width).ceil
yy = 1 + (SCREEN[1].to_f / tile.height).ceil
# Create appropriately sized bitmap, then tile across it with source image.
plane = Bitmap.new(@bitmap.width * xx, @bitmap.height * yy)
(0..xx).each {|x| (0..yy).each {|y|
plane.blt(x * @bitmap.width, y * @bitmap.height, @bitmap, @bitmap.rect)
}}
# Set the bitmap to the sprite through its super class (Sprite).
super(plane)
end
# Redefine methods dealing with coordinates (defined in super) to do nothing.
def x; end
def y; end
def x=(x); end
def y=(y); end
end
#===============================================================================
# DEBUG Mode
#===============================================================================
if $DEBUG #if running in debug/testplay mode
if PRE_CACHE_DATA # If precache configuration is true
# load all tilesets in database
tilesets = load_data('Data/Tilesets.rxdata')
# maps = mapinfos, priority_data and autotile_data are empty hashes
maps, priority_data, autotile_data = load_data('Data/MapInfos.rxdata'), {}, {}
# For each map ID
maps.each_key {|map_id|
# load map file
map = load_data(sprintf("Data/Map%03d.rxdata", map_id))
# map data is loaded (3D-Table)
data = map.data
# get the map's tileset
tileset = tilesets[map.tileset_id]
# get tileset's priorities (*0 to *5)
priorities = tileset.priorities
# get autotiles that tileset uses and load their bitmaps, storing them in cache
autotiles = tileset.autotile_names.collect {|name| RPG::Cache.autotile(name) }
animated = [[], [], [], []]
# for each autotile in array by index (0 to number of autotiles)
autotiles.each_index {|i|
width = autotiles[i].width
# go to next autotile if width is 96 or less (non-animating)
next unless width > 96
# [name of autotile, frames of animation, 0, empty array]
### parameters = [tileset.autotile_names[i], width / 96, 0, []]
parameters = [tileset.autotile_names[i], width / 256, 0, []]
# now store these values into variable 'animated'
[0, 1, 2, 3].each {|j| animated[j].push(parameters[j]) }
}
# for each z-index, for each y-coordinate, for each x-coordinate
[0, 1, 2].each {|z| (0...data.ysize).each {|y| (0...data.xsize).each {|x|
# get tile_id at (x,y,z)
tile_id = data[x, y, z]
# ignore if tile is blank square (top left on tileset)
next if tile_id == 0
# if autotile
if tile_id < 384
# get autotile name that this tile belongs to
name = tileset.autotile_names[(tile_id / 48) - 1]
# find this autotile's array index in 'animated'
index = animated[0].index(name)
# skip if not an animated autotile
next if index == nil
#---------------------------------------------------------------------
# Most of the following below has been removed due to graphical errors
#---------------------------------------------------------------------
# above = []
# Check layers above current z-layer, pushing tile_ids if they exist
# ((z+1)...data.zsize).each {|zz| above.push(data[x, y, zz]) }
# if all the above tile IDs are blank squares, then store this tile ID
animated[3][index].push([x, y, z]) #if above.all? {|id| id == 0 }
end
}}}
# make a new table that is as tall and as wide as the map's size
table = Table.new(data.xsize, data.ysize)
# run through each square on this grid top to bottom, left to right
(0...table.xsize).each {|x| (0...table.ysize).each {|y|
# get tile IDs one space north of current tile on all layers (e.g. trees)
above = [0, 1, 2].collect {|z| data[x, y-1, z] }
# get priorities of tile IDs we collected, replacing values in 'above'
above = above.compact.collect {|p| priorities[p] }
# if any of the priorities collected is 1, then our current spot (x,y)
# is equal to 32. Else, 0.
table[x, y] = above.include?(1) ? 32 : 0
}}
priority_data[map_id], autotile_data[map_id] = table, animated
# If project has a lot of maps, this will ensure you will not get a
# 'Script is hanging' error when caching
Graphics.update
}
file = File.open('Data/PreCacheMapData.rxdata', 'wb')
Marshal.dump(priority_data, file)
Marshal.dump(autotile_data, file)
file.close
RPG::Cache.clear
end
if RESOLUTION_LOG
undersize, mapinfo = [], load_data('Data/MapInfos.rxdata')
file = File.open('Data/PreCacheMapData.rxdata', 'rb')
cached_data = Marshal.load(file)
file.close
# Create a text file and write the header.
file = File.open('Resolution Log.txt', 'wb')
file.write("[RESOLUTION LOG]\r\n\r\n")
time = Time.now.strftime("%x at %I:%M:%S %p")
file.write(" Logged on #{time}\r\n\r\n")
lcm = SCREEN[0].lcm(SCREEN[1]).to_f
aspect = [(lcm / SCREEN[1]), (lcm / SCREEN[0])].collect {|num| num.round }
file.write("RESOLUTION:\r\n #{SCREEN[0].to_i} x #{SCREEN[1].to_i}\r\n")
file.write("ASPECT RATIO:\r\n #{aspect[0]}:#{aspect[1]}\r\n")
file.write("MINIMUM MAP SIZE:\r\n #{(SCREEN[0] / 32).ceil} x #{(SCREEN[1] / 32).ceil}\r\n\r\n")
file.write("UNDERSIZED MAPS:\r\n")
mapinfo.keys.each {|key|
map = load_data(sprintf("Data/Map%03d.rxdata", key))
next if map.width*32 >= SCREEN[0] && map.height*32 >= SCREEN[1]
undersize.push(key)
}
unless undersize.empty?
file.write("The following maps are too small for the defined resolution. They should be adjusted to prevent graphical errors.\r\n\r\n")
undersize.sort.each {|id| file.write(" MAP[#{id}]: #{mapinfo[id].name}\r\n") }
file.write("\r\n")
else
file.write(' All maps are sized correctly.')
end
file.close
end
end
=end
# Call the resolution, setting it to a global variable for plug-ins.
$resolution = Resolution.new