Game Progress Password System
Version: 1.0.2
Introduction
This is a script that generates game passwords based on what type of data you give it.
Features
Demo
A small demo which includes a small password input screen.
Script
Instructions
Install the script above main and below the SDK, if using. Now you have to create the password data. The following is just an example:
Methods are:
FAQ
<no questions>
Compatibility
Compatible with the SDK, as no methods were modified.
Credits and Thanks
Thanks to crc.rb, which I got the Cyclic Redundancy Check algorithm from.
Author's Notes
This script does NOT include an input window to input passwords. You as the scripter will have to do that, or request one(but not here!) If one has any questions on how to operate this, please ask!
Version: 1.0.2
Introduction
This is a script that generates game passwords based on what type of data you give it.
Features
- Easy to use
- Quick
Demo
A small demo which includes a small password input screen.
Script
Code:
#==============================================================================
# ** Game Progress Password System
#------------------------------------------------------------------------------
# * Scripted by: Yeyinde
# * Version 1.0.2
# * Date: 09/28/07
#------------------------------------------------------------------------------
# This is the core for a password saved game. It provides no method of input,
# so that is left up to you as the scripter. This system provides the base
# password tools that you can use to make your own old-school NESesque game.
#
# HOW TO USE:
# 1) Initialize a new instance of Password
# 2) Add switches, self_switches, variables, location, and time to the
# allocation
# 3) Compile the password
# 4) Read the password to restore game data
#------------------------------------------------------------------------------
#==============================================================================
# ** Password
#------------------------------------------------------------------------------
# Holds the data structure that is passwords
#==============================================================================
class Password
# Decryption hash. Change only the characters!
DECRYPT = {
'0' => 0 , '1' => 1 , '2' => 2 , '3' => 3 , '4' => 4 ,
'5' => 5 , '6' => 6 , '7' => 7 , '8' => 8 , '9' => 9 ,
'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14,
'F' => 15, 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19,
'K' => 20, 'L' => 21, 'M' => 22, 'N' => 23, 'O' => 24,
'P' => 25, 'Q' => 26, 'R' => 27, 'S' => 28, 'T' => 29,
'U' => 30, 'V' => 31, 'W' => 32, 'X' => 33, 'Y' => 34,
'Z' => 35, 'a' => 36, 'b' => 37, 'c' => 38, 'd' => 39,
'e' => 40, 'f' => 41, 'g' => 42, 'h' => 43, 'i' => 44,
'j' => 45, 'k' => 46, 'l' => 47, 'm' => 48, 'n' => 49,
'o' => 50, 'p' => 51, 'q' => 52, 'r' => 53, 's' => 54,
't' => 55, 'u' => 56, 'v' => 57, 'w' => 58, 'x' => 59,
'y' => 60, 'z' => 61, '?' => 62, '-' => 63
}
# The encrypt hash. It is the opposite of the decrypt hash.
ENCRYPT = DECRYPT.dup.invert
#--------------------------------------------------------------------------
# * Object initialization
# bytes : how many bytes the password will be
# shift_length : how many bytes to use for encryption
# checksum_length : how many bytes to use for verification
#--------------------------------------------------------------------------
def initialize(bytes, shift_length, checksum_length)
raise('Number of bits must be divisible by 6.') if bytes * 8 % 6 != 0
raise('Not enough bytes for shift and checksum') if shift_length +
checksum_length >= bytes
@total_bytes = bytes
@shift_length = shift_length
@checksum_length = checksum_length
@bytes = Array.new(bytes - shift_length - checksum_length)
@allocation = []
@index = 0
end
#--------------------------------------------------------------------------
# * Return password
#--------------------------------------------------------------------------
def password
return @password || '0' * (@total_bytes * 8 / 6)
end
#--------------------------------------------------------------------------
# * Add Switches
# switches : switch ids to save (maximum of 8)
#--------------------------------------------------------------------------
def add_switches(id1, *other)
@allocation << [0, id1, *other]
end
#--------------------------------------------------------------------------
# * Add Variable
# id : variable id
# bytes : how many bytes to use
# sign = 0 : positive or negative
#--------------------------------------------------------------------------
def add_variable(id, bytes, sign = 0)
@allocation << [1, id, bytes, [[sign, -1].max, 1].min]
end
#--------------------------------------------------------------------------
# * Add Self_Switches
# keys : self_switch keys to save (maximum of 8)
#--------------------------------------------------------------------------
def add_selfswitches(key1, *other)
@allocation << [2, key1, *other]
end
#--------------------------------------------------------------------------
# * Add Location
#--------------------------------------------------------------------------
def add_location
@allocation << [3]
end
#--------------------------------------------------------------------------
# * Add Time
# seconds = false : Use seconds instead of frames
#--------------------------------------------------------------------------
def add_time(seconds = false)
@allocation << [4, seconds]
end
#--------------------------------------------------------------------------
# * Compile Password
#--------------------------------------------------------------------------
def compile
size = allocated_bytes
raise("Allocated bytes do not match initial bytes.
#{size} allocated, #{@total_bytes} initialized.") if size != @total_bytes
@index = 0
@password = nil
@bytes.collect!{nil}
compile_bytes
shift = @shift_length > 0 ? rand(2**(@shift_length * 8 - 1) - 1).to_i : -1
checksum = calculate_checksum(@bytes, shift)
password_bytes = shift_bytes(@bytes, shift, 1)
shift = shift.to_s(2)
shift = '0' + shift while shift.size < @shift_length * 8
@shift_length.times do |i|
password_bytes << shift[(i*8)...(i*8+8)].to_i(2)
end
checksum = checksum.to_s(2)
checksum = '0' + checksum while checksum.size < @checksum_length * 8
@checksum_length.times do |i|
password_bytes << checksum[(i*8)...(i*8+8)].to_i(2)
end
password_string = bit_string(password_bytes, 8)
password = ''
password_string.unpack('a6' * (@total_bytes * 8 / 6)).each do |byte|
byte = byte.to_i(2)
password += ENCRYPT[byte]
end
@password = password
return true
end
#--------------------------------------------------------------------------
# * Read Password
# string : aString to read Must be same amount of characters as a
# generated password
#--------------------------------------------------------------------------
def read(string)
raise("Number of characters do not match.
#{string.size} given, #{@total_bytes * 8 / 6} needed.") if string.size !=
@total_bytes * 8 / 6
password = []
string.unpack('a' * string.size).each do |char|
password << DECRYPT[char]
end
password = bit_string(password, 6).unpack('a8' * @total_bytes)
checksum = ''
@checksum_length.times do
checksum = password.pop + checksum
end
checksum = @checksum_length > 0 ? checksum.to_i(2) : -1
shift = ''
@shift_length.times do
shift = password.pop + shift
end
shift = @shift_length > 0 ? shift.to_i(2) : -1
password.collect!{|byte| byte.to_i(2)}
password = shift_bytes(password, shift, -1)
raise('Invalid Password') if checksum != calculate_checksum(password, shift)
assemble_bytes(password)
return true
end
private
#--------------------------------------------------------------------------
# * Return number of allocated bytes
#--------------------------------------------------------------------------
def allocated_bytes
bytes = @shift_length + @checksum_length
@allocation.each do |data|
case data[0]
when 0
bytes += 1
when 1
bytes += data[2]
when 2
bytes += 1
when 3
bytes += 4
when 4
bytes += 4
end
end
return bytes
end
#--------------------------------------------------------------------------
# * Compile Bytes
#--------------------------------------------------------------------------
def compile_bytes
@allocation.each do |data|
case data[0]
when 0
comp_switches(*data[1...data.size])
when 1
comp_variable(*data[1...data.size])
when 2
comp_selfswitches(*data[1...data.size])
when 3
comp_location
when 4
comp_time(data[1])
end
end
end
#--------------------------------------------------------------------------
# * Assemble Bytes
# bytes : password byte data
#--------------------------------------------------------------------------
def assemble_bytes(bytes)
@allocation.each do |data|
case data[0]
when 0
ass_switches(data[1...data.size], bytes.shift)
when 1
pass_data = []
data[2].times {pass_data << bytes.shift}
ass_variable(data[1...data.size], pass_data)
when 2
ass_selfswitches(data[1...data.size], bytes.shift)
when 3
ass_location(data[1...data.size], [bytes.shift, bytes.shift, bytes.shift,
bytes.shift])
when 4
ass_time(data[1...data.size], [bytes.shift, bytes.shift, bytes.shift,
bytes.shift])
end
end
end
#--------------------------------------------------------------------------
# * Checksum Calculation
# shift : the shift character(s)
#--------------------------------------------------------------------------
def calculate_checksum(bytes, shift)
string = ''
bytes.each {|byte|string += byte.chr}
if shift >= 0
shift_string = shift.to_s(2)
shift_string = '0' + shift_string while shift_string.size < @shift_length * 8
shift_string.unpack('a8' * @shift_length).each do |byte|
string += byte.to_i(2).chr
end
end
order = @checksum_length * 8
poly = 2**order - 1
checksum = CRC.new(order, poly, 0, 0, false)
checksum.update(string)
sum = checksum.final
return @checksum_length > 0 ? sum : -1
end
#--------------------------------------------------------------------------
# * Byte Shift
# bytes : password byte data
# shift : how many times to shift
# dir : direction - negative is left, positive is right
#--------------------------------------------------------------------------
def shift_bytes(bytes, shift, dir)
password_bits = bit_string(bytes, 8)
password_bits = password_bits.unpack('a' * password_bits.size)
shift.times do
if dir == 1
password_bits.unshift password_bits.pop
else
password_bits.push password_bits.shift
end
end
password_bits = password_bits.to_s.unpack('a8' * bytes.size)
password_bits.collect!{|bit| bit.to_i(2)}
return password_bits
end
#--------------------------------------------------------------------------
# * Bit String
# bytes : password byte data
# bits : number of bits per number
#--------------------------------------------------------------------------
def bit_string(bytes, bits)
string = ''
bytes.each do |byte|
byte = byte.to_s(2)
byte = '0' + byte while byte.size < bits
string += byte
end
return string
end
#--------------------------------------------------------------------------
# * Switch compiling
#--------------------------------------------------------------------------
def comp_switches(id1, id2=0, id3=0, id4=0, id5=0, id6=0, id7=0, id8=0)
byte = 0
byte += 1<<7 if $game_switches[id1]
byte += 1<<6 if $game_switches[id2]
byte += 1<<5 if $game_switches[id3]
byte += 1<<4 if $game_switches[id4]
byte += 1<<3 if $game_switches[id5]
byte += 1<<2 if $game_switches[id6]
byte += 1<<1 if $game_switches[id7]
byte += 1<<0 if $game_switches[id8]
@bytes[@index] = byte
@index += 1
end
#--------------------------------------------------------------------------
# * Variable compiling
#--------------------------------------------------------------------------
def comp_variable(id, bytes, sign)
max = sign == 0 ? (2**(bytes*(8-1))-1) : sign == 1 ? 2**(bytes*8) : 0
min = sign == 0 ? -(2**(bytes*(8-1))-1) : sign == -1 ? -2**(bytes*8) : 0
max_bits = bytes * 8
max_bits -= 1 if sign == 0
var = [[$game_variables[id], min].max, max].min
var = var.to_s(2)
var = '0' + var while var.size < max_bits
var = ($game_variables[id] < 0 ? '1' : '0') + var if sign == 0
bytes.times do |i|
@bytes[@index] = var[(i*8)...(i*8+8)].to_i(2)
@index += 1
end
end
#--------------------------------------------------------------------------
# * Self_Switch compiling
#--------------------------------------------------------------------------
def comp_selfswitches(key1, key2=[0,0,'A'], key3=[0,0,'A'], key4=[0,0,'A'],
key5=[0,0,'A'], key6=[0,0,'A'], key7=[0,0,'A'], key8=[0,0,'A'])
byte = 0
byte += 1<<7 if $game_self_switches[key1]
byte += 1<<6 if $game_self_switches[key2]
byte += 1<<5 if $game_self_switches[key3]
byte += 1<<4 if $game_self_switches[key4]
byte += 1<<3 if $game_self_switches[key5]
byte += 1<<2 if $game_self_switches[key6]
byte += 1<<1 if $game_self_switches[key7]
byte += 1<<0 if $game_self_switches[key8]
@bytes[@index] = byte
@index += 1
end
#--------------------------------------------------------------------------
# * Location compiling
#--------------------------------------------------------------------------
def comp_location
map = $game_map.map_id.to_s(2)
x = $game_player.x.to_s(2)
y = $game_player.y.to_s(2)
dir = ($game_player.direction / 2).to_s(2)
map = '0' + map while map.size < 10
x = '0' + x while x.size < 9
y = '0' + y while y.size < 9
dir = '0' + dir while dir.size < 4
bits = map + x + y + dir
4.times do |i|
@bytes[@index] = bits[(i*8)...(i*8+8)].to_i(2)
@index += 1
end
end
#--------------------------------------------------------------------------
# * Time compiling
#--------------------------------------------------------------------------
def comp_time(seconds)
ticks = Graphics.frame_count
ticks %= Graphics.frame_rate if seconds
ticks = [ticks, 2**32-1].min
ticks = ticks.to_s(2)
ticks = '0' + ticks while ticks.size < 32
ticks.reverse!
4.times do |i|
@bytes[@index] = ticks[(i*8)...(i*8+8)].to_i(2)
@index += 1
end
end
#--------------------------------------------------------------------------
# * Switch assembly
#--------------------------------------------------------------------------
def ass_switches(allocation, data)
data = bit_string([data], 8)
allocation.each_with_index do |switch_id, i|
$game_switches[switch_id] = data[i, 1] == '1'
end
$game_map.refresh
end
#--------------------------------------------------------------------------
# * Variable assembly
#--------------------------------------------------------------------------
def ass_variable(allocation, data)
data = bit_string(data, 8)
mult = 1
if allocation[2] == 0
mult = data[0, 1] == '1' ? -1 : 1
data = data[1...data.size]
elsif allocation[2] == -1
mult = -1
end
$game_variables[allocation[0]] = mult * data.to_i(2)
$game_map.refresh
end
#--------------------------------------------------------------------------
# * Self_Switch assembly
#--------------------------------------------------------------------------
def ass_selfswitches(allocation, data)
data = bit_string([data], 8)
allocation.each_with_index do |key, i|
$game_self_switches[key] = data[i, 1] == '1'
end
$game_map.refresh
end
#--------------------------------------------------------------------------
# * Location assembly
#--------------------------------------------------------------------------
def ass_location(allocation, data)
bits = bit_string(data, 8)
map_id = bits[0, 10].to_i(2)
x = bits[10, 9].to_i(2)
y = bits[19, 9].to_i(2)
dir = bits[28, 4].to_i(2) * 2
if map_id == 0
map_id = $data_system.start_map_id
x, y = $data_system.start_x, $data_system.start_y
dir = 2
end
Graphics.freeze
$game_map.setup(map_id)
$game_player.moveto(x, y)
$game_player.direction = dir
$game_map.autoplay
$scene = Scene_Map.new
end
#--------------------------------------------------------------------------
# * Time assembly
#--------------------------------------------------------------------------
def ass_time(allocation, data)
data = bit_string(data, 8).reverse.to_i(2)
data * Graphics.frame_rate if allocation[0]
Graphics.frame_count = data
end
end
class Game_Character
attr_writer :direction
end
#=============================================================================
# ** Cyclic Redundancy Check
#=============================================================================
class CRC
def initialize(order, poly, iv, xor, reflect)
@order = order
@poly = poly
@iv = iv
@xor = xor
@reflect = reflect
if @reflect
@mask = (2 ** (@order - 8)) - 1
end
@lookup = build_lookup
@crc = init
end
def init
crc = @iv
if @reflect
crc = reflect(crc, @order)
end
crc
end
def update(str)
topbit = 1 << (@order - 1)
widthmask = (topbit << 1) - 1
str.each_byte do |byte|
if @reflect
@crc = ((@crc >> 8) & @mask) ^ @lookup[(@crc ^ byte) & 0xFF]
else
@crc = (@crc << 8) ^ @lookup[((@crc >> (@order - 8)) ^ byte) & 0xFF]
end
@crc &= widthmask
end
end
def final
@crc ^= @xor
bytes = (@order + 7) >> 3
@crc
end
private
def build_lookup
lookup = []
topbit = 1 << (@order - 1)
widthmask = (topbit << 1) - 1
for idx in 0..255
v = idx
v = reflect(v, 8) if @reflect
v <<= (@order - 8)
8.times do
if (v & topbit).nonzero?
v = (v << 1) ^ @poly
else
v <<= 1
end
end
v = reflect(v, @order) if @reflect
v &= widthmask
lookup << v
end
lookup
end
def reflect(crc, bits)
base = crc
for idx in 0...bits
bitmask = 1 << ((bits - 1) - idx)
if (base & 1).nonzero?
crc |= bitmask;
else
crc &= ~bitmask;
end
base >>= 1
end
crc
end
end
Instructions
Install the script above main and below the SDK, if using. Now you have to create the password data. The following is just an example:
Code:
PasswordGen = Password.new(12, 1, 1)
PasswordGen.add_switches(1, 2, 4, 3, 5, 7, 8, 6)
PasswordGen.add_variable(1, 1, 0)
PasswordGen.add_time(true)
PasswordGen.add_location
PasswordGen.compile
my_password = PasswordGen.password
Methods are:
- add_switches(ids) Up to 8 IDs. Uses one byte.
- add_variable(id, bytes, sign) Id is the variable ID, bytes is the number of bytes to use, sign is -1, 0 or 1.
- add_selfswitches(keys) Up to 8 KEYs. Uses one byte.
- add_location Saves the player's location and direction. Uses four bytes.
- add_time(seconds) Saves the game time in frames, or seconds. Uses four bytes.
FAQ
<no questions>
Compatibility
Compatible with the SDK, as no methods were modified.
Credits and Thanks
Thanks to crc.rb, which I got the Cyclic Redundancy Check algorithm from.
Author's Notes
This script does NOT include an input window to input passwords. You as the scripter will have to do that, or request one(but not here!) If one has any questions on how to operate this, please ask!