#============================================================================== # ** Shift Puzzles #------------------------------------------------------------------------------ # SephirothSpawn # Version 2 # 2006-07-28 #------------------------------------------------------------------------------ # * Description: # # ~ MiniGame Where you shift tiles around in order to make the picture # complete. You can add a shift function for puzzles, tile borders, tile # numbers, etc. #------------------------------------------------------------------------------ # * Installation: # # ~ Place the Script below the RMXP SDK and above main # ~ Customize the Shift_Puzzles module for puzzle data (Customization Below) #------------------------------------------------------------------------------ # * Instructions: # # ~ To Open a Puzzle, use the syntax: # $scene.open_shiftpuzzle(puzzle_id) # ~ Replace Puzzle ID with the ID of the Puzzle from the Shift Puzzle Module # # ~ To Reset a Puzzle, use the syntax: # $game_shiftpuzzles.reset_puzzle_data(puzzle_id) # # ~ To Test for solved puzzle, use the syntax: # $game_shiftpuzzles[puzzle_id].solved? #------------------------------------------------------------------------------ # * Customization: # # # ~ Setting Defaults # All Non-Specified Parameters for special puzzles will use the defaults # # Width = width of puzzle # Height = height of puzzle # Image = puzzle image file name # Move_Limit = sets move limit (Nil for no limit) # Rotatable = sets if the tiles are rotatable # Show_Numbers = use to show the numbers on the tile # Show_Borders = use to show borders around tile # Number_Color = color of numbers # Border_Color = color of border # Rotation_Counts_As_Move = count rotating tile as a move # Draw_Numbers_After_Rotation = draws numbers of tile after rotation # Puzzle_Solved_SE = load_data("Data/System.rxdata").decision_se # Puzzle_Unsolved_SE = load_data("Data/System.rxdata").buzzer_se # # ~ Setting Custom Parameters # Add a key in the Puzzle_List constant, with a hash of parameters # - For a list of the parameters, see puzzle list constant heading #============================================================================== #------------------------------------------------------------------------------ # * SDK Log Script #------------------------------------------------------------------------------ SDK.log('Shift Puzzles', 'SephirothSpawn', 2, '2006-07-28') #------------------------------------------------------------------------------ # * Begin SDK Enable Test #------------------------------------------------------------------------------ if SDK.state('Shift Puzzles') == true #============================================================================== # ** Shift Puzzles #============================================================================== module Shift_Puzzles #-------------------------------------------------------------------------- # * Default Options #-------------------------------------------------------------------------- Width = 4 Height = 4 Image = 'Shift Puzzle 1' Move_Limit = nil Rotatable = true Show_Numbers = true Show_Borders = true Number_Color = Color.new(255, 255, 255) Border_Color = Color.new(255, 255, 255) Rotation_Counts_As_Move = true Draw_Numbers_After_Rotation = false Puzzle_Solved_SE = load_data("Data/System.rxdata").decision_se Puzzle_Unsolved_SE = load_data("Data/System.rxdata").buzzer_se #-------------------------------------------------------------------------- # * Puzzle List # ~ id => {parameters} # * Parameters # 'width' => puzzle width in tiles # 'height' => puzzle width in tiles # 'image' => image of puzzle # 'move_limit' => nil for no limit or # for limit # 'rotatable' => true or false # 'show_numbers' => true or false # 'show_borders' => true or false # 'number_color' => Color.new(r, g, b, a) # 'border_color' => Color.new(r, g, b, a) # 'rcam' => true or false to make rotation count as a move # 'dnar' => true or false to make the numbers drawn after tile rotated # # * Any Non-Defined Puzzle ID's will be a puzzle with all defaults # * Any Non-Defined Parameters will take defaults #-------------------------------------------------------------------------- Custom_Puzzle_List = { 2 => {'image' => 'Shift Puzzle 2', 'width' => 5, 'height' => 5, 'move_limit' => 350}, 3 => {'image' => 'Shift Puzzle 3', 'show_numbers' => false}, 4 => {'image' => 'Shift Puzzle 4', 'width' => 7, 'height' => 10, 'rotatable' => false} } end #============================================================================== # ** Game_ShiftPuzzles #============================================================================== class Game_ShiftPuzzles #-------------------------------------------------------------------------- # * Object Initialization #-------------------------------------------------------------------------- def initialize # Starts Data @data = [] end #-------------------------------------------------------------------------- # * Get Puzzle Data #-------------------------------------------------------------------------- def [](puzzle_id) # Creates Unstarted Data if @data[puzzle_id].nil? @data[puzzle_id] = Game_ShiftPuzzle.new(puzzle_id) end return @data[puzzle_id] end #-------------------------------------------------------------------------- # * Reset Puzzle Data #-------------------------------------------------------------------------- def reset_puzzle_data(puzzle_id) @data[puzzle_id] = Game_ShiftPuzzle.new(puzzle_id) end end #============================================================================== # ** Bitmap #============================================================================== class Bitmap #-------------------------------------------------------------------------- # * Rotate Square 90 Degree Increments #-------------------------------------------------------------------------- def sqr_rotate_90(degrees = 90) # If Degrees is Greater than 360 degrees -= 360 until degrees < 360 # If Degrees is Less than 0 degress += 360 until degrees >= 0 # Duplicates Self dummy = self.dup # Passes Through all Pixels on Dummy Bitmap for i in 0...self.height for j in 0...self.width # Configures destination Pixel Coordinates case degrees when 90 ; x, y = width - i - 1, j when 180 ; x, y = width - j - 1, height - i - 1 when 270 ; x, y = i, height - j - 1 else ; return end # Reset Pixel self.set_pixel(x, y, dummy.get_pixel(j, i)) end end end end #============================================================================== # ** Game_ShiftPuzzle #============================================================================== class Game_ShiftPuzzle #-------------------------------------------------------------------------- # * Include Shift Puzzle Module #-------------------------------------------------------------------------- include Shift_Puzzles #-------------------------------------------------------------------------- # * Public Instance Variables #-------------------------------------------------------------------------- attr_reader :width attr_reader :height attr_reader :image attr_reader :move_limit attr_reader :rotatable attr_reader :cursor_x attr_reader :cursor_y attr_reader :moves attr_reader :tile_width attr_reader :tile_height #-------------------------------------------------------------------------- # * Object Initialization #-------------------------------------------------------------------------- def initialize(puzzle_id) # Gets Parameters From Puzzle List parameters = Custom_Puzzle_List.has_key?(puzzle_id) ? Custom_Puzzle_List[puzzle_id] : {} # Sets Defaults parameters['width'] = Width unless parameters.has_key?('width') parameters['height'] = Height unless parameters.has_key?('height') parameters['image'] = Image unless parameters.has_key?('image') parameters['move_limit'] = Move_Limit unless parameters.has_key?('move_limit') parameters['rotatable'] = Rotatable unless parameters.has_key?('rotatable') parameters['show_numbers'] = Show_Numbers unless parameters.has_key?('show_numbers') parameters['show_borders'] = Show_Borders unless parameters.has_key?('show_borders') parameters['number_color'] = Number_Color unless parameters.has_key?('number_color') parameters['border_color'] = Border_Color unless parameters.has_key?('border_color') parameters['rcam'] = Rotation_Counts_As_Move unless parameters.has_key?('rcam') parameters['dnar'] = Draw_Numbers_After_Rotation unless parameters.has_key?('dnar') # Sets Puzzle Parameters @width = parameters['width'] @height = parameters['height'] @image = RPG::Cache.picture("Shift Puzzles/#{parameters['image']}") @move_limit = parameters['move_limit'] @rotatable = parameters['rotatable'] @show_numbers = parameters['show_numbers'] @show_borders = parameters['show_borders'] @number_color = parameters['number_color'] @border_color = parameters['border_color'] @rcam = parameters['rcam'] @dnar = parameters['dnar'] # Gets Tile Dimensions @tile_width = @image.width / @width @tile_height = @image.height / @height # Sets Up Data Table @data = Table.new(@width, @height) @rotations = Table.new(@width, @height) setup_table # Starts Move Counter @moves = 0 end #-------------------------------------------------------------------------- # * Setup Table #-------------------------------------------------------------------------- def setup_table range = (0...(@width * @height)).to_a for x in 0...@width for y in 0...@height @data[x, y] = range[index = rand(range.size)] range.delete_at(index) if @data[x, y] == (@width * @height) - 1 @cursor_x = x @cursor_y = y else @rotations[x, y] = @rotatable ? rand(4) : 0 end end end end #-------------------------------------------------------------------------- # * Rotate Tile Left #-------------------------------------------------------------------------- def rotate_tile_left(x, y) # Play cursor SE $game_system.se_play($data_system.cursor_se) # Decrease Rotation Angel @rotations[x, y] = @rotations[x, y] == 0 ? 3 : @rotations[x, y] - 1 # Move Counter @moves += 1 if @rcam end #-------------------------------------------------------------------------- # * Rotate Tile Right #-------------------------------------------------------------------------- def rotate_tile_right(x, y) # Play cursor SE $game_system.se_play($data_system.cursor_se) # Decrease Rotation Angel @rotations[x, y] = @rotations[x, y] == 3 ? 0 : @rotations[x, y] + 1 # Move Counter @moves += 1 if @rcam end #-------------------------------------------------------------------------- # * Move #-------------------------------------------------------------------------- def move(x_, y_) # Play cursor SE $game_system.se_play($data_system.cursor_se) # Switches Data @data[@cursor_x, @cursor_y], @data[@cursor_x + x_, @cursor_y + y_] = @data[@cursor_x + x_, @cursor_y + y_], @data[@cursor_x, @cursor_y] @rotations[@cursor_x, @cursor_y], @rotations[@cursor_x + x_, @cursor_y + y_] = @rotations[@cursor_x + x_, @cursor_y + y_], @rotations[@cursor_x, @cursor_y] # Adds to Cursor @cursor_x += x_ @cursor_y += y_ # Adds to Move Counter @moves += 1 end #-------------------------------------------------------------------------- # * Move Right #-------------------------------------------------------------------------- def move_right # If Far Right Tile if @cursor_x == @width - 1 # Play buzzer SE $game_system.se_play($data_system.buzzer_se) return end # Move Tile move(1, 0) end #-------------------------------------------------------------------------- # * Move Left #-------------------------------------------------------------------------- def move_left # If Far Left Tile if @cursor_x == 0 # Play buzzer SE $game_system.se_play($data_system.buzzer_se) return end # Move Tile move(-1, 0) end #-------------------------------------------------------------------------- # * Move Up #-------------------------------------------------------------------------- def move_up # If Upper Tile if @cursor_y == 0 # Play buzzer SE $game_system.se_play($data_system.buzzer_se) return end # Move Tile move(0, -1) end #-------------------------------------------------------------------------- # * Move Down #-------------------------------------------------------------------------- def move_down # If Lower Tile if @cursor_y == @height - 1 # Play buzzer SE $game_system.se_play($data_system.buzzer_se) return end # Move Tile move(0, 1) end #-------------------------------------------------------------------------- # * Tile Image #-------------------------------------------------------------------------- def tile_image(x_, y_) # Gets Data Tile tile_n = @data[x_, y_] # Reconfigure X and Y x = tile_n % @width y = tile_n / @height # Creates Blank Bitmap bitmap = Bitmap.new(@tile_width, @tile_height) # Transfers Section of Bitmap onto Blank Bitmap bitmap.blt(0, 0, @image, Rect.new(x * @tile_width, y * @tile_height, @tile_width, @tile_height)) # Show Tile Numbers if @show_numbers unless @dnar bitmap.font.color = @number_color bitmap.draw_text(0, 0, @tile_width, @tile_height, (tile_n + 1).to_s, 1) end end # If Rotatable Puzzle if @rotatable # Rotates Bitmap bitmap.sqr_rotate_90(@rotations[x_, y_] * 90) end # Show Tile Numbers if @show_numbers if @dnar bitmap.font.color = @number_color bitmap.draw_text(0, 0, @tile_width, @tile_height, (tile_n + 1).to_s, 1) end end # Show Tile Border if @show_borders bitmap.fill_rect(0, 0, @tile_width, 1, @border_color) bitmap.fill_rect(0, @tile_height - 1, @tile_width, 1, @border_color) bitmap.fill_rect(0, 0, 1, @tile_height, @border_color) bitmap.fill_rect(@tile_width - 1, 0, 1, @tile_height, @border_color) end # Returns Bitmap return bitmap end #-------------------------------------------------------------------------- # * Can Move #-------------------------------------------------------------------------- def can_move? # If Move Restriction unless @move_limit.nil? # If Taken Max Moves return false if @moves == @move_limit end return true end #-------------------------------------------------------------------------- # * Can Move #-------------------------------------------------------------------------- def can_rotate? # If Move Restriction unless @move_limit.nil? # If Rotation counts as a move if @rcam # If Taken Max Moves return false if @moves == @move_limit end end return true end #-------------------------------------------------------------------------- # * Solved Test #-------------------------------------------------------------------------- def solved? for i in 0...@width for j in 0...@height unless @rotations[i, j] == 0 return false end unless @data[i, j] == j * height + i return false end end end return true end end #============================================================================== # ** Window_ShiftPuzzle #============================================================================== class Window_ShiftPuzzle < Window_Base #-------------------------------------------------------------------------- # * Public Instance Variables #-------------------------------------------------------------------------- attr_reader :puzzle #-------------------------------------------------------------------------- # * Object Initialization #-------------------------------------------------------------------------- def initialize(puzzle_id = 1) puzzle = $game_shiftpuzzles[puzzle_id] super(0, 0, puzzle.image.width + 32, puzzle.image.height + 80) self.contents = Bitmap.new(width - 32, height - 32) @puzzle = puzzle @active = true # Sets Up Coordinates self.x = 320 - self.width / 2 self.y = 240 - self.height / 2 # Sets Up Image refresh end #-------------------------------------------------------------------------- # * Refresh #-------------------------------------------------------------------------- def refresh self.contents.clear # Draws Every Tile for x in 0...@puzzle.width for y in 0...@puzzle.height self.contents.blt(x * @puzzle.tile_width, y * @puzzle.tile_height, @puzzle.tile_image(x, y), Rect.new(0, 0, @puzzle.tile_width, @puzzle.tile_height)) end end # Shows Score refresh_score end #-------------------------------------------------------------------------- # * Refresh Score #-------------------------------------------------------------------------- def refresh_score # Clears Old Area self.contents.fill_rect(0, @puzzle.image.height, contents.width, 48, Color.new(0, 0, 0, 0)) # If Move Restriction unless @puzzle.move_limit.nil? unless @puzzle.can_move? self.contents.font.color = crisis_color self.contents.draw_text(4, y + 24, contents.width, 24, 'Cannot Move', 1) return end end # Draws Status & Moves Words self.contents.font.color = system_color self.contents.draw_text(0, y = @puzzle.image.height, contents.width, 24, @puzzle.solved? ? 'You Win' : 'Keep Trying...', 1) # Draws Moves Taken self.contents.draw_text(4, y + 24, contents.width, 24, 'Moves:') self.contents.font.color = normal_color self.contents.draw_text(- 4, y + 24, contents.width, 24, @puzzle.moves.to_s, 2) end #-------------------------------------------------------------------------- # * Refresh Tile #-------------------------------------------------------------------------- def refresh_tile(x, y) self.contents.blt(x * @puzzle.tile_width, y * @puzzle.tile_height, @puzzle.tile_image(x, y), Rect.new(0, 0, @puzzle.tile_width, @puzzle.tile_height)) end #-------------------------------------------------------------------------- # * Frame Update #-------------------------------------------------------------------------- def update super # Refresh Score refresh_score # If Active if @active # Stop If Cannot Make any more moves return unless @puzzle.can_move? # Gets Cursor X & Y x, y = @puzzle.cursor_x, @puzzle.cursor_y # If Puzzle Rotatable if @puzzle.rotatable # If L or R is Pressed if Input.press?(Input::L) || Input.press?(Input::R) # Flip Left Tile if Input.trigger?(Input::LEFT) return unless x > 0 if Input.press?(Input::L) @puzzle.rotate_tile_left(x - 1, y) refresh_tile(x - 1, y) elsif Input.press?(Input::R) @puzzle.rotate_tile_right(x - 1, y) refresh_tile(x - 1, y) end end # Flip Right Tile if Input.trigger?(Input::RIGHT) return unless x < @puzzle.width - 1 if Input.press?(Input::L) @puzzle.rotate_tile_left(x + 1, y) refresh_tile(x + 1, y) elsif Input.press?(Input::R) @puzzle.rotate_tile_right(x + 1, y) refresh_tile(x + 1, y) end end # Flip Upper Tile if Input.trigger?(Input::UP) return unless y > 0 if Input.press?(Input::L) @puzzle.rotate_tile_left(x, y - 1) refresh_tile(x, y - 1) elsif Input.press?(Input::R) @puzzle.rotate_tile_right(x, y - 1) refresh_tile(x, y - 1) end end # Flip Lower Tile if Input.trigger?(Input::DOWN) return unless y < @puzzle.height - 1 if Input.press?(Input::L) @puzzle.rotate_tile_left(x, y + 1) refresh_tile(x, y + 1) elsif Input.press?(Input::R) @puzzle.rotate_tile_right(x, y + 1) refresh_tile(x, y + 1) end end return end end # If Right is Pressed if Input.trigger?(Input::RIGHT) @puzzle.move_right return unless x < @puzzle.width - 1 refresh_tile(x, y) refresh_tile(x + 1, y) # If Left is Pressed elsif Input.trigger?(Input::LEFT) @puzzle.move_left return unless x > 0 refresh_tile(x, y) refresh_tile(x - 1, y) # If Up is Pressed elsif Input.trigger?(Input::UP) @puzzle.move_up return unless y > 0 refresh_tile(x, y) refresh_tile(x, y - 1) # If Down is Pressed elsif Input.trigger?(Input::DOWN) @puzzle.move_down return unless y < @puzzle.width - 1 refresh_tile(x, y) refresh_tile(x, y + 1) end end end end #============================================================================== # ** Scene_Map #============================================================================== class Scene_Map #-------------------------------------------------------------------------- # * Alias Listings #-------------------------------------------------------------------------- alias seph_shiftpuzzles_scnmap_update update #-------------------------------------------------------------------------- # * Frame Update #-------------------------------------------------------------------------- def update # If Shift Puzzle Active unless @seph_shiftpuzzle_window.nil? update_seph_shiftpuzzle return end # Original Update seph_shiftpuzzles_scnmap_update end #-------------------------------------------------------------------------- # * Frame Update : Seph Shift Puzzle #-------------------------------------------------------------------------- def update_seph_shiftpuzzle # Update Shift Puzzle Window @seph_shiftpuzzle_window.update # Update Map and Spriteset $game_map.update $game_system.map_interpreter.update $game_system.update $game_screen.update @spriteset.update @message_window.update # If C Button is Pressed if Input.trigger?(Input::C) # If Puzzle Solved if @seph_shiftpuzzle_window.puzzle.solved? # Play Solved SE $game_system.se_play(Game_ShiftPuzzle::Puzzle_Solved_SE) else # Play Unsolved SE $game_system.se_play(Game_ShiftPuzzle::Puzzle_Unsolved_SE) end # Dispose Window @seph_shiftpuzzle_window.dispose @seph_shiftpuzzle_window = nil end end #-------------------------------------------------------------------------- # * Open Shift Puzzle #-------------------------------------------------------------------------- def open_shiftpuzzle(puzzle_id = 1) # Creates Shift Puzzle Window @seph_shiftpuzzle_window = Window_ShiftPuzzle.new(puzzle_id) end end #============================================================================== # ** Scene_Title #============================================================================== class Scene_Title #-------------------------------------------------------------------------- # * Alias Listings #-------------------------------------------------------------------------- alias seph_shiftpuzzles_scnttl_cng command_new_game #-------------------------------------------------------------------------- # * Command : New Game #-------------------------------------------------------------------------- def command_new_game # Original Command New Game seph_shiftpuzzles_scnttl_cng # Creates Shift Puzzle Game Data $game_shiftpuzzles = Game_ShiftPuzzles.new end end #============================================================================== # ** Scene_Save #============================================================================== class Scene_Save #-------------------------------------------------------------------------- # * Alias Listings #-------------------------------------------------------------------------- alias seph_shiftpuzzles_scnsave_wd write_data #-------------------------------------------------------------------------- # * Command : New Game #-------------------------------------------------------------------------- def write_data(file) # Original Write Data seph_shiftpuzzles_scnsave_wd(file) # Saves Shift Puzzle Data Marshal.dump($game_shiftpuzzles, file) end end #============================================================================== # ** Scene_Load #============================================================================== class Scene_Load #-------------------------------------------------------------------------- # * Alias Listings #-------------------------------------------------------------------------- alias seph_shiftpuzzles_scnload_rd read_data #-------------------------------------------------------------------------- # * Command : New Game #-------------------------------------------------------------------------- def read_data(file) # Original Write Data seph_shiftpuzzles_scnload_rd(file) # Saves Shift Puzzle Data $game_shiftpuzzles = Marshal.load(file) end end #------------------------------------------------------------------------------ # * End SDK Enable Test #------------------------------------------------------------------------------ end