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.

[VX] Game Patcher

Status
Not open for further replies.
RMVX Game Patcher
Version 1.2.0

Introduction

You've just released your grand project.  It has a compressed size of 142MB.  You uploaded and posted it.  Suddenly, you remembered you forgot something!  Your starting place is in the wrong spot, and you didn't finish that event page!  And what's this! Your first boss is way too hard! You want to fix it, but that 142MB upload took an hour!  Thankfully, you remembered to install Yeyinde's VX Patch script!  You quickly create a 25KB patch file and upload it.  Now, with the patch you provided, the game runs just like it should.  What would you do without it?

This script allows you to patch your game with various "Patch Files". These files can add scripts, change game data, and even add new features!  Game patches are small in size, so they are easily uploaded.  Patch files also have a security feature: Only "authorized" patches can be loaded into your game thanks to a "Master Password".  Patch files that do not meet this password will close the game.

Patches: The easy way to fix and add.

Scripts

Code:
#==============================================================================
# ** Game Patcher
#------------------------------------------------------------------------------
#  * Scripted by: Yeyinde
#  * Version 1.2.0
#  * Date: 03/08/08
#------------------------------------------------------------------------------
#  This script lets you patch your game.
#  In this version, scripts, data and graphics can be patched.
#------------------------------------------------------------------------------
module Patcher
  EXT = '.rvdata'
  KEY = 'MyPa5Sw0|2d'
  DIR = 'Patch'
  SALT = %w(a b c d e f g h i j k l m n o p q r s t u v w x y z .
            A B C D E F G H I J K L M N O P Q R S T U V W X Y Z /)
  unless File.directory?(DIR)
    Dir.mkdir(DIR)
  end
end

class RPG::Map
  alias original_init initialize
  attr_accessor :id
  def initialize
    original_init
    @id = 0
  end
end

class RPG::MapInfo
  alias original_init initialize
  attr_accessor :id
  def initialize
    original_init
    @id = 0
  end
end

class Game_Map
  def setup(map_id)
    @map_id = map_id
    @map = $data_maps[@map_id]
    if @map.nil?
      print "Map #{@map_id} could not be located."
      exit
    end
    @display_x = 0
    @display_y = 0
    @passages = $data_system.passages
    referesh_vehicles
    setup_events
    setup_scroll
    setup_parallax
    @need_refresh = false
  end
end

class Font
  def marshal_dump;end
  def marshal_load(obj);end
end
  
class Bitmap
  # メモリ転送用の関数
  RtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
  RtlMoveMemory_ip = Win32API.new('kernel32', 'RtlMoveMemory', 'ipi', 'i')
  def _dump(limit)
    data = "rgba" * width * height
    RtlMoveMemory_pi.call(data, address, data.length)
    [width, height, Zlib::Deflate.deflate(data)].pack("LLa*") # ついでに圧縮
  end
  def self._load(str)
    w, h, zdata = str.unpack("LLa*"); b = new(w, h)
    RtlMoveMemory_ip.call(b.address, Zlib::Inflate.inflate(zdata), w * h * 4); b
  end
  # [[[bitmap.object_id * 2 + 16] + 8] + 16] == 生データの先頭(注意:上下反転)
  def address
    buffer, ad = "xxxx", object_id * 2 + 16
    RtlMoveMemory_pi.call(buffer, ad, 4); ad = buffer.unpack("L")[0] + 8
    RtlMoveMemory_pi.call(buffer, ad, 4); ad = buffer.unpack("L")[0] + 16
    RtlMoveMemory_pi.call(buffer, ad, 4); return buffer.unpack("L")[0]
  end
end

module Cache
  def self.set_bitmap(bitmap, path)
    @cache = {} if @cache == nil
    path = 'Graphics/' + path
    if @cache[path]
      @cache[path].dispose
      @cache[path] = nil
    end
    @cache[path] = bitmap.clone
  end
end

module Patcher
  NEW_DATA = {}
  CLASS_MAP = {RPG::Actor=>'$data_actors', RPG::Class=>'$data_classes',
    RPG::Skill=>'$data_skills', RPG::Item=>'$data_items',
    RPG::Weapon=>'$data_weapons', RPG::Armor=>'$data_armors',
    RPG::Enemy=>'$data_enemies', RPG::Troop=>'$data_troops',
    RPG::Animation=>'$data_animations', RPG::Map=>'$data_maps',
    RPG::MapInfo=>'$data_mapinfos', RPG::State=>'$data_states',
    RPG::CommonEvent=>'$data_common_events', RPG::System=>'$data_system',
    RPG::Area=>'$data_areas'}
    $data_mapinfos = load_data('Data/MapInfos.rvdata')
    $data_maps = {}
  (1..999).each do |map_id|
    begin
      map = load_data(sprintf("Data/Map%03d.rvdata", map_id))
      map.id = map_id
      $data_maps[map_id] = map
      $data_mapinfos[map_id].id = map_id
    rescue Errno::ENOENT
    end
  end
  def self.patch_data
    Patcher::NEW_DATA.each do |entry, data|
      eval(entry + '=data')
    end
  end
  def self.start_patcher
    Dir[Patcher::DIR + '/*' + Patcher::EXT].sort.each do |path|
      load_patch(path)
    end
  end
end
def load_patch(file_name)
  key = ''
  mtime = 0
  patch_script = []
  begin
    file = Zlib::GzipReader.open(file_name)
    key = file.comment
    mtime = file.mtime.to_i
    if file.orig_name != 'patch_data'
      print "Unauthorized patch detected.\n(#{file_name})"
      exit
    end
    patch_script = Marshal.load(file)
    other_data = []
    while !file.eof?
      other_data << Marshal.load(file)
    end
    other_data.each do |data_entry|
      if data_entry.is_a?(Array)
        Cache.set_bitmap(data_entry[0], data_entry[1])
      elsif !data_entry.is_a?(RPG::System)
        Patcher::NEW_DATA[Patcher::CLASS_MAP[data_entry.class] + '[' + 
          data_entry.id.to_s + ']'] = data_entry
      else
        Patcher::NEW_DATA[Patcher::CLASS_MAP[data_entry.class]] = data_entry
      end
    end
    file.close
    salt = Patcher::SALT[mtime % 54] + Patcher::SALT[(mtime % 54) ^ 53]
    if key != Patcher::KEY.crypt(salt)[2..-1]
      print "Unauthorized patch detected.\n(#{file_name})"
      exit
    end
    eval(Zlib::Inflate.inflate(patch_script))
  rescue ScriptError, SyntaxError, TypeError
    print "Unauthorized patch detected.\n(#{file_name})"
    exit
  end
end

class Scene_Title
  alias patcher_database load_database
  alias patcher_btdatabase load_bt_database
  def load_database
    patcher_database
    Patcher.patch_data
  end
  def load_bt_database
    patcher_btdatabase
    Patcher.patch_data
  end
end
Code:
class Window_DataSelect < Window_Command
  def initialize
    super(212, ['Script', 'Graphics'] + Patcher::CLASS_MAP.values.sort + ['>FINISH'])
    self.height = 32 + WLH * 17
    self.y = (Graphics.height - self.height) / 2
  end
  def selection
    return @commands[self.index]
  end
end
class Window_CurrentMode < Window_Base
  def initialize
    super(0, 0, 212, WLH+32)
  end
  def set(mode)
    return if @mode == mode
    self.contents.clear
    @mode = mode
    self.contents.draw_text(4, 0, 172, WLH, @mode)
  end
end
class Window_FileList < Window_Selectable
  attr_accessor :mode
  def initialize(array = [])
    super(0, 32+WLH, 212, WLH * 15+32)
    self.index = 0
    self.visible = false
    self.active = false
    @data = array
    @mode = 0
    refresh
  end
  def data(index = self.index)
    dat = nil
    if @data.is_a?(Array)
      dat = @data[self.index]
    else
      dat = @data[@data.keys[index]]
    end
    return dat
  end
  def data=(array)
    @data = array.dup
    refresh
  end
  def refresh
    self.index = 0
    if @mode == 0
      @data << nil
    else
      @data.compact! if @data.is_a?(Array)
    end
    @item_max = @data.size
    create_contents
    for i in 0...@item_max
      draw_item(i)
    end
  end
  def draw_item(index)
    if data(index).is_a?(RPG::Map) || data(index).is_a?(RPG::MapInfo)
      self.contents.draw_text(item_rect(index), 'Map ' +  data(index).id.to_s)
    elsif data(index).is_a?(RPG::Area)
      self.contents.draw_text(item_rect(index), 'Area ' +  data(index).id.to_s)
    elsif @data[index].is_a?(String)
      self.contents.draw_text(item_rect(index), @data[index])
    elsif @data[index].nil?
      self.contents.draw_text(item_rect(index), 'Use No Script')
    else
      self.contents.draw_text(item_rect(index), 'Data ' + (index + 1).to_s)
    end
  end
end

class Window_DataInfo < Window_Base
  def initialize
    super(212, 0, 332, WLH*17+32)
    self.y = (Graphics.height - self.height) / 2
    self.visible = false
    @data = nil
    @using = false
  end
  def set_data(data, using = false)
    return if (@data == data && @using == using)
    self.contents.clear
    @data = data
    @using = using
    if data
      branch_per_class(data)
      self.contents.draw_text(4, 0, 292, WLH, data.class.to_s)
      self.contents.draw_text(4, 0, 292, WLH, using, 2)
    else
      self.contents.draw_text(4, 0, 292, WLH, 'No custom data')
    end
  end
  def branch_per_class(object)
    case object
    when String
      return unless @data.include?('/')
      bitmap = Cache.load_bitmap('Graphics/' + @data.split('/')[0] + '/',
        @data.split('/')[1])
      self.contents.blt(0, 0, bitmap, bitmap.rect)
    when RPG::Actor
      draw_actor
    when RPG::Animation
      draw_animation
    when RPG::Area
      draw_area
    when RPG::Armor
      draw_armor
    when RPG::Class
      draw_class
    when RPG::CommonEvent
      draw_common_event
    when RPG::Enemy
      draw_enemy
    when RPG::Item
      draw_item
    when RPG::MapInfo
      draw_mapinfo
    when RPG::Map
      draw_map
    when RPG::Skill
      draw_skill
    when RPG::State
      draw_state
    when RPG::System
      draw_system
    when RPG::Troop
      draw_troop
    when RPG::Weapon
      draw_weapon
    end
  end
  def draw_item_base
    draw_item_name(@data, 4, WLH)
    self.contents.draw_text(4, WLH*2, 292, WLH, @data.description)
  end
  def draw_usable_item
    scope = %W(None One\sEnemy All\sEnemies One\sEnemy*2 Random\sEnemy
    2\sRandom\sEnemies 3\sRandom\sEnemies One\sAlly All\sAllies Dead\sAlly
    All\sDead\sAllies User)[@data.scope]
    occasion = @data.occasion == 0 ? 'Always' : @data.occasion == 1 ?
      'Battle Only' : @data.occasion == 2 ? 'Menu Only' : 'No Use'
    self.contents.draw_text(4, WLH*3, 292, WLH, 'Scope: ' + scope)
    self.contents.draw_text(4, WLH*4, 292, WLH, 'Use: ' + occasion)
    self.contents.draw_text(4, WLH*5, 292, WLH, 'Speed: ' + @data.speed.to_s)
    self.contents.draw_text(4, WLH*6, 292, WLH, 'Animation: ' + @data.animation_id.to_s)
    self.contents.draw_text(4, WLH*7, 292, WLH, 'Common Event: ' + @data.common_event_id.to_s)
  end
  def draw_actor
    self.contents.draw_text(4, WLH, 292, WLH, 'Name: ' + @data.name)
    self.contents.draw_text(4, WLH*2, 292, WLH, 'Class: ' + @data.class_id.to_s)
    self.contents.draw_text(4, WLH*3, 292, WLH, 'Level: ' + @data.initial_level.to_s)
    self.contents.draw_text(4, WLH*4, 292, WLH, 'EXP Base: ' + @data.exp_basis.to_s)
    self.contents.draw_text(4, WLH*5, 292, WLH, 'EXP Inflate: ' + @data.exp_inflation.to_s)
    self.contents.draw_text(4, WLH*6, 292, WLH, 'Sprite: ' + @data.character_name)
    self.contents.draw_text(4, WLH*7, 292, WLH, 'Sprite ID: ' + @data.character_index.to_s)
    self.contents.draw_text(4, WLH*8, 292, WLH, 'Face: ' + @data.face_name)
    self.contents.draw_text(4, WLH*9, 292, WLH, 'Face ID: ' + @data.face_index.to_s)
    equipment = [@data.weapon_id,@data.armor1_id,@data.armor2_id,@data.armor3_id,
      @data.armor4_id].join(',')
    self.contents.draw_text(4, WLH*10, 292, WLH, 'Equipment: ' + equipment) 
    self.contents.draw_text(4, WLH*11, 292, WLH, '2 Hands: ' + @data.two_swords_style.to_s)
    self.contents.draw_text(4, WLH*12, 292, WLH, 'Fixed: ' + @data.fix_equipment.to_s)
    self.contents.draw_text(4, WLH*13, 292, WLH, 'CPU: ' + @data.auto_battle.to_s)
    self.contents.draw_text(4, WLH*14, 292, WLH, 'Guard+: ' + @data.super_guard.to_s)
    self.contents.draw_text(4, WLH*15, 292, WLH, 'Healer: ' + @data.pharmacology.to_s)
    self.contents.draw_text(4, WLH*16, 292, WLH, 'Crit Bonus: ' + @data.critical_bonus.to_s)
  end
  def draw_animation
    self.contents.draw_text(4, WLH, 292, WLH, 'Name: ' + @data.name)
    self.contents.draw_text(4, WLH*2, 292, WLH, 'File 1: ' + @data.animation1_name)
    self.contents.draw_text(4, WLH*3, 292, WLH, 'Hue 1: ' + @data.animation1_hue.to_s)
    self.contents.draw_text(4, WLH*4, 292, WLH, 'File 2: ' + @data.animation2_name)
    self.contents.draw_text(4, WLH*5, 292, WLH, 'Hue 2: ' + @data.animation2_hue.to_s)
    pos = @data.position == 0 ? 'Head' : @data.position == 1 ? 'Center' :
      @data.position == 2 ? 'Feet' : 'Screen'
    self.contents.draw_text(4, WLH*6, 292, WLH, 'Position: ' + pos)
    self.contents.draw_text(4, WLH*7, 292, WLH, 'Frames: ' + @data.frame_max.to_s)
  end
  def draw_area
    self.contents.draw_text(4, WLH, 292, WLH, 'Name: ' + @data.name)
    self.contents.draw_text(4, WLH*2, 292, WLH, 'Map: ' + @data.map_id.to_s)
    self.contents.draw_text(4, WLH*3, 292, WLH, 'Area:')
    self.contents.draw_text(32, WLH*4, 264, WLH, 'X: ' + @data.rect.x.to_s)
    self.contents.draw_text(32, WLH*5, 264, WLH, 'Y: ' + @data.rect.y.to_s)
    self.contents.draw_text(32, WLH*6, 264, WLH, 'W: ' + @data.rect.width.to_s)
    self.contents.draw_text(32, WLH*7, 264, WLH, 'H: ' + @data.rect.height.to_s)
    self.contents.draw_text(4, WLH*8, 292, WLH, 'Encounters: ' + @data.encounter_list.join(','))
  end
  def draw_armor
    draw_item_base
    kind = @data.kind == 0 ? 'Shield' : @data.kind == 1 ? 'Helmet' :
      @data.kind == 2 ? 'Body Armor' : 'Accessory'
    self.contents.draw_text(4, WLH*3, 292, WLH, 'Kind: ' + kind)
    self.contents.draw_text(4, WLH*4, 292, WLH, 'Price: ' + @data.price.to_s)
    self.contents.draw_text(4, WLH*5, 292, WLH, 'EVA: ' + @data.eva.to_s)
    self.contents.draw_text(4, WLH*6, 292, WLH, 'ATK: ' + @data.atk.to_s)
    self.contents.draw_text(4, WLH*7, 292, WLH, 'DEF: ' + @data.def.to_s)
    self.contents.draw_text(4, WLH*8, 292, WLH, 'SPI: ' + @data.spi.to_s)
    self.contents.draw_text(4, WLH*9, 292, WLH, 'AGI: ' + @data.agi.to_s)
    self.contents.draw_text(4, WLH*10, 292, WLH, 'No Crit: ' + @data.prevent_critical.to_s)
    self.contents.draw_text(4, WLH*11, 292, WLH, '1/2 MP: ' + @data.half_mp_cost.to_s)
    self.contents.draw_text(4, WLH*12, 292, WLH, 'EXP*2: ' + @data.double_exp_gain.to_s)
    self.contents.draw_text(4, WLH*13, 292, WLH, 'Healing: ' + @data.auto_hp_recover.to_s)
    self.contents.draw_text(4, WLH*14, 292, WLH, 'Elements: ' + @data.element_set.join(','))
    self.contents.draw_text(4, WLH*15, 292, WLH, 'States: ' + @data.state_set.join(','))
  end
  def draw_class
    self.contents.draw_text(4, WLH, 292, WLH, 'Name: ' + @data.name)
    pos = @data.position == 0 ? 'Front' : @data.position == 1 ? 'Middle' : 'Back'
    self.contents.draw_text(4, WLH*2, 292, WLH, 'Row: ' + pos)
    self.contents.draw_text(4, WLH*3, 292, WLH, 'Custom Skill: ' + @data.skill_name_valid.to_s)
    self.contents.draw_text(4, WLH*4, 292, WLH, 'Skill Name: ' + @data.skill_name)
  end
  def draw_common_event
    trigger = %w(Call Autorun Parallel)[@data.trigger]
    self.contents.draw_text(4, WLH, 292, WLH, 'Name: ' + @data.name)
    self.contents.draw_text(4, WLH*2, 292, WLH, 'Trigger: ' + trigger)
    if @data.trigger > 0
      self.contents.draw_text(4, WLH*3, 292, WLH, 'Switch: ' + @data.switch_id.to_s)
    end
  end
  def draw_enemy
    self.contents.draw_text(4, WLH, 292, WLH, 'Name: ' + @data.name)
    self.contents.draw_text(4, WLH*2, 292, WLH, 'Sprite: ' + @data.battler_name)
    self.contents.draw_text(4, WLH*3, 292, WLH, 'Sprite Hue: ' + @data.battler_hue.to_s)
    self.contents.draw_text(4, WLH*4, 292, WLH, 'HP/MP: ' + @data.maxhp.to_s + '/' + @data.maxmp.to_s)
    self.contents.draw_text(4, WLH*5, 292, WLH, 'ATK: ' + @data.atk.to_s)
    self.contents.draw_text(4, WLH*6, 292, WLH, 'DEF: ' + @data.def.to_s)
    self.contents.draw_text(4, WLH*7, 292, WLH, 'SPI: ' + @data.spi.to_s)
    self.contents.draw_text(4, WLH*8, 292, WLH, 'AGI: ' + @data.agi.to_s)
    self.contents.draw_text(4, WLH*9, 292, WLH, 'EVA: ' + @data.eva.to_s)
    self.contents.draw_text(4, WLH*10, 292, WLH, 'Hit %: ' + @data.hit.to_s)
    self.contents.draw_text(4, WLH*11, 292, WLH, 'EXP: ' + @data.exp.to_s)
    self.contents.draw_text(4, WLH*12, 292, WLH, 'Gold: ' + @data.gold.to_s)
    type = %w(None Item Weapon Armor)[@data.drop_item1.kind]
    if @data.drop_item1.kind > 0
      drop1 = type+' '+@data.drop_item1.item_id.to_s+' 1/'+@data.drop_item1.denominator.to_s
    else
      drop1 = type
    end
    type = %w(None Item Weapon Armor)[@data.drop_item2.kind]
    if @data.drop_item1.kind > 0
      drop2 = type+' '+@data.drop_item2.item_id.to_s+' 1/'+@data.drop_item2.denominator.to_s
    else
      drop2 = type
    end
    self.contents.draw_text(4, WLH*13, 292, WLH, 'Drop 1: ' + drop1)
    self.contents.draw_text(4, WLH*14, 292, WLH, 'Drop 2: ' + drop2)
    self.contents.draw_text(4, WLH*15, 292, WLH, 'Air: ' + @data.levitate.to_s)
    self.contents.draw_text(4, WLH*16, 292, WLH, 'Critical: ' + @data.has_critical.to_s)
  end
  def draw_item
    draw_item_base
    draw_usable_item
    self.contents.draw_text(4, WLH*8,292, WLH, 'Price: ' + @data.price.to_s)
    self.contents.draw_text(4, WLH*9,292, WLH, 'Consumable: ' + @data.consumable.to_s)
    self.contents.draw_text(4, WLH*10,292, WLH, 'HP: ' + @data.hp_recovery_rate.to_s +
      '% + ' + @data.hp_recovery.to_s)
    self.contents.draw_text(4, WLH*11,292, WLH, 'MP: ' + @data.mp_recovery_rate.to_s +
      '% + ' + @data.mp_recovery.to_s)
    type = %w(None HP MP ATK DEF SPI AGI)
    string = type[@data.parameter_type]
    string += ' +' + @data.parameter_points.to_s if @data.parameter_type > 0
    self.contents.draw_text(4, WLH*12,292, WLH, 'Stat: ' + string)
    self.contents.draw_text(4, WLH*13, 292, WLH, 'Damage: ' + @data.base_damage.to_s +
    ' ± ' + @data.variance.to_s + '%')
    self.contents.draw_text(4, WLH*14, 292, WLH, 'Elements: ' + @data.element_set.join(','))
    self.contents.draw_text(4, WLH*15, 292, WLH, '+States: ' + @data.plus_state_set.join(','))
    self.contents.draw_text(4, WLH*16, 292, WLH, '-States: ' + @data.minus_state_set.join(','))
  end
  def draw_mapinfo
    self.contents.draw_text(4, WLH, 292, WLH, 'Name: ' + @data.name)
  end
  def draw_map
    self.contents.draw_text(4, WLH, 292, WLH, 'Width: ' + @data.width.to_s)
    self.contents.draw_text(4, WLH*2, 292, WLH, 'Height: ' + @data.height.to_s)
    scroll_type = @data.scroll_type == 0 ? 'None' : @data.scroll_type == 1 ?
      'Vertical' : @data.scroll_type == 2 ? 'Horizontal' : 'Both'
    self.contents.draw_text(4, WLH*3, 292, WLH, 'Scroll: ' + scroll_type)
    self.contents.draw_text(4, WLH*4, 292, WLH, 'Auto BGM: ' + @data.autoplay_bgm.to_s)
    self.contents.draw_text(4, WLH*5, 292, WLH, 'BGM: ' + @data.bgm.name)
    self.contents.draw_text(4, WLH*6, 292, WLH, 'Auto BGS: ' + @data.autoplay_bgs.to_s)
    self.contents.draw_text(4, WLH*7, 292, WLH, 'BGS: ' + @data.bgs.name)
    self.contents.draw_text(4, WLH*8, 292, WLH, 'Dash: ' + (!@data.disable_dashing).to_s)
    self.contents.draw_text(4, WLH*9, 292, WLH, 'Encounter Rate: ' + @data.encounter_step.to_s)
    self.contents.draw_text(4, WLH*10, 292, WLH, 'Encounters: ' + @data.encounter_list.join(','))
    self.contents.draw_text(4, WLH*11, 292, WLH, 'Parallax: ' + @data.parallax_name)
    self.contents.draw_text(32, WLH*12, 264, WLH, 'Loop X: ' + @data.parallax_loop_x.to_s)
    self.contents.draw_text(32, WLH*13, 264, WLH, 'Loop Y: ' + @data.parallax_loop_y.to_s)
    self.contents.draw_text(32, WLH*14, 264, WLH, 'Scroll X: ' + @data.parallax_sx.to_s)
    self.contents.draw_text(32, WLH*15, 264, WLH, 'Scroll Y: ' + @data.parallax_sy.to_s)
  end
  def draw_skill
    draw_item_base
    draw_usable_item
    self.contents.draw_text(4, WLH*8,292, WLH, 'MP: ' + @data.mp_cost.to_s)
    self.contents.draw_text(4, WLH*9,292, WLH, 'Hit %: ' + @data.hit.to_s)
    self.contents.draw_text(4, WLH*10, 292, WLH, 'Message:')
    self.contents.draw_text(8, WLH*11, 284, WLH, @data.message1)
    self.contents.draw_text(4, WLH*12, 292, WLH, 'Damage: ' + @data.base_damage.to_s +
    ' ± ' + @data.variance.to_s + '%')
    self.contents.draw_text(4, WLH*13, 292, WLH, 'Factors: ' + [@data.atk_f, @data.spi_f].join(','))
    self.contents.draw_text(4, WLH*14, 292, WLH, 'Elements: ' + @data.element_set.join(','))
    self.contents.draw_text(4, WLH*15, 292, WLH, '+States: ' + @data.plus_state_set.join(','))
    self.contents.draw_text(4, WLH*16, 292, WLH, '-States: ' + @data.minus_state_set.join(','))
  end
  def draw_state
    draw_item_name(@data, 4, WLH)
    self.contents.draw_text(4, WLH*2, 292, WLH, 'Priority: ' + @data.priority.to_s)
    restriction = %W(None No\sMagic Attack\sEnemies Attack\sParty No\sAction
    No\sAction/Evade)[@data.restriction]
    self.contents.draw_text(4, WLH*3, 292, WLH, 'Restriction: ' + restriction)
    rates = [@data.atk_rate, @data.def_rate, @data.spi_rate, @data.agi_rate].join(',')
    self.contents.draw_text(4, WLH*4, 292, WLH, 'Stat Rates: ' + rates)
    self.contents.draw_text(4, WLH*5, 292, WLH, 'No Block: ' + @data.nonresistance.to_s)
    self.contents.draw_text(4, WLH*6, 292, WLH, 'Reversal: ' + @data.offset_by_opposite.to_s)
    self.contents.draw_text(4, WLH*7, 292, WLH, 'Poison: ' + @data.slip_damage.to_s)
    self.contents.draw_text(4, WLH*8, 292, WLH, 'Blind: ' + @data.reduce_hit_ratio.to_s)
    self.contents.draw_text(4, WLH*9, 292, WLH, 'Battle Only: ' + @data.battle_only.to_s)
    release = ''
    if @data.hold_turn > 0
      release += @data.hold_turn.to_s + ' turns: ' + @data.auto_release_prob.to_s + '% '
    end
    if @data.release_by_damage
      release += 'Damage'
    end
    if release.empty?
      release = 'No cure'
    end
    self.contents.draw_text(4, WLH*10, 292, WLH, 'Release: ' + release)
    elements = @data.element_set.join(',')
    states = @data.state_set.join(',')
    self.contents.draw_text(4, WLH*11, 292, WLH, 'Anti-Ele: ' + elements)
    self.contents.draw_text(4, WLH*12, 292, WLH, 'Cure: ' + states)
    self.contents.draw_text(4, WLH*13, 292, WLH, @data.message1)
    self.contents.draw_text(4, WLH*14, 292, WLH, @data.message2)
    self.contents.draw_text(4, WLH*15, 292, WLH, @data.message3)
    self.contents.draw_text(4, WLH*16, 292, WLH, @data.message4)
  end
  def draw_system
    self.contents.draw_text(4, WLH, 292, WLH, 'Name: ' + @data.game_title)
    self.contents.draw_text(4, WLH*2, 292, WLH, 'Version: ' + @data.version_id.to_s)
    self.contents.draw_text(4, WLH*3, 292, WLH, 'Starting Pos:')
    self.contents.draw_text(32, WLH*4, 264, WLH, 'Map Id: ' + @data.start_map_id.to_s)
    self.contents.draw_text(32, WLH*5, 264, WLH, 'X: ' + @data.start_x.to_s)
    self.contents.draw_text(32, WLH*6, 264, WLH, 'Y: ' + @data.start_y.to_s)
    self.contents.draw_text(4, WLH*7, 292, WLH, 'Party: ' + @data.party_members.join(','))
    self.contents.draw_text(4, WLH*8, 292, WLH, 'Title: ' + @data.title_bgm.name)
    self.contents.draw_text(4, WLH*9, 292, WLH, 'Battle: ' + @data.battle_bgm.name)
    self.contents.draw_text(4, WLH*10, 292, WLH, 'Victory: ' + @data.battle_end_me.name)
    self.contents.draw_text(4, WLH*11, 292, WLH, 'Game Over: ' + @data.gameover_me.name)
  end
  def draw_troop
    self.contents.draw_text(4, WLH, 292, WLH, 'Name: ' + @data.name)
    enemies = @data.members.collect{|i| i.enemy_id}
    self.contents.draw_text(4, WLH*2, 292, WLH, 'Enemies: ' + enemies.join(','))
  end
  def draw_weapon
    draw_item_base
    self.contents.draw_text(4, WLH*3, 292, WLH, 'Animation: ' + @data.animation_id.to_s)
    self.contents.draw_text(4, WLH*4, 292, WLH, 'Price: ' + @data.price.to_s)
    self.contents.draw_text(4, WLH*5, 292, WLH, 'Hit %: ' + @data.hit.to_s)
    self.contents.draw_text(4, WLH*6, 292, WLH, 'ATK: ' + @data.atk.to_s)
    self.contents.draw_text(4, WLH*7, 292, WLH, 'DEF: ' + @data.def.to_s)
    self.contents.draw_text(4, WLH*8, 292, WLH, 'SPI: ' + @data.spi.to_s)
    self.contents.draw_text(4, WLH*9, 292, WLH, 'AGI: ' + @data.agi.to_s)
    self.contents.draw_text(4, WLH*10, 292, WLH, '2 Hands: ' + @data.two_handed.to_s)
    self.contents.draw_text(4, WLH*11, 292, WLH, 'First: ' + @data.fast_attack.to_s)
    self.contents.draw_text(4, WLH*12, 292, WLH, 'Attack*2: ' + @data.dual_attack.to_s)
    self.contents.draw_text(4, WLH*13, 292, WLH, 'Crit Bonus: ' + @data.critical_bonus.to_s)
    self.contents.draw_text(4, WLH*14, 292, WLH, 'Elements: ' + @data.element_set.join(','))
    self.contents.draw_text(4, WLH*15, 292, WLH, 'States: ' + @data.state_set.join(','))
  end
end    

class Scene_PatchMaker < Scene_Base
  def start
    super
    create_menu_background
    @PATCH = [Zlib::Deflate.deflate('')]
    @select_window = Window_DataSelect.new
    @file_window = Window_FileList.new
    @info_window = Window_DataInfo.new
    @mode_window = Window_CurrentMode.new
    @mode_window.visible = false
  end
  def update
    super
    update_windows
    if @select_window.active
      update_data_select
    elsif @file_window.active
      update_file_list
    end
  end
  def terminate
    super
    @select_window.dispose
    @file_window.dispose
    @info_window.dispose
    @mode_window.dispose
  end
  def update_windows
    @select_window.update
    @file_window.update
    @info_window.update
    @mode_window.update
    @info_window.visible = @select_window.selection == '$data_system' || (
      @file_window.active && @file_window.mode != 0)
    @mode_window.set(@select_window.selection)
  end
  def update_data_select
    @info_window.set_data($data_system, @PATCH.include?($data_system))
    if Input.trigger?(Input::C)
      Sound.play_decision
      if @select_window.selection == 'Script'
        @file_window.mode = 0
        @file_window.data = Dir['*.rb']
        @file_window.index = 0
        @file_window.visible = true
        @file_window.active = true
        @select_window.active = false
        @select_window.visible = false
        @mode_window.visible = true
      elsif @select_window.selection == 'Graphics'
        @file_window.mode = 2
        data = Dir['Graphics/**/*.{png,jpg}'].collect{|i| i[9...(i.length-4)]}
        @file_window.data = data
        @file_window.index = 0
        @file_window.visible = true
        @file_window.active = true
        @select_window.active = false
        @select_window.visible = false
        @mode_window.visible = true
      elsif @select_window.selection == '>FINISH'
        make_patch
        $scene = Scene_Map.new
      elsif @select_window.selection == '$data_system'
        if @PATCH.include?($data_system)
          @PATCH.delete($data_system)
        else
          @PATCH << $data_system
        end
      else
        @file_window.mode = 1
        @file_window.data = eval(@select_window.selection)
        @file_window.index = 0
        @file_window.visible = true
        @file_window.active = true
        @select_window.active = false
        @select_window.visible = false
        @mode_window.visible = true
      end
    elsif Input.trigger?(Input::B)
      Sound.play_cancel
      $scene = Scene_Map.new
    end
  end
  def update_file_list
    if @file_window.mode == 2
      if @file_window.data
        bitmap = Cache.load_bitmap('Graphics/' + @file_window.data.split('/')[0] + '/',
        @file_window.data.split('/')[1])
      else
        bitmap = Cache.load_bitmap('', '')
      end
      array = [bitmap, @file_window.data]
      @info_window.set_data(@file_window.data, @PATCH.include?(array))
    else
      @info_window.set_data(@file_window.data, @PATCH.include?(@file_window.data))
    end
    if Input.trigger?(Input::C)
      Sound.play_decision
      if @file_window.mode == 0
        set_script
        @file_window.visible = false
        @file_window.active = false
        @select_window.active = true
        @select_window.visible = true
        @mode_window.visible = false
      elsif @file_window.mode == 1
        return if @file_window.data.nil?
        if @PATCH.include?(@file_window.data)
          @PATCH.delete(@file_window.data)
        else
          @PATCH << @file_window.data
        end
      else
        return if @file_window.data.nil?
        bitmap = Cache.load_bitmap('Graphics/' + @file_window.data.split('/')[0] + '/',
        @file_window.data.split('/')[1])
        array = [bitmap, @file_window.data]
        if @PATCH.include?(array)
          @PATCH.delete(array)
        else
          @PATCH << array
        end
      end
    elsif Input.trigger?(Input::B)
      Sound.play_cancel
      @file_window.visible = false
      @file_window.active = false
      @select_window.active = true
      @select_window.visible = true
      @mode_window.visible = false
    end
  end
  def set_script
    @script_name = @file_window.data
    lines = []
    if @file_window.data
      lines = File.readlines(@file_window.data)
    end
    @PATCH[0] = Zlib::Deflate.deflate(lines.join)
  end
  def make_patch
    name = 'MyPatch'
    if @script_name
      name = File.basename(@script_name, '.rb')
    end
    name += Patcher::EXT
    mtime = Time.now().to_i
    salt = Patcher::SALT[mtime % 54] + Patcher::SALT[(mtime % 54) ^ 53]
    key = Patcher::KEY.crypt(salt)
    gz = Zlib::GzipWriter.open(name)
    gz.comment = key[2..-1]
    gz.mtime = mtime
    gz.orig_name = 'patch_data'
    @PATCH.each {|data| Marshal.dump(data, gz)}
    gz.close
  end
end
Code:
# Include this in your Main script.  It will start the patching sequence.
Patcher.start_patcher

Instructions

Setting Up:
1) Change the KEY in the Patcher module.  This is the password that lets only authorized patches work.
2) Change the DIR in the Patcher module if you want to use a different folder to get patches from.
3) Change the EXT in the Patcher module to have a different extension for patch files.
4) By rearranging SALT, even more security can be added!

Making a Patch:
1) Add scripts you want into a text file and give the file the extension ".rb".  Save this file in your game's main directory. (OPTIONAL)
2) Call Script: $scene = Scene_PatchMaker.new
3) Select the script you want to use in the Script menu. (OPTIONAL IF DATA IS INCLUDED)
4) Select the data you want to include in your patch.  Data is categorized, so it is easy to locate.  The true/false in the top right corner indicates if the data will be in the patch file. (OPTIONAL IF SCRIPT IS INCLUDED)
5) Select ">FINISH". This will generate your patch file.
6) Rename your patch.  The order in which the Game Patcher will load things is in this order: -, _, 0 to 9, A to Z, a-z.  Patches that are loaded last can overwrite previously loaded patches.
7) Enjoy your small patch file.

Notes

Does not patch audio files.

VX->XP Conversion Fund

For those who really want this script in XP, please contribute to the $30 fund.
Funds: $0/30
 
Holy cow, this script is amazing! Makes it much easier to update. Perhaps you could make an XP version yea? Not everyone is comfortable with VX yet. --Just a thought =P

-Krobe
 
I tried so many times to do a script like that. Well, I did something similar using your RSC Require script but it wasn't as good as this!
Awesome work Yeyinde!

I'm going to try this out right now :thumb:
 
Why every cool script comes out for that hell-shit-ugly-pervert thing called VX...

PLZ PLZ PLZ make it for XP...  *.-

Venetia: No moar. If the scripter wanted to make it for XP they would. (Not that I'd complain.)
 
Krobelus":2nfn02ry said:
Holy cow, this script is amazing! Makes it much easier to update. Perhaps you could make an XP version yea? Not everyone is comfortable with VX yet. --Just a thought =P

-Krobe
Perhaps I'll make an XP version.  Maybe if I can get more support...

Larynni":2nfn02ry said:
Totally owns.
XP it pl0x?
Another for XP!  Good stuff.  I just need one more....

Sir Lord Biowulve":2nfn02ry said:
Why every cool script comes out for that hell-shit-ugly-pervert thing called VX...

PLZ PLZ PLZ make it for XP...  *.-
Screw XP compatibility now.  Thanks to jerkwads like this, you won't get it.  One bad apple spoils the bunch.

Why don't we take a lessen here, folks.  Saying shit about VX = No script for XP.  Simple as that.
 
Yeyinde":ekwvctik said:
Screw XP compatibility now.  Thanks to jerkwads like this, you won't get it.  One bad apple spoils the bunch.

Why don't we take a lessen here, folks.  Saying shit about VX = No script for XP.  Simple as that.

Oh, owned.  <3

This is so handy, Yeyinde.  I already told you what I wanna use it for. >> <<
 
Yeyinde!
XP NAO!!!
:shock:

Seriously this is an amazing use, and you've made one project switch to VX I can tell you that much.  Keep it up man, you never cease at surprising me -as I've told you already.
:pred: :toadie: :pred:
 

e

Sponsor

Dear Yeyinde,

I recently learned that I was affected by a most dreadful, eldritch illness; I can hear it seeping insidiously through my body at night, a thick goo spreading upon my lively cells, sliding in between them before solidifying into a deadly cement.

It is called Cercan. My doctor, although an honourable old, 18th century dandy, has been unable to casually explain to me, in terms I might understand, what exactly Cercan is; on the other hand, according to Wikipedia, it is a plushie. I fear my life will be cut short by this mad, horrifying stuffed buffoon.

Mommy says I don't have much more than a few nanoseconds to live. She says that I should spend these in a level-headed manner, coolly and in full lucidity; therefore, I ask of you one thing before I shuffle off my mortal coil:

Will you please port this script to RPG Maker XP? It would make my heart shine through the heavens as my soul is lifted toward mine own maker.

- Littlest Cthulhu

I don't think I need to add much more to this. A RMXP port would truly be a blessed thing, Yeyinde. Cain bless your soul.
 
All right, guys.  Next person that asks for an XP version gets smat.  Yeyinde said he wasn't going to do it, that's it.  Game over.  Get VX if you want to use this.
 

Taylor

Sponsor

*sniggers*

I could be wrong, but can't you override compressed things by creating a "Graphics/whatever" etc. folder?

...
What I'm trying to say is, even if the project is compressed, couldn't you create an edited/added file and load it to the right directory and it overrides the compressed version?

I could be wrong, I think this only works for missing files or replacing RTP files - I did this when I was creating some add-ons for  'The Search for Thomas' ^^
 
Jirbytaylor":3o3ghttx said:
I could be wrong, but can't you override compressed things by creating a "Graphics/whatever" etc. folder?
What I'm trying to say is, even if the project is compressed, couldn't you create an edited/added file and load it to the right directory and it overrides the compressed version?
I could be wrong, I think this only works for missing files or replacing RTP files - I did this when I was creating some add-ons for  'The Search for Thomas' ^^
You may be wrong there.  The last time I made any Graphics/whatever files for an encrypted game, the game would not load.  Also, how would I store image data in patch files without any way to dump the Bitmap object?


People, if you *really* want an XP version, you'll have to pay for it.  I calculated the approximate cost of this script in XP, and it is around $30.  So, if you want to see this script in XP glory, chip in.  Once I get to $30, I'll make and release it.  Don't want to pay? Then no XP version.  It's that simple.

VX->XP Funds: $0/30

Payment is through Paypal ONLY.  PM me for details.

EDIT: For clarification, the $30 is NOT a PER SCRIPT cost. It is a ONE TIME CONVERSIONAL fee. You DO NOT need to pay the whole $30 at once. (You add $10, somebody else adds $5, etc.)
 
Great... now the VX version is gone too. Great work people, and by the way you should all be happy with the fact that you all have like 500 scripts for RMXP already which seem really good. VX needs some good scripts I say. Anyway although I didn't get it seemed really cool. Must've taken quite a lot of work. Thanks anyway.
 
The VX version will be up again at the end of the week, or if the $50 is payed.  If the $50 is payed, an XP version will be released.  If the $50 isn't payed, no XP script will be put out and will never come.  So, just have patience...
 
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