The old post with this script vanished into the ether sometime in the last two years, so here it is again.
Lockpicking Minigame Version: 1.0.0, for RMXP
By: Eilei
Introduction
The lockpicking minigame is a little script I slapped together a long time ago to teach myself Ruby. The game has a number of tumblers you need to get into place, and on the harder locks moving one tumbler can move another too. Successful completion of the minigame sets a switch of your choice to ON, so it's pretty easy to interact with from events.
Features
Screenshots
Minigame on "Average" difficulty:
Demo
Link Dead
Script
Instructions (using the Demo as a base)
Editing
Usage
See the two chests for the two ways to use this script; one method puts the lockpicking result in a specified event's self switches, the other puts it in a specified global switch.
FAQ
None yet...
Compatibility
SDK 2.3 compatible
Author's Notes
I don't know what I have to do to make this SDK 2.4 compatible, but I will probably do so sometime in the near future.
Feel free to make any comments or suggestions.
Terms and Conditions
This script is released under GPL 3. Please list my name in the credits if you use this!
* There is a non-zero probability that two games may actually be the same.
Lockpicking Minigame Version: 1.0.0, for RMXP
By: Eilei
Introduction
The lockpicking minigame is a little script I slapped together a long time ago to teach myself Ruby. The game has a number of tumblers you need to get into place, and on the harder locks moving one tumbler can move another too. Successful completion of the minigame sets a switch of your choice to ON, so it's pretty easy to interact with from events.
Features
- Varying difficulties for different levels of play
- Completely random boards, so no two games are ever the same*
- Can interact with either global switches or event self-switches
Screenshots
Minigame on "Average" difficulty:

Demo
Link Dead
Script
Code:
#==============================================================================
# ** Lockpick Minigame
#------------------------------------------------------------------------------
# Your Name : Eilei
# Version : 1.0.0
# Date : September 9, 2007
# SDK Version : Version 2.3, Part I
#==============================================================================
=begin Installation Instructions
0.) Get SDK if you don't have it; Part I is required for this script.
1.) Copy this script and paste it into your script list, just above Main.
Editing Instructions
1.) Change the main background by swapping out
Graphics/Pictures/lockpick_background.png
for whatever you want. Change the audio file at
Audio/BGM/lockpick_music.mp3
Change the color of the tumblers by messing with
Graphics/Pictures/lockpick_pins.png,
but I don't recommend changing the sizes of the pins. Finally, change the
minigame lock background colors by editing both
Graphics/Pictures/lockpick_cylinder.png
and
Graphics/Pictures/lockpick_pin_background.png
2.) This script isn't otherwise very customizeable at the moment. Feel free
to tinker with the number of tumblers per difficulty and such.
Usage
1.) See the two chests for the two ways to use this script; one method puts
the lockpicking result in a specified event's self switches, the other
puts it in a specified global switch.
Legal Notices
This script is Copyright © 2007 C. Schrupp.
This script is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This script is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
A copy of the GNU General Public License is in gpl.txt in the main
directory. If not, see <http://www.gnu.org/licenses/>.
=end
#--------------------------------------------------------------------------
# * Begin SDK Log
#--------------------------------------------------------------------------
SDK.log( 'Lockpicking Minigame', 'Eilei', '1.0', '2007-09-08')
#--------------------------------------------------------------------------
# * Begin Requirements Check
#--------------------------------------------------------------------------
SDK.check_requirements( 2.3, [1] )
#--------------------------------------------------------------------------
# * Begin SDK Enable Test
#--------------------------------------------------------------------------
if SDK.enabled?( 'Lockpicking Minigame' )
#----------------------------------------------------------------------------
# Begin Game_Temp Edit
#----------------------------------------------------------------------------
class Game_Temp
attr_accessor :lock_difficulty # difficulty for the next lock to be picked
end
#----------------------------------------------------------------------------
# End Game_Temp Edit
#----------------------------------------------------------------------------
#==============================================================================
# ** Scene_LockpickMinigame
#------------------------------------------------------------------------------
# Scene_LockpickMinigame is the scene to call when you want to run the
# lockpicking minigame
#
# NOTE: Scene_LockpickMinigame.set_result MUST be called before $scene is
# set, or the minigame will not work.
#==============================================================================
class Scene_LockpickMinigame < SDK::Scene_Base
#---------------------------------------------------------------------------+
# Scene Constants |
#---------------------------------------------------------------------------+
LOCK_VERY_EASY = 0
LOCK_EASY = 1
LOCK_AVERAGE = 2
LOCK_DIFFICULT = 3
LOCK_INSANE = 4
# The number of tumblers for each difficulty should be prime to maximize the
# probability that the puzzle will be solveable.
LOCK_TUMBLERS = {
LOCK_VERY_EASY => 2,
LOCK_EASY => 3,
LOCK_AVERAGE => 5,
LOCK_DIFFICULT => 7,
LOCK_INSANE => 11
}
LOCK_AUDIO_UNLOCK = RPG::AudioFile.new( 'lock_open' )
# Internal constants
CYLINDER_WIDTH = 288
#--------------------------------------------------------------------------
# * Main Processing : Variable Initialization
#--------------------------------------------------------------------------
def main_variable
# Check that the default value is ok
if not LOCK_TUMBLERS.keys.include?( $game_temp.lock_difficulty )
$game_temp.lock_difficulty = LOCK_VERY_EASY
end
# Initialize the tumbler pins
@pins = Array.new( LOCK_TUMBLERS[ $game_temp.lock_difficulty ] )
# Initialize the current lock modifier
# (guarantees @lock_number will be prime)
n = rand( 40 ) + 1
@lock_number = n**2 + n + 41
end
#--------------------------------------------------------------------------
# * Main Processing : Sprite Initialization
#--------------------------------------------------------------------------
def main_sprite
# Initialize viewports
@viewport_background = Viewport.new( 0, 0, 640, 480)
@viewport_background.z = -500
@viewport_lock = Viewport.new( ( 640 - CYLINDER_WIDTH ) / 2, 90,
CYLINDER_WIDTH, 300 )
@viewport_lock.z = -200
# display background image
@background_sprite = Sprite.new( @viewport_background )
@background_sprite.bitmap = RPG::Cache.picture( 'lockpick_background' )
# display lock cylinder
@cylinder_sprite = Sprite.new( @viewport_lock )
@cylinder_sprite.bitmap = RPG::Cache.picture( 'lockpick_cylinder' )
# display tumbler springs and pins
for i in [email=0...@pins.size]0...@pins.size[/email]
@pins[ i ] = Tumbler.new( @viewport_lock )
@pins[ i ].x = CYLINDER_WIDTH * ( i + 1 ) / ( @pins.size + 1 )
@pins[ i ].y = 0
end
# display lockpick
@lockpick_sprite = Lockpick.new
@lockpick_sprite.tumblers = @pins.size
end
#--------------------------------------------------------------------------
# * Main Processing : Window Initialization
#--------------------------------------------------------------------------
def main_window
@help_window = Window_Help.new
@help_window.set_text(
'Line up the tumbler pins with the cylinder to pick the lock.' )
@help_window.back_opacity = 160
end
#--------------------------------------------------------------------------
# * Main Processing : Audio Initialization
#--------------------------------------------------------------------------
def main_audio
$game_system.bgm_play( RPG::AudioFile.new( 'lockpick_music', 80 ))
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
# game cancelled
if Input.trigger?( Input::B )
$scene = Scene_Map.new
end
# Don't allow other input if animating
if @lockpick_sprite.move?
return
end
for i in [email=0...@pins.size]0...@pins.size[/email]
if @pins[ i ].move?
return
end
end
# move the lockpick left or right
if Input.trigger?( Input::RIGHT )
@lockpick_sprite.move_right
if not @lockpick_sprite.move?
$game_system.se_play( $data_system.buzzer_se )
end
end
if Input.trigger?( Input::LEFT )
@lockpick_sprite.move_left
if not @lockpick_sprite.move?
$game_system.se_play( $data_system.buzzer_se )
end
end
# knock a tumbler up - cascades
if Input.trigger?( Input::UP )
@pins[ @lockpick_sprite.position ].raise
if @pins[ @lockpick_sprite.position ].move?
$game_system.se_play( Tumbler::TUMBLER_AUDIO_UP )
@lockpick_sprite.tap_up
if @lockpick_sprite.position > 0 # first pin guaranteed no cascades
@pins[ ( @lock_number * @lockpick_sprite.position ) %
@pins.size ].raise
end
if $game_temp.lock_difficulty == LOCK_INSANE
@pins[ ( @lock_number + @lockpick_sprite.position ) %
@pins.size ].lower
end
else
$game_system.se_play($data_system.buzzer_se)
end
end
# knock a tumbler down - cascades
if Input.trigger?( Input::DOWN )
@pins[ @lockpick_sprite.position ].lower
if @pins[ @lockpick_sprite.position ].move?
$game_system.se_play( Tumbler::TUMBLER_AUDIO_DOWN )
@lockpick_sprite.tap_down
if @lockpick_sprite.position > 0 # first pin guaranteed no cascades
@pins[ ( @lock_number * @lockpick_sprite.position ) %
@pins.size ].lower
end
if $game_temp.lock_difficulty == LOCK_INSANE
@pins[ ( @lock_number + @lockpick_sprite.position ) %
@pins.size ].raise
end
else
$game_system.se_play( $data_system.buzzer_se )
end
end
# game finished, maybe
if Input.trigger?( Input::C )
unlockable = true
for i in [email=0...@pins.size]0...@pins.size[/email]
if not @pins[ i ].open?
unlockable = false
break
end
end
if unlockable
$game_system.se_play( LOCK_AUDIO_UNLOCK )
$scene = Scene_Map.new
# change the specified result switch
if @result_switch == 'X'
# not a self-switch
$game_switches[ @result_id ] = true
else
$game_self_switches[ [ $game_map.map_id, @result_id,
@result_switch ] ] = true
end
$game_map.need_refresh = true
else
$game_system.se_play( $data_system.buzzer_se )
end
end
end
#--------------------------------------------------------------------------
# * Main Processing : Ending
#--------------------------------------------------------------------------
def main_end
Audio.bgm_fade( 2000 )
end
#--------------------------------------------------------------------------
# * set_result specifies which game switch is to be changed to true on a
# successful lockpick.
# id = event id for a self-switch, or switch id for a global switch
# self_switch = 'A', etc. for a self-switch.
# LEAVE self_switch BLANK TO SPECIFY A GLOBAL SWITCH
#--------------------------------------------------------------------------
def set_result( id, self_switch = 'X' )
@result_id = id
@result_switch = self_switch
end
end # class Scene_LockpickMinigame
#==============================================================================
# ** Tumbler
#------------------------------------------------------------------------------
# Tumbler represents one of the lock's tumblers
#==============================================================================
class Tumbler < Sprite
#---------------------------------------------------------------------------+
# Tumbler Constants |
#---------------------------------------------------------------------------+
# Maximum vertical size (in potential openings) of a tumbler
TUMBLER_POSITIONS = 6
# Bitmap sources for the pictures
TUMBLER_PIN_BITMAP = RPG::Cache.picture( 'lockpick_pins' )
TUMBLER_SPRING_BITMAP = [
RPG::Cache.picture( 'lockpick_spring1' ),
RPG::Cache.picture( 'lockpick_spring2' ),
RPG::Cache.picture( 'lockpick_spring3' ),
RPG::Cache.picture( 'lockpick_spring4' ),
RPG::Cache.picture( 'lockpick_spring5' ),
RPG::Cache.picture( 'lockpick_spring6' )
]
TUMBLER_BACKGROUND_BITMAP = RPG::Cache.picture( 'lockpick_pin_background' )
# Source rectangles inside the tumbler pin bitmap
TUMBLER_DRIVER_TOP = Rect.new( 0, 0, 20, 2 )
TUMBLER_DRIVER_MIDDLE = Rect.new( 0, 2, 20, 27 )
TUMBLER_DRIVER_BOTTOM = Rect.new( 0, 29, 20, 3 )
TUMBLER_KEY_TOP = Rect.new( 20, 0, 20, 3 )
TUMBLER_KEY_MIDDLE = Rect.new( 20, 3, 20, 17 )
TUMBLER_KEY_BOTTOM = Rect.new( 20, 20, 20, 12 )
# Audio for ratcheting
TUMBLER_AUDIO_UP = RPG::AudioFile.new( 'tumbler', 100, 105 )
TUMBLER_AUDIO_DOWN = RPG::AudioFile.new( 'tumbler', 100, 95 )
# Rate at which the tumbler pins move up and down
TUMBLER_MOVE_SPEED = 2 # this should be a factor of 20 (ie, 1, 2, 4, 5 )
#---------------------------------------------------------------------------+
# Tumbler Methods |
#---------------------------------------------------------------------------+
def initialize( *arg )
super *arg
@opening = rand( TUMBLER_POSITIONS )
while @level.nil? or @level + @opening == TUMBLER_POSITIONS - 1
@level = rand( TUMBLER_POSITIONS )
end
self.bitmap = Bitmap.new( 22, 262 )
self.bitmap.blt( 0, 0, TUMBLER_BACKGROUND_BITMAP,
TUMBLER_BACKGROUND_BITMAP.rect )
@current = ( @level + 1 ) * 20 - TUMBLER_MOVE_SPEED
end
#--------------------------------------------------------------------------
# * raise moves the tumbler up a number of clicks
# distance = maximum distance raised
#--------------------------------------------------------------------------
def raise( distance = 1 )
@level -= distance
if @level >= TUMBLER_POSITIONS
@level = TUMBLER_POSITIONS - 1
elsif @level < 0
@level = 0
end
end
#--------------------------------------------------------------------------
# * lower moves the tumbler down a number of clicks
# distance = maximum distance lowered
#--------------------------------------------------------------------------
def lower( distance = 1 )
@level += distance
if @level >= TUMBLER_POSITIONS
@level = TUMBLER_POSITIONS - 1
elsif @level < 0
@level = 0
end
end
#--------------------------------------------------------------------------
# * open? determines if the current level is the same as the opening
# between the driver and key pins
#--------------------------------------------------------------------------
def open?
return @level + @opening == TUMBLER_POSITIONS - 1
end
#--------------------------------------------------------------------------
# * move? determines if the pin is currently moving
#--------------------------------------------------------------------------
def move?
return @current != ( @level + 1 ) * 20
end
#--------------------------------------------------------------------------
# * update updates the current display of the tumbler, ratcheting it up
# or down depending on its current position vs. desired
#--------------------------------------------------------------------------
def update
super
# See if we need to update position
if not move?
return
elsif @current - ( @level + 1 ) * 20 > 0
@current -= TUMBLER_MOVE_SPEED # move up
else
@current += TUMBLER_MOVE_SPEED # move down
end
# Fill in the background
self.bitmap.fill_rect( Rect.new( 1, 1, 20, 260 ),
Color.new( 255, 255, 255 ) )
# Draw the spring
spring_level = ( ( @current + 10 ) / 20 ) - 1
self.bitmap.stretch_blt( Rect.new( 1, 1, 20, @current + 1 ),
TUMBLER_SPRING_BITMAP[ spring_level ],
TUMBLER_SPRING_BITMAP[ spring_level ].rect )
# Draw the driver pin
self.bitmap.blt( 1, @current + 1, TUMBLER_PIN_BITMAP,
TUMBLER_DRIVER_TOP )
self.bitmap.stretch_blt( Rect.new( 1, @current + 3, 20,
( @opening + 1 ) * 20 - 5 ), TUMBLER_PIN_BITMAP,
TUMBLER_DRIVER_MIDDLE )
self.bitmap.blt( 1, ( @opening + 1 ) * 20 + @current - 2,
TUMBLER_PIN_BITMAP, TUMBLER_DRIVER_BOTTOM )
# Draw the key pin
self.bitmap.blt( 1, ( @opening + 1 ) * 20 + @current + 1,
TUMBLER_PIN_BITMAP, TUMBLER_KEY_TOP )
self.bitmap.stretch_blt( Rect.new( 1, ( @opening + 1 ) * 20 + @current + 4,
20, ( TUMBLER_POSITIONS - @opening ) * 20 - 15 ), TUMBLER_PIN_BITMAP,
TUMBLER_KEY_MIDDLE )
self.bitmap.blt( 1, ( TUMBLER_POSITIONS + 1 ) * 20 + @current - 11,
TUMBLER_PIN_BITMAP, TUMBLER_KEY_BOTTOM )
end
def set_result_switch( event_id, switch_id )
end
end # class Tumbler
#==============================================================================
# ** Lockpick
#------------------------------------------------------------------------------
# Lockpick represents the game's lockpick
#==============================================================================
class Lockpick < Sprite
attr_accessor :tumblers
attr_accessor :position
#---------------------------------------------------------------------------+
# Lockpick Constants |
#---------------------------------------------------------------------------+
LOCKPICK_X_OFFSET = ( 640 - Scene_LockpickMinigame::CYLINDER_WIDTH ) / 2 - 482
LOCKPICK_MOVEMENT_SPEED = 8 # This can be any integer; higher is faster
#--------------------------------------------------------------------------
# * initialize sets the starting lockpick x coordinate
#--------------------------------------------------------------------------
def initialize( *arg )
super *arg
self.bitmap = RPG::Cache.picture( 'lockpick_lockpick' )
self.x = LOCKPICK_X_OFFSET
self.y = 355
@position = 0
@current = 0
@tumblers = 1
@tap_count = 0
end
#--------------------------------------------------------------------------
# * move_right moves the lockpick right one tumbler
#--------------------------------------------------------------------------
def move_right
if @tap_count != 0
return
end
if @position >= @tumblers - 1
@position = @tumblers - 1
else
@position += 1
end
end
#--------------------------------------------------------------------------
# * move_left moves the lockpick left one tumbler
#--------------------------------------------------------------------------
def move_left
if @tap_count != 0
return
end
if @position <= 0
@position = 0
else
@position -= 1
end
end
#--------------------------------------------------------------------------
# * tap_up moves the lockpick in an upwards tapping motion
#--------------------------------------------------------------------------
def tap_up
@tap_count = 8
end
#--------------------------------------------------------------------------
# * tap_down moves the lockpick in a downwards tapping motion
#--------------------------------------------------------------------------
def tap_down
@tap_count = -6
end
#--------------------------------------------------------------------------
# * move? determines if the lockpick needs to move
#--------------------------------------------------------------------------
def move?
current_x = Scene_LockpickMinigame::CYLINDER_WIDTH * ( @position + 1 ) /
( @tumblers + 1 )
return ( @current != current_x or @tap_count != 0 )
end
#--------------------------------------------------------------------------
# * initialize sets the starting lockpick x coordinate
#--------------------------------------------------------------------------
def update
super
# See if we're animated up or down
if @tap_count != 0 # down
if @tap_count < 0
self.x = @current + LOCKPICK_X_OFFSET
self.y = 354 - @tap_count
@tap_count += 1
else # up
self.x = @current + LOCKPICK_X_OFFSET - @tap_count
self.y = 356 - @tap_count
@tap_count -= 1
end
return
end
# See if we need to update position
if not move?
return
elsif Scene_LockpickMinigame::CYLINDER_WIDTH * ( @position + 1 ) /
( @tumblers + 1 ) > @current
@current += LOCKPICK_MOVEMENT_SPEED
else
@current -= LOCKPICK_MOVEMENT_SPEED
end
# if we're close, just set it to the right value
if ( @current - Scene_LockpickMinigame::CYLINDER_WIDTH * ( position + 1 ) /
( @tumblers + 1 ) ).abs <=
LOCKPICK_MOVEMENT_SPEED / 2
@current = Scene_LockpickMinigame::CYLINDER_WIDTH * ( @position + 1 ) /
( @tumblers + 1 )
end
self.x = @current + LOCKPICK_X_OFFSET
self.y = 355
end
end # class Lockpick
end # if SDK.enabled?
Instructions (using the Demo as a base)
Editing
- Change the main background by swapping out Graphics/Pictures/lockpick_background.png for whatever you want.
- Change the audio file at Audio/BGM/lockpick_music.mp3
- Change the color of the tumblers by messing withGraphics/Pictures/lockpick_pins.png, but I don't recommend changing the sizes of the pins.
- Finally, change the minigame lock background colors by editing both Graphics/Pictures/lockpick_cylinder.png and Graphics/Pictures/lockpick_pin_background.png
- This script isn't otherwise very customizeable at the moment. Feel free to tinker with the number of tumblers per difficulty and such.
Usage
See the two chests for the two ways to use this script; one method puts the lockpicking result in a specified event's self switches, the other puts it in a specified global switch.
FAQ
None yet...
Compatibility
SDK 2.3 compatible
Author's Notes
I don't know what I have to do to make this SDK 2.4 compatible, but I will probably do so sometime in the near future.
Feel free to make any comments or suggestions.
Terms and Conditions
This script is released under GPL 3. Please list my name in the credits if you use this!
* There is a non-zero probability that two games may actually be the same.