# Clean up code and make it more modular
#==============================================================================
# ** Window_HorizontalSelect < Window_Base - Class
#------------------------------------------------------------------------------
# - This window allows for one row of horizontal scrolling text that displays
# various options that can be configured per window
# - Window allows Scrolling Horizontally, which can also be Animated
# - Versatile Class can be positioned anywhere on screen without any
# additional need to position the Cursor
# - The Lables for the Options do not all need to be displayed at the same
# time, which is entirely the point of allowing this Menu class to
# be scrolled horizontally
# - Text can be changed from outside the class. The window can be used for
# any type of one line Horizontal Menu with scrolling overflow such as
# a Menu that shows "Yes / No" or "On / Off" or even Screen Resolutions
# - This script does not handle Screen Resolutions, only an Option Menu
# that allows the Player to change any Script settings during gameplay
# from Game Interface.
# - Padding allows scrolling to occur prior to the item on the edge
# being selected to show that more options are available to player.
#==============================================================================
class Window_HorizontalSelect < Window_Base
#--------------------------------------------------------------------------
# * Public Instance Variables - Window_HorizontalSelect
# - The properties with attr_reader methods have Setter Methods which
# are necessary to adjust other internal properties when changed.
#--------------------------------------------------------------------------
attr_reader :index # cursor position
attr_reader :help_window # help window
attr_reader :column_max # Columns to be displayed
attr_reader :column_pad # scrolls columns from window edge
attr_accessor :anime_frames # Total Frames for each Animation
attr_accessor :hide_cursor # Hide Cursor when Inactive (Bool)
#--------------------------------------------------------------------------
# * Object Initialization - Window_HorizontalSelect
# - Initializes Main Options Window for Category Input
# - Has Default Values for everything but x, y, width and height
# x : x-position of window
# y : y-position of window
# w : width of window
# h : height of window
# c : Cursor Hiding (Bool) True to Hide Cursor when Inactive
# labels : Array of Text Labels to display in Window ['Foo','Bar','Baz']
# help : Array of Text to display in Help Window for each Label
# i : Index (Ingeger)
# m : Column Max (Integer)
# p : Column Padding (Integer)
# f : Frames of Animation (set to 0 for no animation)
#--------------------------------------------------------------------------
def initialize(x, y, w, h, c=false, labels=nil, help=nil, i=0, m=3, p=1, f=8)
# Call Parent Class Initialize Method for Skins and Cursors
super(x, y, w, h)
# Sets up Option Labels and Option Help Text
setup_option_text(labels, help)
# Initializes and calculates internal Variables
setup_variables(i, m, p, f, c)
# Sets up Option Labels and Option Help Text
setup_option_text(labels, help)
# Draw Contents
refresh
end
#--------------------------------------------------------------------------
# * Setup Variables - Window_HorizontalSelect
# - Initialize Variables
# index : Integer Default Value
# column_max : Integer, Number of Columns to display
# column_pad : Integer, Pads Scrolling, Set to 0 to scroll at edge
# anime_frames : Number of Frames to Animate Scroll to next Item
# c : Cursor Hiding (Bool) True to Hide Cursor when Inactive
#--------------------------------------------------------------------------
def setup_variables(index, column_max, column_pad, anime_frames, cursor)
# Set Index to First Option (Change Default with @window.index = 3)
@index = index
# Number of Labels to display, scrollable when Options exceed this number
@column_max = column_max
# Columns to Pad when determining Scrolling (set to 0 for edge scrolling)
@column_pad = column_pad
# Number of Frames to Animate Scrolling (set to 0 for instant unanimated)
@anime_frames = anime_frames
# Counter for Animation when Animating (Internal)
@anime_duration = 0
# Hide Cursor when this option is true, Default is False via Initialize
@hide_cursor = cursor
# OX Position Target to Animate Scrolling
@ox_target = self.ox
end
#--------------------------------------------------------------------------
# * Refresh - Window_HorizontalSelect
# - Draws Text and Cursor for Window
#--------------------------------------------------------------------------
def refresh
# Clear Text Contents of Window
self.contents.clear unless self.contents.nil?
# Recalculate Width of each Option Label
@label_width = setup_label_width
# Create Bitmap for drawing contents (Must redraw if variables change)
self.contents = Bitmap.new(@label_width * @option_labels.size - 32, 32)
# Write Text for each Option Label
for i in 0...@option_labels.size
# Align Text Horizontally using Width of Columns to Center
draw_option_item(i)
end
# Setup the Left and Right Column X Positions
setup_column_positions
# Set Scroll Position of Background via self.ox
self.ox = make_ox
# Update Cursor Position
update_cursor_rect
end
#--------------------------------------------------------------------------
# * Setup Label Width - Window_HorizontalSelect
# - Uses current variables to determine width of each Option Label
#--------------------------------------------------------------------------
def setup_label_width
# Calculates width of each Option Label based on size of Window, not Bitmap
return self.width / @column_max
end
#--------------------------------------------------------------------------
# * Setup Column Positions - Window_HorizontalSelect
# - Sets the Left and Right Column X Positions
#--------------------------------------------------------------------------
def setup_column_positions
# Set X Position for Left Column
setup_left_column
# Set X Position for Right Column
setup_right_column
end
#--------------------------------------------------------------------------
# * Setup Left Column - Window_HorizontalSelect
# - Determines Position of Left Column
# - Allows for 1 pixel of additional padding for Math Rounding to 1 errors
#--------------------------------------------------------------------------
def setup_left_column
# X Position for Left Column
@left_col = self.x + (@label_width * @column_pad) + 1
end
#--------------------------------------------------------------------------
# * Setup Right Column - Window_HorizontalSelect
# - Determines Position of Right Column
# - Allows for 1 pixel of additional padding for Math Rounding to 1 errors
#--------------------------------------------------------------------------
def setup_right_column
# Temporary Variables with Adjustments and Clamping for Range
lw, cm = @label_width - 32, [@column_max - 1 - @column_pad, 0].max
# X Position for Right Column (can be greater than window size to scroll)
@right_col = lw * cm + cm * 32 + self.x - 1
end
#--------------------------------------------------------------------------
# * Setup Help Text - Window_HorizontalSelect
# - Sets the Labels and corresponding Help Text for Window
#--------------------------------------------------------------------------
def setup_option_text(labels, help)
# Check for Invalid Size during Gameplay Testing
if $debug and labels and help and labels.size != help.size
# Display Error
print "Error: Array Sizes must match for Label and Help Arrays\n",
labels.inspect, "\n", help.inspect
# Prevent Crash
exit
end
# Setup Option Labels (Game, Video, Audio, Input, Stats)
@option_labels = setup_option_labels(labels)
# Setup Option Help Text (must be same size as @option_labels)
@option_help = setup_option_help(help)
end
#--------------------------------------------------------------------------
# * Setup Option Labels - Window_HorizontalSelect
# - Returns an Array of Text Labels for Input
# - Default Values
#--------------------------------------------------------------------------
def setup_option_labels(labels = nil)
# Return Argument Array if Argument exists
return labels if not labels.nil?
# Labels for Options (Default, change with @window.option_labels = [array])
return ["Label"]
end
#--------------------------------------------------------------------------
# * Setup Option Help - Window_HorizontalSelect
# - Text to be displayed in Help Window for each Option Label
#--------------------------------------------------------------------------
def setup_option_help(help = nil)
# Return Argument Array if Argument exists
return help if not help.nil?
# Array of Text to display in Help Window
return ["Label Help when Help Window is assigned"]
end
#--------------------------------------------------------------------------
# * Option Labels - Window_HorizontalSelect
# - Setter Method, @window_options.option_lables = array
# - Allows Text to be assigned outside this class
# labels : Array of Text - ["Graphics","Sound","Input"...]
#--------------------------------------------------------------------------
def option_labels=(labels)
# Check Data Type
return unless labels.is_a?(Array)
# Set Value
@option_labels = labels
# Redraw contents of window
refresh
end
#--------------------------------------------------------------------------
# * Option Help - Window_HorizontalSelect
# - Setter Method, @window_options.options_help = array
# - Allows Text to be assigned outside this class
# options_help : Array of Text - ["Adjust Gameplay Options", "Set..."]
#--------------------------------------------------------------------------
def option_help=(options_help)
# Check Data Type
return unless options_help.is_a?(Array)
# Set the Value
@option_help = options_help
# Redraw contents of window
refresh
end
#--------------------------------------------------------------------------
# * Set Cursor Position - Window_HorizontalSelect
# - Set to -1 to Disable
# index : new cursor position
#--------------------------------------------------------------------------
def index=(index)
# Set New Index, clamp to Option Labels Array Size
@index = [index, @option_labels.size - 1].min
# Refresh the Contents
refresh
# Update Cursor Rectangle Position
update_cursor_rect
# Update Help Text (update_help is defined by the subclasses)
if self.active and @help_window != nil
# Update Help Window when Active and valid
update_help
end
end
#--------------------------------------------------------------------------
# * Column Max - Window_HorizontalSelect
# - Setter Method, @window_options.column_max = int
# - Redraws contents with adjusted positions when needed
# - This is the number of Columns to Display although list can be larger
# new_max : New Max, Integer, Number of Columns to Display
#--------------------------------------------------------------------------
def column_max=(new_max)
# Remember last value of Column Max
last_column_max = @column_max
# Assign Value
@column_max = new_max
# Redraw Contents if value of Column Max was changed
refresh if @column_max != last_column_max
# Update Cursor Position
update_cursor_rect
end
#--------------------------------------------------------------------------
# * Column Pad - Window_HorizontalSelect
# - Setter Method
# - Set to change Column Padding
# - Values above 0 will cause Window to Scroll when this many columns
# from either edge of Window
# new_pad : New Number of Columns to Scroll from Edge
#--------------------------------------------------------------------------
def column_pad=(new_pad)
# Remember Last Value
last_column_pad = @column_pad
# Set New Value from Argument
@column_pad = new_pad
# Refresh if Value is Different
refresh if @column_pad != last_column_pad
# Update cursor rectangle
update_cursor_rect
end
#--------------------------------------------------------------------------
# * Set Help Window - Window_HorizontalSelect
# - Assigns an external Help Window to display Help Text on Selection
# help_window : Window_Help from $scene
#--------------------------------------------------------------------------
def help_window=(help_window)
# Prevent Invalid Object Type
return unless help_window.is_a?(Window_Help)
# Assign Help Window from $scene to this window
@help_window = help_window
# Update help text
if self.active and @help_window != nil
update_help
end
end
#--------------------------------------------------------------------------
# * Update Help - Window_HorizontalSelect
# - Updates the Text of the Help Window
#--------------------------------------------------------------------------
def update_help
# Check for valid Help Window
return unless self.active and @help_window != nil
# If Text is different than contents
if @help_window.text != @option_help[@index]
# Assign Text to Help Window if this Window has Active Cursor
@help_window.set_text(@index > -1 ? @option_help[@index] : "")
end
end
#--------------------------------------------------------------------------
# * Draw Option Item - Window_HorizontalSelect
# - Draws Text for Option Items
# column : Column Number
#--------------------------------------------------------------------------
def draw_option_item(column)
# Standard Font Color
self.contents.font.color = normal_color
# Determine X Position for Option Label
x = (@label_width - 32) * column + column * 32 + self.x
# Rect for Option Label
rect = Rect.new(x, 0, @label_width - 32, 32)
# Draw Option Label in Rect and use 1 to Center
self.contents.draw_text(rect, @option_labels[column], 1)
end
#--------------------------------------------------------------------------
# * Cursor Movable? - Window_HorizontalSelect
# - Evaluates if Cursor Rect should respond to Left Right Input
#--------------------------------------------------------------------------
def cursor_movable?
# Movable if Window has Focus and can be displayed
return true if self.active and @column_max > 0 and @index >= 0
end
#--------------------------------------------------------------------------
# * Animating? - Window_HorizontalSelect
# - Evaluates if the Window is Animating a Scroll
#--------------------------------------------------------------------------
def animating?
# Returns value of evaluating temporary Animation Counter
return @anime_duration > 0
end
#--------------------------------------------------------------------------
# * Start Animate Scroll - Window_HorizontalSelect
# - Starts Horizontal Scroll Animation
# target : self.ox number for Window Position
#--------------------------------------------------------------------------
def start_animate_scroll(target)
# If No Animation
if @anime_frames < 1
# Set the Window Target and Position to Value with no Animation
self.ox, @ox_target = target, target
# Prevent further processing
return
end
# Remember Scroll Target
@ox_target = target
# Set the Number of Frames of Animation Counter
@anime_duration = @anime_frames
end
#--------------------------------------------------------------------------
# * Make OX - Window_HorizontalSelect
# - Determines OX Position to display Cursor on Setup and other changes
#--------------------------------------------------------------------------
def make_ox
# Prevent Inactive Scrolling
return self.ox if @index < 0
# Shorthand Temporary Variables
i, cp, lw, sox, = @index, @column_pad, @label_width, self.ox
# Calculate New self.ox, Clamp to 0 and Content Width
ox = [self.contents.width - self.width + 32, [0, (i - cp) * lw].max].min
# Calculate New Cursor X
cx = i * lw - self.ox + self.x
# If Cursor will be visible at current position
if ox >= sox + @left_col and ox <= sox + @right_col and
cx >= @left_col and cx <= @right_col
# No Change to Scroll Position
return self.ox
end
# Return New Value without Animations
return ox
end
#--------------------------------------------------------------------------
# * Update Animation - Window_HorizontalSelect
# - Handles Scrolling Animations
#--------------------------------------------------------------------------
def update_animation
# If an Animated Scroll is Occuring
if animating?
# Calcuate New Position
self.ox = (self.ox * (@anime_duration - 1) + @ox_target) / @anime_duration
# Decrement Animation Counter
@anime_duration -= 1
# If End of Animation
if @anime_duration == 0
# Set value to target
self.ox = @ox_target
end
end
end
#--------------------------------------------------------------------------
# * Update Cursor Rectangle - Window_HorizontalSelect
# - Positions the Cursor Rectangle over Selected Option Text
# - Use @option_window.hide_cursor = true to Hide the Cursor without
# losing the current Index
#--------------------------------------------------------------------------
def update_cursor_rect
# If cursor position is less than 0 or Hide Cursor enabled
if @index < 0 or @hide_cursor
# Erase the Cursor if Hide Cursor is on
self.cursor_rect.empty
# No further Processing
return
end
# Calculate Cursor Coordinates and adjust for Window Scroll and Position
x = @index * @label_width - self.ox + self.x
# Update cursor rectangle relative to Window Position and Size
self.cursor_rect.set(x, 0, @label_width - 32, 32)
end
#--------------------------------------------------------------------------
# * Update Input - Window_HorizontalSelect
# - Handles Left and Right Input Processing for Index Change and Animates
# - Does not handle conditions for Enter or Cancel, use $scene
#--------------------------------------------------------------------------
def update_input
# If this window is selected in the Options Scene
if not animating? and cursor_movable?
# If the right directional button was pressed
if Input.repeat?(Input::RIGHT)
# If Index is not at End of Options List
if @index < @option_labels.size - 1
# If Cursor is on the Right
if self.cursor_rect.x >= @right_col and
@index < @option_labels.size - 1 - @column_pad
# Scroll Contents within the Option Window
start_animate_scroll(self.ox + @label_width)
end
# Play Cursor Sound
$game_system.se_play($data_system.cursor_se)
# Advance the Index, Clamp Index to Options
@index = [@index + 1, @option_labels.size - 1].min
end
end
# If the left directional button was pressed
if Input.repeat?(Input::LEFT)
# If Cursor is not at Start of Options List
if @index > 0
# If Cursor Rect is on the Left
if self.cursor_rect.x <= @left_col and @index > @column_pad
# Scroll Contents within the Option Window
start_animate_scroll(self.ox - @label_width)
end
# Play Cursor Sound
$game_system.se_play($data_system.cursor_se)
# Advance the Index, Clamp Index to 0
@index = [@index - 1, 0].max
end
end
end
end
#--------------------------------------------------------------------------
# * Update - Window_HorizontalSelect
# - This handles Input for Cursor Position and Index only
#--------------------------------------------------------------------------
def update
# Call Parent Method of Update for all Child Classes (for Cursor Blink)
super()
# Update Input Handling for Cursor Position
update_input
# Update Horizontal Scroll Animations
update_animation
# Update the Help Text description
update_help
# Update cursor position based on Index and OX Scroll
update_cursor_rect
end
end
class Window_Help < Window_Base
#--------------------------------------------------------------------------
# * Public Instance Variables - Window_Help
#--------------------------------------------------------------------------
attr_reader :text # Content Text
attr_reader :align # 0 left, 1 center, 2 right
end
#==============================================================================
# ** Scene_Options
#------------------------------------------------------------------------------
# This class performs Options Menu processing.
#==============================================================================
class Scene_Options
#--------------------------------------------------------------------------
# * Main Processing
#--------------------------------------------------------------------------
def main
# Throw in an Option that allows users to change Windowskins?
# Make Options Windows
create_windows
# Position the Help Window
@help_window.y = 64
# Assign Help Window to Options Window for setting Text
@options_window.help_window = @help_window
# Execute transition
Graphics.transition
# Main loop
loop do
# Update game screen
Graphics.update
# Update input information
Input.update
# Frame update
update
# Abort loop if screen is changed
if $scene != self
break
end
end
# Prepare for transition
Graphics.freeze
# Dispose of Options Windows
dispose_windows
end
#--------------------------------------------------------------------------
# * Create Windows - Scene_Options
#--------------------------------------------------------------------------
def create_windows
@gameplay_window = Window_Base.new(0, 128, 640, 352)
@graphics_window = Window_Base.new(0, 128, 640, 352)
@audio_window = Window_Base.new(0, 128, 640, 352)
@input_window = Window_Base.new(0, 128, 640, 352)
@statistics_window = Window_Base.new(0, 128, 640, 352)
# Make the Help Window
@help_window = Window_Help.new
# Text for Horizontal Options Menu as "L"
l = ["Game", "Video", "Audio", "Input", "Stats"]
# Game Help Text
h1 = "Configure Gameplay Options"
# Video Help Text
h2 = "Configure Video Options"
# Audio Help Text
h3 = "Configure Audio Options"
# Input Help Text
h4 = "Configure Input and Controller Options"
# Stats Help Text
h5 = "Display Gameplay Statistics"
# Array of Help Text for Options Window Setup as "H"
h = [h1, h2, h3, h4, h5]
# Make the Main Options Window at Top (Width, Option Labels)
@options_window = Window_HorizontalSelect.new(
# X, Y, W, H, Cursor Hide, Label, Help, Index, Columns, Pad, Anime
0, 0, 640, 64, false, l, h, 0, 3, 1)
end
#--------------------------------------------------------------------------
# * Dispose Windows - Scene_Options
#--------------------------------------------------------------------------
def dispose_windows
# Dispose of windows
@options_window.dispose
@help_window.dispose
@gameplay_window.dispose
@graphics_window.dispose
@audio_window.dispose
@input_window.dispose
@statistics_window.dispose
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
# Update Options Window
@options_window.update
if Input.trigger?(Input::SHIFT)
@options_window.column_max = (@options_window.column_max == 3) ? 5 : 3
end
if Input.trigger?(Input::C)
# Prevent Updating Help Window
@options_window.active = false
# Branch by Main Option Index
case @options_window.index
when 0 # Gameplay
when 1 # Graphics
when 2 # Audio
when 3 # Input
when 4 # Statistics
end
@help_window.set_text("Scene Set text")
return
end
# If B button was pressed
if Input.trigger?(Input::B)
# If Main Options Window is Active
if @options_window.active
# Play cancel SE
$game_system.se_play($data_system.cancel_se)
# Switch to menu screen and set Selection Index to Options Menu
$scene = Scene_Menu.new(5)
# End Processing
return
else
# Retore Active Status
@options_window.active = true
end
end
end
end
#==============================================================================
# ** Scene_Menu
#------------------------------------------------------------------------------
# This class performs menu screen processing.
#==============================================================================
class Scene_Menu
#--------------------------------------------------------------------------
# * Main Processing
#--------------------------------------------------------------------------
def main
# Make command window
s1 = $data_system.words.item
s2 = $data_system.words.skill
s3 = $data_system.words.equip
s4 = "Status"
s5 = "Save"
s6 = "Options"
s7 = "End Game"
@command_window = Window_Command.new(160, [s1, s2, s3, s4, s5, s6, s7])
# Setting the Height allows contents of menu items to be scrollable
@command_window.height = 224
# Set Index of Command Window
@command_window.index = @menu_index
# If number of party members is 0
if $game_party.actors.size == 0
# Disable items, skills, equipment, and status
@command_window.disable_item(0)
@command_window.disable_item(1)
@command_window.disable_item(2)
@command_window.disable_item(3)
end
# If save is forbidden
if $game_system.save_disabled
# Disable save
@command_window.disable_item(4)
end
# Make play time window
@playtime_window = Window_PlayTime.new
@playtime_window.x = 0
@playtime_window.y = 224
# Make steps window
@steps_window = Window_Steps.new
@steps_window.x = 0
@steps_window.y = 320
# Make gold window
@gold_window = Window_Gold.new
@gold_window.x = 0
@gold_window.y = 416
# Make status window
@status_window = Window_MenuStatus.new
@status_window.x = 160
@status_window.y = 0
# Execute transition
Graphics.transition(20)
# Main loop
loop do
# Update game screen
Graphics.update
# Update input information
Input.update
# Frame update
update
# Abort loop if screen is changed
if $scene != self
break
end
end
# Prepare for transition
Graphics.freeze
# Dispose of windows
@command_window.dispose
@playtime_window.dispose
@steps_window.dispose
@gold_window.dispose
@status_window.dispose
end
#--------------------------------------------------------------------------
# * Frame Update (when command window is active)
#--------------------------------------------------------------------------
def update_command
# If B button was pressed
if Input.trigger?(Input::B)
# Play cancel SE
$game_system.se_play($data_system.cancel_se)
# Switch to map screen
$scene = Scene_Map.new
return
end
# If C button was pressed
if Input.trigger?(Input::C)
# If command other than save or end game, and party members = 0
if $game_party.actors.size == 0 and @command_window.index < 4
# Play buzzer SE
$game_system.se_play($data_system.buzzer_se)
return
end
# Branch by command window cursor position
case @command_window.index
when 0 # item
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Switch to item screen
$scene = Scene_Item.new
when 1 # skill
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Make status window active
@command_window.active = false
@status_window.active = true
@status_window.index = 0
when 2 # equipment
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Make status window active
@command_window.active = false
@status_window.active = true
@status_window.index = 0
when 3 # status
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Make status window active
@command_window.active = false
@status_window.active = true
@status_window.index = 0
when 4 # save
# If saving is forbidden
if $game_system.save_disabled
# Play buzzer SE
$game_system.se_play($data_system.buzzer_se)
return
end
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Switch to save screen
$scene = Scene_Save.new
when 5 # Options
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Switch to save screen
$scene = Scene_Options.new
when 6 # End Game
# Play decision SE
$game_system.se_play($data_system.decision_se)
# Switch to end game screen
$scene = Scene_End.new
end
return
end
end
end