Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

File Size Based Save System (FSBSS)

Status
Not open for further replies.
File Size Based Save System
Version: 1.0

Introduction

This script changes the default save system to one that uses file sizes instead of one that uses an index. Because it uses a file size, I allow the player to name his/her save file to whatever he/she wants (using legal characters, of course).

Features
  • Easy to use
  • Can name your own save file!
  • Customizable memory capacity
  • Customizable file extension

Screenshots

Please note that these screenshots are from my game, Tropicana. The system here looks similar, but it doesn't have the selection window, batter gauge and connectivity metre.
http://i12.photobucket.com/albums/a229/ ... ystem2.png[/IMG]http://i12.photobucket.com/albums/a229/meismeofcourse/Savesystem3.png[/IMG]

Script

Looks like the families get a lucky break today.
Code:
#==============================================================================
# ** File Size Based Save System (FSBSS)
#------------------------------------------------------------------------------
#  © Yeyinde, 2007
#==============================================================================

module FSBSS
  # Maximum memory capacity (in Mega Bytes (MB)) - Floating points may be used.
  MAXIMUM_MEMORY = 0.5
  # Save file extension, leave out the .
  # Please don't name it something like ini or exe, this may cause errors.
  SAVE_FILE_EXT = 'rxdata'
  # Temporary save extension, do not name it the same as above
  TEMP_FILE_EXT = 'temp'
  # Maximum characters in filename (excluding extension)
  MAX_CHARACTERS = 20
end


#--------------------------------------------------------------------------
# * Get Memory remaining
#--------------------------------------------------------------------------
def get_memory
  list = Dir.entries('.')
  list.delete('.').delete('..').delete('Audio').delete('Graphics').delete('Data')
  list.delete_if {|file| file.split('.')[-1] != FSBSS::SAVE_FILE_EXT}
  megs = FSBSS::MAXIMUM_MEMORY
  size = 0
  list.each do |filename|
    file = File.open(filename)
    size += File.size(file) / 1024
    file.close
  end
  megs *= 1024
  megs -= size
  return megs.to_i
end
  
  
#==============================================================================
# ** Window_SaveFile
#------------------------------------------------------------------------------
#  This window displays save files on the save and load screens.
#==============================================================================

class Window_SaveFile < Window_Selectable
  #--------------------------------------------------------------------------
  # * Object Initialization
  #     loading : if window is used for loading
  #--------------------------------------------------------------------------
  def initialize(loading = false)
    super(0, 96, 640, 416)
    self.index = 0
    self.opacity = 0
    @loading = loading
    refresh
  end
  #--------------------------------------------------------------------------
  # * Get Save
  #--------------------------------------------------------------------------
  def save
    return @data[self.index]
  end
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    if self.contents != nil
      self.contents.clear
      self.contents = nil
    end
    @data = []
    list = Dir.entries('.')
    list.delete('.').delete('..').delete('Audio').delete('Graphics').delete('Data')
    list.delete_if {|file| file.split('.')[-1] != FSBSS::SAVE_FILE_EXT}
    @data = list << nil
    @item_max = @data.size
    self.contents = Bitmap.new(width - 32, @item_max * 32)
    @data.each_index { |i| draw_save(i)}
  end
  #--------------------------------------------------------------------------
  # * Draw Save
  #     index : save number
  #--------------------------------------------------------------------------
  def draw_save(index)
    y = index * 32
    filename = @data[index]
    if filename
      size = 0
      file = File.open(filename)
      size = File.size(file)
      file.close
      self.contents.draw_text(4, y, 300, 32, filename.split('.')[0])
      self.contents.draw_text(304, y, 300, 32, "#{size / 1024} KB", 2)
    else
      self.contents.draw_text(4, y, 300, 32, '<Create New Data>')
    end
  end
  #--------------------------------------------------------------------------
  # * Help Text Update
  #--------------------------------------------------------------------------
  def update_help
    text = @loading ? 'Load this file?' : 'Do what with this file?'
    @help_window.set_text(save ? text : 'Create new data.')
  end
end


#==============================================================================
# ** Window_SaveBar
#------------------------------------------------------------------------------
#  This window displays the memory remaining and acts as a background to
#    Window_SavfeFile.
#==============================================================================

class Window_SaveBar < Window_Base
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    super(0, 64, 640, 416)
    self.contents = Bitmap.new(width - 32, height - 32)
    refresh
  end
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    self.contents.clear
    self.contents.font.color = system_color
    self.contents.draw_text(4, 0, 128, 32, '-Filename-')
    self.contents.font.color = normal_color
    self.contents.draw_text(132, 0, 472, 32, 
      "Remaining: #{get_memory} KB", 2)
  end
end


#==============================================================================
# ** Window_Keyboard
#------------------------------------------------------------------------------
#  This window displays characters to name savefiles.
#==============================================================================

class Window_Keyboard < Window_Selectable
  CHARACTER_UPCASE =
  [
    "1","2","3","4","5","6","7","8","9","0",
    "Q","W","E","R","T","Y","U","I","O","P",
    "A","S","D","F","G","H","J","K","L","→",
    "Z","X","C","V","B","N","M","↓","←","_"
  ]
  CHARACTER_DOWNCASE = [
    "1","2","3","4","5","6","7","8","9","0",
    "q","w","e","r","t","y","u","i","o","p",
    "a","s","d","f","g","h","j","k","l","→",
    "z","x","c","v","b","n","m","↑","←","-"
  ]
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :upcase
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    super(0, 0, 640, 160)
    self.contents = Bitmap.new(width - 32, height - 32)
    self.index = 0
    @item_max = CHARACTER_UPCASE.size
    @column_max = 10
    @upcase = false
    refresh
  end
  #--------------------------------------------------------------------------
  # * Get Character
  #--------------------------------------------------------------------------
  def character
    table = @upcase ? CHARACTER_UPCASE : CHARACTER_DOWNCASE
    return table[self.index]
  end
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    self.contents.clear
    table = @upcase ? CHARACTER_UPCASE : CHARACTER_DOWNCASE
    table.each_index do |i|
      x = i % 10 * 64
      y = i / 10 * 32
      self.contents.draw_text(x, y, 32, 32, table[i], 1)
    end
  end
end


#==============================================================================
# ** Window_FileName
#------------------------------------------------------------------------------
#  This window displays the current filename when naming a savefile.
#==============================================================================

class Window_FileName < Window_Base
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_reader :name
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    super(0, 64, 640, 416)
    self.contents = Bitmap.new(width - 32, height - 32)
    @name = ''
    refresh
  end
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    self.contents.clear
    self.contents.draw_text(4, 0, 600, 32, @name + '.' + FSBSS::SAVE_FILE_EXT, 1)
  end
  #--------------------------------------------------------------------------
  # * Add character
  #     char : character
  #--------------------------------------------------------------------------
  def add(char)
    if char == "←"
      delete
      return
    end
    @name += char
    refresh
  end
  #--------------------------------------------------------------------------
  # * Delete Character
  #--------------------------------------------------------------------------
  def delete
    string = @name.unpack('a' * @name.length)
    string.pop
    @name = string.to_s
    refresh
  end
  #--------------------------------------------------------------------------
  # * Clear
  #--------------------------------------------------------------------------
  def clear
    @name = ''
    refresh
  end
end


#==============================================================================
# ** Scene_File
#------------------------------------------------------------------------------
#  This is a superclass for the save screen and load screen.
#==============================================================================

class Scene_File
  #--------------------------------------------------------------------------
  # * Main Processing
  #--------------------------------------------------------------------------
  def main
    @help_window = Window_Help.new
    @save_window = Window_SaveFile.new($scene.is_a?(Scene_Load))
    @savebar_window = Window_SaveBar.new
    @save_window.help_window = @help_window
    @keyboard_window = Window_Keyboard.new
    @keyboard_window.x = 320 - @keyboard_window.width / 2
    @keyboard_window.y = 272 - @keyboard_window.height / 2
    @keyboard_window.visible = false
    @keyboard_window.active = false
    @filename_window = Window_FileName.new
    @filename_window.visible = false
    s1 = 'Overwrite'
    s2 = 'Load'
    s3 = 'Delete'
    s4 = 'Cancel'
    @save_command_window = Window_Command.new(160, [s1, s2, s3, s4])
    @save_command_window.x = 320 - @save_command_window.width / 2
    @save_command_window.y = 240 - @save_command_window.height / 2
    @save_command_window.z += 10
    @save_command_window.visible = false
    @save_command_window.active = false
    Graphics.transition
    loop do
      Graphics.update
      Input.update
      update
      break if $scene != self
    end
    Graphics.freeze
    @help_window.dispose
    @save_window.dispose
    @savebar_window.dispose
    @keyboard_window.dispose
    @filename_window.dispose
    @save_command_window.dispose
  end
  #--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  def update
    @help_window.update
    @save_window.update
    @savebar_window.update
    @keyboard_window.update
    @filename_window.update
    @save_command_window.update
    if @save_window.active
      update_save_window
    elsif @keyboard_window.active
      update_keyboard_window
    elsif @save_command_window.active
      update_save_command
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Save Window
  #--------------------------------------------------------------------------
  def update_save_window
    if Input.trigger?(Input::C)
      on_decision(@save_window.save)
      return
    end
    if Input.trigger?(Input::B)
      on_cancel
      return
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Keyboard Window
  #--------------------------------------------------------------------------
  def update_keyboard_window
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      if @filename_window.name.length == 0
        @save_window.visible = true
        @save_window.active = true
        @savebar_window.visible = true
        @keyboard_window.visible = false
        @filename_window.visible = false
        @keyboard_window.active = false
        return
      end
      @filename_window.delete
    end
    if Input.trigger?(Input::C)
      if @keyboard_window.character == "→"
        if @filename_window.name.length == 0
          $game_system.se_play($data_system.buzzer_se)
          @help_window.set_text('Cannot have a file with no name.')
          return
        end
        if File.exist?(@filename_window.name + '.' + FSBSS::SAVE_FILE_EXT)
          $game_system.se_play($data_system.buzzer_se)
          @help_window.set_text('File already exists.')
          return
        end
        file = File.new(@filename_window.name + '.' + FSBSS::SAVE_FILE_EXT, 'wb')
        write_save_data(file)
        file.close
        if get_memory < 0
          $game_system.se_play($data_system.buzzer_se)
          File.delete(@filename_window.name + '.' + FSBSS::SAVE_FILE_EXT)
          return
        end
        $game_system.se_play($data_system.save_se)
        @save_window.visible = true
        @save_window.active = true
        @save_window.refresh
        @savebar_window.refresh
        @savebar_window.visible = true
        @keyboard_window.visible = false
        @filename_window.visible = false
        @filename_window.clear
        @keyboard_window.active = false
        return
      end
      if @filename_window.name.length > FSBSS::MAX_CHARACTERS or 
        @keyboard_window.character == ""
        $game_system.se_play($data_system.buzzer_se)
        return
      end
      $game_system.se_play($data_system.decision_se)
      if @keyboard_window.character == "↑"
        @keyboard_window.upcase = true
        @keyboard_window.refresh
        return
      end
      if @keyboard_window.character == "↓"
        @keyboard_window.upcase = false
        @keyboard_window.refresh
        return
      end
      @filename_window.add(@keyboard_window.character)
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Command Window
  #--------------------------------------------------------------------------
  def update_save_command
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @save_window.active = true
      @save_command_window.visible = false
      @save_command_window.active = false
      return
    end
    if Input.trigger?(Input::C)
      case @save_command_window.index
      when 0 # Overwrite
        old_file = @save_window.save.split('.')[0] + '.' + FSBSS::TEMP_FILE_EXT
        File.rename(@save_window.save, old_file)
        file = File.open(@save_window.save, "wb")
        write_save_data(file)
        file.close
        if get_memory < 0
          $game_system.se_play($data_system.buzzer_se)
          File.delete(@save_window.save)
          File.rename(old_file, @save_window.save)
          @save_window.refresh
          return
        end
        File.delete(old_file)
        @save_window.refresh
        @savebar_window.refresh
        $game_system.se_play($data_system.save_se)
      when 1 # Load
        $game_system.se_play($data_system.load_se)
        file = File.open(@save_window.save)
        read_data(file)
        file.close
        $scene = Scene_Map.new
        return
      when 2 # Delete
        $game_system.se_play($data_system.decision_se)
        File.delete(@save_window.save)
        @save_window.refresh
        @savebar_window.refresh
      when 3 # Cancel
        $game_system.se_play($data_system.decision_se)
      end
      @save_window.active = true
      @save_command_window.visible = false
      @save_command_window.active = false
    end
  end
  #--------------------------------------------------------------------------
  # * Read Save Data
  #     file : file object for reading (opened)
  #--------------------------------------------------------------------------
  def read_data(file)
    characters = Marshal.load(file)
    Graphics.frame_count = Marshal.load(file)
    $game_system        = Marshal.load(file)
    $game_switches      = Marshal.load(file)
    $game_variables     = Marshal.load(file)
    $game_self_switches = Marshal.load(file)
    $game_screen        = Marshal.load(file)
    $game_actors        = Marshal.load(file)
    $game_party         = Marshal.load(file)
    $game_troop         = Marshal.load(file)
    $game_map           = Marshal.load(file)
    $game_player        = Marshal.load(file)
    if $game_system.magic_number != $data_system.magic_number
      $game_map.setup($game_map.map_id)
      $game_player.center($game_player.x, $game_player.y)
    end
    $game_party.refresh
  end
end


#==============================================================================
# ** Scene_Save
#------------------------------------------------------------------------------
#  This class performs save screen processing.
#==============================================================================

class Scene_Save < Scene_File
  #--------------------------------------------------------------------------
  # * Decision Processing
  #--------------------------------------------------------------------------
  def on_decision(filename)
    if filename.nil?
      @save_window.active = false
      @save_window.visible = false
      @savebar_window.visible = false
      @keyboard_window.active = true
      @keyboard_window.visible = true
      @filename_window.visible = true
      return
    end
    @save_window.active = false
    @save_command_window.visible = true
    @save_command_window.index = 0
    @save_command_window.active = true
    return
  end
  #--------------------------------------------------------------------------
  # * Cancel Processing
  #--------------------------------------------------------------------------
  def on_cancel
    $game_system.se_play($data_system.cancel_se)
    if $game_temp.save_calling
      $game_temp.save_calling = false
      $scene = Scene_Map.new
      return
    end
    $scene = Scene_Menu.new(4)
  end
end


#==============================================================================
# ** Scene_Load
#------------------------------------------------------------------------------
#  This class performs load screen processing.
#==============================================================================

class Scene_Load < Scene_File
  #--------------------------------------------------------------------------
  # * Decision Processing
  #--------------------------------------------------------------------------
  def on_decision(filename)
    if @save_window.save
      $game_system.se_play($data_system.load_se)
      file = File.open(@save_window.save)
      read_save_data(file)
      file.close
    else
      $game_system.se_play($data_system.decision_se)
      command_new_game
    end
    $scene = Scene_Map.new
  end
  #--------------------------------------------------------------------------
  # * Cancel Processing
  #--------------------------------------------------------------------------
  def on_cancel
    $game_system.se_play($data_system.cancel_se)
    $scene = Scene_Title.new
  end
  #--------------------------------------------------------------------------
  # * Read Save Data
  #     file : file object for reading (opened)
  #--------------------------------------------------------------------------
  alias read_save_data read_data
  def read_save_data(file)
    read_data(file)
  end
  #--------------------------------------------------------------------------
  # * Command: New Game
  #--------------------------------------------------------------------------
  def command_new_game
    temp = Scene_Title.new
    temp.command_new_game
    temp = nil
  end
end

Instructions

  1. Insert this script below Scene_Debug. This is to assure that scripts that add to the save file are not messed up.
  2. Remove lines 48 to 52 in Scene_Title, change @continue_enabled = false[/FONT] to @continue_enabled = true[/FONT]
  3. Edit the constants in the FSBSS module to suit your needs.

FAQ

No questions asked

Compatibility

May be SDK compatible (conformation needed). Should be compatible with scripts that add to the save files.

Author's Notes

This script was originally developed for my game, Tropicana. I just thought I'd share it with you all.
 
this is a nice save system

But its better with some game info´s

maby

how many character in the party *icon


But the SAve system its great ;)
 
Landarma":1wa2js6x said:
Well.... I wonder if 'alias read_save_data read_data' can be a trouble if you use this with SDK........
Yeah, I see the problem. I'll update the script later without that so it will be SDK compatible.

Ex.":1wa2js6x said:
this is a nice save system

But its better with some game info´s

maby

how many character in the party *icon


But the SAve system its great :wink01:
The thing about getting to name your saves is that you should know your character data. And if you load the wrong one accidentally, you can just go back to the save menu and select load.



Thank you all for the comments.
 
Yeyinde":11oha625 said:
Load up the save screen, save a couple times under different names. There's your screenshot.

lol you sound just like Trickster! :p
Excelent script Yeyinde, I love it!
Keep up the good work! :thumb:

-Dargor
 
When you select load from the menu and select new data, there is an error.
Could you take out the create new data option out of the load screen?

EDIT: Fixed
 
Just saying "There is an error" won't solve it more quickly. You'll need to tell me exactly what the error says and the line it occurs on.
 
People still use Cybersams Keyboard module? Doesn't that thing still use about 500 global variables? It works excellently, but needs to be updated drastically...

Good work Yey.
Looks like the families get a lucky break today.

I am telling Trickster...
 
really nice script. However, when you load a saved game from the title screen, the title bgm still continues playing. Little bug i found

-Edit, I thought it would be a quick little time saver to bind the shift key to make the letters upper case.
So somewhere in def update_keyboard_window i put
Code:
if Input.press?(Input::A)
      @keyboard_window.upcase = true
        @keyboard_window.refresh
        return
      end
however it doesn't go back to lowercase with other codings i've tried. I was hoping if it wasn't too much, that you could finish the coding off for me, since im still a newb :D Thanks
 
Status
Not open for further replies.

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top