Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - ForeverZer0

31
I was wondering.

It would have made the editor a cinch, allowed us to use several different languages, and maintained cross-platform compatibility.
The framework is stable and holding compatibility with .NET 2.0.

This is mainly just me bitching about Python and not being able to use my preferred language, but in all reality, the only downside I see is adding Mono as a dependency. I didn't know if this decision came from a misconception of the stability or ability of Mono, but I have personally experimented with it with great results. I even have Mono Tools installed in VS, so I can quickly test in a Mono environment with the click of a button, which I then have ported to Ubuntu and Snow Leopard VMs and used just the same. 

I realize this is extremely late in the game to try and seriously push the issue, but I think the editor would have been done long ago if we could have used the power of VS to build it.  PyTools is a massive help, but it can't even compare.
32
Welcome! / Farewell, all, I'm moving on.
May 02, 2012, 01:37:28 am
I have reached a time in my life that I feel I need to move on from this site. I have been contemplating to myself over the past few weeks if I should, and the more days that pass, the more I feel certain in my decision. It is nothing personal with anyone here, I love this place, and I love all you guys, I just don't feel the same about this place anymore, and visit more out of habit than anything else anymore.

I feel I am getting (actually already are) too old for this anymore, and need would like to move on to different things, and yes, this includes ARC as well. Too be quite honest, I am bored with RPG Maker in general, and have a hard time finding motivation to do anything for it.  It is a shame to back out of ARC when it is so far along, but it feels more like a burden to me now than something I actually enjoy. This is supposed to be a hobby, not something I feel negatively about, and I want to leave before I develop any more feelings of animosity towards it.

I won't be leaving all  abruptly, I will likely be around for a couple more days, and maybe post a few things script related I have not before, but this is my farewell to you all. I think you all for being such a great community, and I wish you all the best of luck in your endeavors.
33
RPG Maker Scripts / Easy RGSS Video Player
April 30, 2012, 02:01:34 am
So I was continuing to fool around with MCI functions after completing my little Audio module rewrite, and I found that it also allows for making the most simple video player in RPG Maker. Seriously, it only takes about 15-20 lines of code to get just about any standard video format to play right in the game window.

Here's an example if anyone wants to see how easy it is.

http://www.mediafire.com/?b8gblyim83m772k

God, I wish I understood Win32API functions better back when I used to write more scripts for RMXP, I could have done so much more...
34
MCI Audio Player
Authors: ForeverZer0
Version: 1.3
Type: Custom Audio Module
Key Term: Game Utility



Introduction

This script acts a either a drop-in replacement or enhancement to the built-in Audio module. It contains a plethora of functions that the default player lacks, such as seek, pause, record, fade in/out, and many more. It works by totally bypassing the built-in audio library, and directly accessing Window's "winmm" library using Ruby's Win32API. This library is home to the Media Control Interface, or MCI, which provides functions for manipulating audio and video. This allows for much more control over sound, and the ability for RPG Maker to play additional audio formats, since all that is needed is to distribute the appropriate codecs along with your game in order to use them.


Features


  • Full seek functions, accurate to the millisecond

  • Ability to read file lengths

  • Ability to pause and resume a playing file

  • Functions for transitioning from one volume to another over a given number of frames, to both lower and higher volumes

  • Can create as many mixers as needed, which allows to play multiple sounds simultaneously, which gives the ability to play more than one BGM or BGS at a time

  • Record function to capture input from the user (.wav format only)

  • Ability to set volume to left and right speaker independently

  • Mute functions

  • Can set the speed of playback

  • Ability to set treble and bass (Not all devices support this)

  • Searches RTP files and uses them automatically if file is not local

  • Easy access for additional calls to the Media Control Interface

  • No porting external libraries with your game, all functioning is done within the script and the operating system

  • Can use any audio format you wish, so long as the appropriate codec is installed on the host computer

  • Compatibility with RMXP, RMVX, and RMVXA

  • Memorize/Restore audio on all/some channels




Screenshots

SAMPLE ONLY Incomplete Audio Player (XP): ShowHide



Demo

Demo Link (RMXP)(1.3)


Script

Spoiler: ShowHide
#=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
# MCI Audio Player
# Author: ForeverZer0
# Version: 1.3
# Date: 7.5.2014
#=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
#                             VERSION HISTORY
#=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
# v.1.0   4.29.2012
#   - Original Release
#
# v.1.1   4.29.2012
#   - Fixed a typo
#   - Added instructions for ensuring all channels stop when player closes game
#   - Added RPG Maker VX compatibility
#   - Added RPG Maker VX Ace compatibility
#   - Fixed duration to ensure a minimum of 1 frame, else nothing happens
#   - Added "start position" argument to "play" call. This ensures VXA
#     functionality, as well as a minor improvement to the system
#
# v.1.2   7.8.2012
#   - Fixed incorrect filepaths that mixed forward and backward slashes
#   - Fixed a bug that would cause full paths to files not to play sometimes
#   - Added an enumerator for iterating Audio mixers ("Audio.each_mixer")
#   - Added methods to Game_System for memorizing/restoring audio
#
# v.1.3   7.5.2014
#   - Fixed bug that would cause BGM/BGS to restart from beginning on transfer
#     to new map with same BGM or BGS
#=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
#
# Introduction:
#
#   This script acts a either a drop-in replacement or enhancement to the
#   built-in Audio module. It contains a plethora of functions that the default
#   player lacks, such as seek, pause, record, fade in/out, and many more. It
#   works by totally bypassing the built-in audio library, and directly
#   accessing Window's "winmm" library using Ruby's Win32API. This library is
#   home to the Media Control Interface, or MCI, which provides functions for
#   manipulating audio and video. This allows for much more control over sound,
#   and the ability for RPG Maker to play additional audio formats, since all
#   that is needed is to distribute the appropriate codecs along with your game
#   in order to use them.
#
# Features:
#
#   - Full seek functions, accurate to the millisecond
#   - Ability to read file lengths
#   - Ability to pause and resume a playing file
#   - Functions for transitioning from one volume to another over a given number
#     frames, to both lower and higher volumes
#   - Can create as many mixers as needed, which allows to play multiple sounds
#     simultaneously, which gives the ability to play more than one BGM or BGS
#     at a time
#   - Record function to capture input from the user (.wav format only)
#   - Ability to set volume to left and right speaker independently
#   - Mute functions
#   - Can set the speed of playback
#   - Ability to set treble and bass (Not all devices support this)
#   - Searches RTP files and uses them automatically if file is not local
#   - Easy access for additional calls to the Media Control Interface
#   - No porting external libraries with your game, all functioning is done
#     within the script and the operating system
#   - Can use any audio format you wish, so long as the appropriate codec is
#     installed on the host computer
#   - Full compatibility with RMXP, RMVX, and RMVX Ace
#   - Memorize and restore all/some channels
#
# Instructions:
#
#   - Scroll below to make the setting for what RPG Maker version you are using
#   - Place script anywhere above Main
#   - Only one setting (below) to set the MCI player as default audio player,
#     which is by default "true". If false, the MCI player will only be used for
#     special circumstances via script calls
#   - There are a whole bunch of new script calls available for the Audio module
#     There is full documentation if you look below, which I reccomend that you
#     look at if you choose to use this script, but most are self-explanatory.
#     Here is a partial list, words in caps are arguments that need replaced.

#     - play(FILENAME, VOLUME, SPEED, REPEAT)
#     - pause
#     - restart
#     - pause
#     - resume
#     - stop
#     - close
#     - volume/volume=
#     - set_volume_left(VOLUME)
#     - set_volume_right(VOLUME)
#     - mute
#     - fade(DURATION, FRAMES)
#     - speed/speed=
#     - duration
#     - position/position=
#     - seek(MILLISECOND)
#     - playing?
#     - paused?
#     - recording?
#     - treble/treble=
#     - bass/bass=
#     - status
#     - record(BITS_PER_SAMPLE, SAMPLERATE, CHANNELS)
#     - save(FILENAME)
#     
#     To play a sound on a mixer is pretty straightforward, you don't even need
#     to create a mixer first, that is done automatically. All you need to do
#     is use a unique name for each mixer you want to control, and use the
#     above methods on it. For example, to play a file:
#
#     Audio['myName'].play('myFile.mp3')
#
#     From here on, you can access the same mixer using 'myName' as the key to
#     perform further actions. Such as...
#
#     Audio['myName'].pause            - Pauses playback
#     Audio['myName'].resume           - Resumes playback
#     Audio['myName'].volume = 50      - Sets volume to fifty
#     Audio['myName'].fade(80, 0)      - Fades volume to 0 in 80 frames
#     Audio['myName'].fade(240, 100)   - Transitions volume to 100 in 6 seconds
#     Audio['myName'].record           - Begins recording
#     Audio['myName'].save('file.wav') - Saves recorded file
#     Audio['myName'].seek(4500)       - Sets playback position to 4.5 seconds
#
#     As you can see, all mixers are accessed in a hash-like way via the Audio
#     module. By default, 'BGM', 'BGS', 'ME', and 'SE' are mixers used as
#     replacements for the built-in audio library, so use names other them if
#     creating additional mixers.
#
#     There is also a script call to make a call using mciSendString if you are
#     familiar with the library at all. I simplified it down a bit, but it can
#     be used with the following snippet:
#
#         Audio.mci_eval(MCI_COMMAND)
#
#     For more information about using MCI commands, please see the full
#     documentation at MSDN.
#
# http://msdn.microsoft.com/en-us/library/windows/desktop/dd743572(v=vs.85).aspx
#
#     There are also a few methods available via the Game_System class for
#     memorizing/restoring audio at its current position.
#
#     ex.
#
#     $game_system.memorize_audio               - Memorize all channels
#     $game_system.memorize_audio('BGM')        - Memorize BGM channel
#     $game_system.memorize_audio('BGM', 'BGS') - Memorize BGM and BGS channels
#     $game_system.restore_audio                - Restore all channels
#     $game_system.restore_audio('BGM')         - Restore BGM channel
#     $game_system.restore_audio('BGM', 'BGS')  - Restore BGM and BGS channels
#
#     You can use as many arguments for each method as you wish. Omitting
#     arguments will simply have it memorize/restore all channels.
#
# Compatibility:
#
#   - Not tested on Linux running under Wine. If anyone tests this, let me know.
#   - Not compatible with DREAM.
#
# Credits/Thanks:
#
#   - ForeverZer0, for the script
#
# Authors Notes:
#
#   - Changing pitch will be different. MCI does not have a function for this,
#     so I am changing the speed as a generic substitute. Changing the speed
#     does change the pitch, but it true sound pitch alters the sampling rate
#     as well, which this player does not. You have a couple alternatives if
#     you absolutely need the pitch change:
#
#     1. Edit the files using an external editor and import it
#     2. Use the default system to play such sounds using the alias names.
#
#=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=

#===============================================================================
# ** Audio
#===============================================================================

module Audio

  # Set true/false if the MCI Player should be the default audio controller. It
  # will maintain all the same functionality as the standard control, and all
  # normal calls to the Audio module will work as normal, but it will also
  # extend the its functionality. If false, RMXP's standard library will be used
  # and this player will only be used for custom mixers.
  MCI_DEFAULT = true
 
  # Due to vast differences in how the format is handled, some of this player's
  # features do not work with MIDI, most notably volume control, which also
  # effects fading. I have created alternate controls to control MIDI volume,
  # but they can only work with the sacrifice of many other functions, and the
  # volume applies to ALL playing MIDIs, not just the one the volume is applied
  # to. I decided this was not worth it, so I omitted volume control. If you
  # are willing to make them sacrifices, you can enable this mode by setting
  # MIDI_MODE to true. If you your game relies heavily on MIDI, but you still
  # would like to use this script, there are conversion programs available,
  # which I can assist you with if need be.
  MIDI_MODE = false
 
  # Enter the code for the version of RPG Maker you are using this script for.
  #   RMXP  = 0
  #   RMVX  = 1
  #   RMVXA = 2
  RPG_VERSION = 0
 
#===============================================================================
# ** Mixer
#-------------------------------------------------------------------------------
# This class acts a wrapper for Window's Media Control Interface (MCI).
#===============================================================================

  MCISendString = Win32API.new('winmm', 'mciSendString', 'PPLL', 'L')
  MIDIOutSetVolume = Win32API.new('winmm', 'midiOutSetVolume', 'LL', 'L')

  class Mixer
   
    attr_reader :name           # The arbitrary name of the mixer
    attr_reader :filepath       # The path of the currently loaded file
    attr_reader :repeat         # Flag if playback is set to repeat
    attr_reader :filename       # Name of the file being played
   
    #---------------------------------------------------------------------------
    # * Object Initialization
    #     name    : The unique name of the mixer
    #---------------------------------------------------------------------------
    def initialize(name)
      @name = name
      @fade_duration = 0
      @fade_volume = 0
      @opened = false
      @repeat = false
      @midi = false
    end
    #---------------------------------------------------------------------------
    # * Load a file and prepare for playback
    #     filename  : The path to the file.
    #---------------------------------------------------------------------------
    def open(filename)
      if File.exists?(filename)
        path = filename
      else
        path = Dir::glob(filename + '.*')[0]
        if path == nil
          directory = File.dirname(filename)
          if RTP.subfolder?(directory)
            file = File.basename(filename)
            path = RTP[directory].find {|f| File.basename(f, '.*') == file }
          end
        end
      end
      @filepath = path.gsub(/\\/, '/')
      if MIDI_MODE && ['.mid', '.midi'].include?(File.extname(path))
        @midi = true
        cmd = "open \"#{path}\" type sequencer alias #{@name}"
      else
        cmd = "open \"#{path}\" type mpegvideo alias #{@name}"
      end
      MCISendString.call(cmd, nil, 0, 0)
      MCISendString.call("set #{@name} time format milliseconds", nil, 0, 0)
      MCISendString.call("set #{@name} seek exactly on", nil, 0, 0)
      @opened = true
    end
    #---------------------------------------------------------------------------
    # * Began playback on the mixer
    #     filename  : The name of the file to play
    #     volume    : The volume to play the file at
    #     speed     : The speed to play the the fule at
    #     repeat    : Flag if playback should loop after done playing
    #     start     : The position, in milliseconds, to begin playback at
    #---------------------------------------------------------------------------
    def play(filename, volume = 100, speed = 100, repeat = false, start = 0)
      @filename = filename
      self.close
      self.open(filename)
      self.speed = speed
      if MIDI_MODE && @midi
        @midi_master = @midi_right = @midi_left = volume * 10
        self.set_volume(volume)
        MCISendString.call("play #{@name} from 0", nil, 0, 0)
        return
      end
      self.set_volume(volume)
      @repeat = repeat
      if start != 0
        MCISendString.call("seek #{@name} to #{start}", nil, 0, 0)
      else
        MCISendString.call("seek #{@name} to start", nil, 0, 0)
      end
      MCISendString.call("play #{@name}#{repeat ? ' repeat' : ''}", nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Restarts playback of the currently loaded file from the beginning
    #---------------------------------------------------------------------------
    def restart
      MCISendString.call("seek #{@name} to start", nil, 0, 0)
      MCISendString.call("play #{@name}#{repeat ? ' repeat' : ''}", nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Pause playback and maintain current position
    #---------------------------------------------------------------------------
    def pause
      MCISendString.call("pause #{@name}", nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Resume playback on a paused mixer from previous position
    #---------------------------------------------------------------------------
    def resume
      MCISendString.call("resume #{@name}", nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Stops playback, setting position back to the start
    #---------------------------------------------------------------------------
    def stop
      MCISendString.call("seek #{@name} to start", nil, 0, 0)
      MCISendString.call("stop #{@name}", nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Closes the opened file and frees it from memory
    #---------------------------------------------------------------------------
    def close
      MCISendString.call("close #{@name}", nil, 0, 0)
      @filepath = nil
      @opened = false
    end
    #---------------------------------------------------------------------------
    # * Gets the actual volume of the mixer, an integer from 0 to 1000
    #---------------------------------------------------------------------------
    def real_volume
      if MIDI_MODE && @midi
        return @midi_master
      else
        data = "\0" * 128
        MCISendString.call("status #{@name} volume", data, 128, 0)
        return data.delete("\0").to_i
      end
    end
    #---------------------------------------------------------------------------
    # * Sets the actual volume of the mixer
    #     value    : The volume level, integer between 0 and 1000
    #---------------------------------------------------------------------------
    def real_volume=(value)
      self.set_real_volume(value)
    end
    #---------------------------------------------------------------------------
    # * Sets the actual volume of the mixer
    #     value    : The volume level, integer between 0 and 1000
    #---------------------------------------------------------------------------
    def set_real_volume(value)
      vol = [0, [value, 1000].min].max
      if MIDI_MODE && @midi
        @midi_master = value
        self.set_midi_volume(value, value)
      else
        MCISendString.call("setaudio #{@name} volume to #{vol}", nil, 0, 0)
      end
    end
    #---------------------------------------------------------------------------
    # * Returns the volume of the mixer
    #---------------------------------------------------------------------------
    def volume
      return self.real_volume / 10   
    end
    #---------------------------------------------------------------------------
    # * Sets the volume of the mixer
    #     value    : The volume level, integer between 0 and 100
    #---------------------------------------------------------------------------
    def volume=(value)
      value = [0, [value, 100].min].max
      self.set_real_volume(value * 10)
    end
    #---------------------------------------------------------------------------
    # * Sets the volume of the mixer
    #     value    : The volume level, integer between 0 and 100
    #---------------------------------------------------------------------------
    def set_volume(value)
      value = [0, [value, 100].min].max
      self.set_real_volume(value * 10)
    end
    #---------------------------------------------------------------------------
    # * Set the volume of the mixer in the left speaker only
    #     value   : Volume level, integer between 0 and 100
    #---------------------------------------------------------------------------
    def set_volume_left(value)
      vol = [0, [value * 10, 1000].min].max
      if MIDI_MODE && @midi
        self.set_midi_volume(value, @midi_right)
      else
        MCISendString.call("setaudio #{@name} left volume to #{vol}", nil, 0, 0)
      end
    end
    #---------------------------------------------------------------------------
    # * Set the volume of the mixer in the right speaker only
    #     value   : Volume level, integer between 0 and 100
    #---------------------------------------------------------------------------
    def set_volume_right(value)
      vol = [0, [value * 10, 1000].min].max
      if MIDI_MODE && @midi
        self.set_midi_volume(@midi_left, value)
      else
        MCISendString.call("setaudio #{@name} right volume to #{vol}", nil, 0, 0)
      end
    end
    #---------------------------------------------------------------------------
    # * Special handling for adjusting MIDI volume. MCI cannot handle the volume
    #   for this format directly, so we need to precalculate the channels and
    #   make the call to the MIDI synthesizer ourselves.
    #     left    : The volume of the left channel
    #     right   : The volume of the right channel
    #
    #   NOTE:
    #   It is recommended that you do not call this method directly.
    #---------------------------------------------------------------------------
    def set_midi_volume(left, right)
      @midi_left, @midi_right = left, right
      left = (0xFFFF * (left / 1000.0)).round
      right = (0xFFFF * (right / 1000.0)).round
      vol = right.to_s(16) + left.to_s(16)
      MIDIOutSetVolume.call(0, vol.to_i(16))
    end
    #---------------------------------------------------------------------------
    # * Mutes sound from the mixer
    #     bool    : True/false flag to mute/unmute sound
    #---------------------------------------------------------------------------
    def mute(bool)
      MCISendString.call("setaudio #{@name} #{bool ? 'on' : 'off'}", nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Transition volume to another volume
    #     duration    : The number of frames the transition will take
    #     target      : The target volume to transition to
    #---------------------------------------------------------------------------
    def fade(duration, target = 0)
      @fade_volume = target * 10
      @fade_duration = [duration, 1].max
    end
    #---------------------------------------------------------------------------
    # * Returns the current speed of playback  (100 = normal)
    #---------------------------------------------------------------------------
    def speed
      data = "\0" * 256
      MCISendString.call("status #{@name} speed", data, 256, 0)
      data.delete!("\0")
      return data.to_i / 10
    end
    #---------------------------------------------------------------------------
    # * Set the current speed of playback
    #     value   : The rate of playback to set
    #---------------------------------------------------------------------------
    def speed=(value)
      set_speed(value)
    end
    #---------------------------------------------------------------------------
    # * Set the current speed of playback
    #     value   : The rate of playback to set
    #---------------------------------------------------------------------------
    def set_speed(value)
      value = [0, [2000, value * 10].min].max
      MCISendString.call("set #{@name} speed #{value}", nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Gets the length of the loaded file in milliseconds
    #---------------------------------------------------------------------------
    def duration
      if self.playing?
        length = "\0" * 256
        MCISendString.call("status #{@name} length", length, 256, 0)
        length.delete!("\0")
        return length.to_i
      end
      return 0
    end
    #---------------------------------------------------------------------------
    # * Returns duration as a string in normal MM:SS format
    #---------------------------------------------------------------------------
    def duration_string
      seconds = self.duration / 1000
      return sprintf('%2d:%02d', seconds / 60, seconds % 60)
    end
    #---------------------------------------------------------------------------
    # * Returns the current position of playback, in milliseconds
    #---------------------------------------------------------------------------
    def position
      pos = "\0" * 256
      MCISendString.call("status #{@name} position", pos, 256, 0)
      pos.delete!("\0")
      return pos.to_i
    end
    #---------------------------------------------------------------------------
    # * Returns current position as a string in normal MM:SS format
    #---------------------------------------------------------------------------
    def position_string
      seconds = self.position / 1000
      return sprintf('%2d:%02d', seconds / 60, seconds % 60)
    end
    #---------------------------------------------------------------------------
    # * Sets the current playback position
    #     value   : The time in milliseconds to set current playback
    #---------------------------------------------------------------------------
    def position=(value)
      self.seek(value)
    end
    #---------------------------------------------------------------------------
    # * Sets the current playback position
    #     value   : The time in milliseconds to set current playback
    #---------------------------------------------------------------------------
    def seek(value)
      cmd = "#{self.playing? ? 'play' : 'seek'} #{@name} from #{value}"
      MCISendString.call(cmd, nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Returns tha "playing" status of the mixer
    #---------------------------------------------------------------------------
    def playing?
      return self.status == 'playing'
    end
    #---------------------------------------------------------------------------
    # * Returns tha "paused" status of the mixer
    #---------------------------------------------------------------------------
    def paused?
      return self.status == 'paused'
    end
    #---------------------------------------------------------------------------
    # * Returns true/false if file is currently loaded for playback
    #---------------------------------------------------------------------------
    def opened?
      return @opened
    end
    #---------------------------------------------------------------------------
    # * Returns true/false if mixer is currently recording
    #---------------------------------------------------------------------------
    def recording?
      return self.status == 'recording'
    end
    #---------------------------------------------------------------------------
    # * Returns the mixer's bass value
    #---------------------------------------------------------------------------
    def treble
      data = "\0" * 128
      MCISendString.call("status #{@name} treble", data, 128, 0)
      data.delete!("\0")
      return data.to_i
    end
    #---------------------------------------------------------------------------
    # * Set mixer treble
    #     value   : Treble value, integer between 0 and 1000
    #---------------------------------------------------------------------------
    def treble=(value)
      set_treble(value)
    end
    #---------------------------------------------------------------------------
    # * Set mixer treble
    #     value   : Treble value, integer between 0 and 1000
    #---------------------------------------------------------------------------
    def set_treble(value)
      value = [0, [value, 1000].min].max
      MCISendString.call("setaudio #{@name} treble to #{value}", nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Returns the mixer's bass value
    #---------------------------------------------------------------------------
    def bass
      data = "\0" * 128
      MCISendString.call("status #{@name} bass", data, 128, 0)
      data.delete!("\0")
      return data.to_i
    end
    #---------------------------------------------------------------------------
    # * Set mixer bass
    #     value   : Bass value, integer between 0 and 1000
    #---------------------------------------------------------------------------
    def bass=(value)
      set_bass(value)
    end
    #---------------------------------------------------------------------------
    # * Set mixer bass
    #     value   : Bass value, integer between 0 and 1000
    #---------------------------------------------------------------------------
    def set_bass(value)
      value = [0, [value, 1000].min].max
      MCISendString.call("setaudio #{@name} bass to #{value}", nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Gets the current status
    #---------------------------------------------------------------------------
    def status
      data = "\0" * 256
      MCISendString.call("status #{@name} mode", data, 256, 0)
      return data.delete("\0")
    end
    #---------------------------------------------------------------------------
    # * Begins recording from the input, typically the PC's microphone
    #     bits_ps     : Bits per sample the file will be recorded at
    #     sample_rate : Sample rate the the file will be recorded at
    #     channels    : Number of channels that will be opened for recording
    #
    #   * WARNING *
    #     Make sure that "stop", "close" or "save" is performed on this mixer
    #     within a reasonable of amount of time. While the mixer is recording,
    #     the file is held in RAM, which will become very large if left without
    #     closing it, and eventually slow down the PC and/or crash the game.
    #     Basically I'm just saying "don't forget you are recording"
    #---------------------------------------------------------------------------
    def record(bits_ps = 16, sample_rate = 44100, channels = 2)
      self.close
      MCISendString.call("open new type waveaudio alias #{@name}", nil, 0, 0)
      MCISendString.call("set #{@name} bitspersample #{bits_ps}", nil, 0, 0)
      MCISendString.call("set #{@name} samplespersec #{sample_rate}", nil, 0, 0)
      MCISendString.call("set #{@name} channels #{channels}", nil, 0, 0)
      MCISendString.call("record #{@name}", nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Saves a recording into WAV format
    #     filename  : The path of the file t save, must have '.wav' extension
    #---------------------------------------------------------------------------
    def save(filename)
      if self.recording?
        MCISendString.call("stop #{@name}", nil, 0, 0)
      end
      if File.extname(filename) != '.wav'
        filename += '.wav'
      end
      MCISendString.call("save #{@name} #{filename}", nil, 0, 0)
      MCISendString.call("close #{@name}", nil, 0, 0)
    end
    #---------------------------------------------------------------------------
    # * Frame update
    #---------------------------------------------------------------------------
    def update
      if @fade_duration >= 1
        d = @fade_duration
        self.set_real_volume((self.real_volume * (d - 1) + @fade_volume) / d)
        @fade_duration -= 1
      end
    end
  end

#===============================================================================
# ** Audio
#-------------------------------------------------------------------------------
# The metaclass of the Audio module. This class is a wrapper between the default
# audio controls and the MCI Player controls.
#===============================================================================
 
  class << self
    #---------------------------------------------------------------------------
    # * Use MCI Player play function
    #---------------------------------------------------------------------------
    alias mci_bgm_play bgm_play
    def bgm_play(filename, volume = 100, pitch = 100, start = 0)
      if MCI_DEFAULT
        mixer_play('BGM', filename, volume, pitch, true, start)
      elsif RPG_VERSION == 2
        mci_bgm_play(filename, volume, pitch, start)
      else
        mci_bgm_play(filename, volume, pitch)
      end
    end
    #---------------------------------------------------------------------------
    # * Use MCI Player play function
    #---------------------------------------------------------------------------
    alias mci_bgs_play bgs_play
    def bgs_play(filename, volume = 100, pitch = 100, start = 0)
      if MCI_DEFAULT
        mixer_play('BGS', filename, volume, pitch, true, start)
      elsif RPG_VERSION == 2
        mci_bgs_play(filename, volume, pitch, start)
      else
        mci_bgs_play(filename, volume, pitch)
      end
    end
    #---------------------------------------------------------------------------
    # * Use MCI Player play function
    #---------------------------------------------------------------------------
    alias mci_me_play me_play
    def me_play(filename, volume = 100, pitch = 100, start = 0)
      if MCI_DEFAULT
        mixer_play('ME', filename, volume, pitch, false, start)
      elsif RPG_VERSION == 2
        mci_me_play(filename, volume, pitch, start)
      else
        mci_me_play(filename, volume, pitch)
      end
    end
    #---------------------------------------------------------------------------
    # * Use MCI Player play function
    #---------------------------------------------------------------------------
    alias mci_se_play se_play
    def se_play(filename, volume = 100, pitch = 100, start = 0)
      if MCI_DEFAULT
        mixer_play('SE', filename, volume, pitch, false, start)
      elsif RPG_VERSION == 2
        mci_se_play(filename, volume, pitch, start)
      else
        mci_se_play(filename, volume, pitch, start)
      end
    end
    #---------------------------------------------------------------------------
    # Use MCI Player to play a file on a mixer using given parameters
    #---------------------------------------------------------------------------
    def mixer_play(mixer_name, filename, volume, pitch, repeat, start = 0)
      if ['BGM', 'BGS'].include?(mixer_name)
        return if self[mixer_name].filename == filename
      end
      self[mixer_name].play(filename, volume, pitch, repeat, start)
    end
    #---------------------------------------------------------------------------
    # * Use MCI Player stop
    #---------------------------------------------------------------------------
    alias mci_bgm_stop bgm_stop
    def bgm_stop
      MCI_DEFAULT ? @mixers['BGM'].stop : mci_bgm_stop
    end
    #---------------------------------------------------------------------------
    # * Use MCI Player stop
    #---------------------------------------------------------------------------
    alias mci_bgs_stop bgs_stop
    def bgs_stop
      MCI_DEFAULT ? @mixers['BGS'].stop : mci_bgs_stop
    end
    #---------------------------------------------------------------------------
    # * Use MCI Player stop
    #---------------------------------------------------------------------------
    alias mci_me_stop me_stop
    def me_stop
      MCI_DEFAULT ? @mixers['ME'].stop : mci_me_stop
    end
    #---------------------------------------------------------------------------
    # * Use MCI Player stop
    #---------------------------------------------------------------------------
    alias mci_se_stop se_stop
    def se_stop
      MCI_DEFAULT ? @mixers['SE'].stop : mci_se_stop
    end
    #---------------------------------------------------------------------------
    # * Use MCI Player fade
    #---------------------------------------------------------------------------
    alias mci_bgm_fade bgm_fade
    def bgm_fade(time)
      rate = RPG_VERSION == 0 ? 40 : 60
      MCI_DEFAULT ? @mixers['BGM'].fade((time / 1000) * rate) :
        mci_bgm_fade(time)
    end
    #---------------------------------------------------------------------------
    # * Use MCI Player fade
    #---------------------------------------------------------------------------
    alias mci_bgs_fade bgs_fade
    def bgs_fade(time)
      rate = RPG_VERSION == 0 ? 40 : 60
      MCI_DEFAULT ? @mixers['BGS'].fade((time / 1000) * rate) :
        mci_bgs_fade(time)
    end
    #---------------------------------------------------------------------------
    # * Use MCI Player fade
    #---------------------------------------------------------------------------
    alias mci_me_fade me_fade
    def me_fade(time)
      rate = RPG_VERSION == 0 ? 40 : 60
      MCI_DEFAULT ? @mixers['ME'].fade((time / 1000) * rate) :
        mci_me_fade(time)
    end
  end
  #-----------------------------------------------------------------------------
  # * Gives hash-type access of the mixers of the module
  #-----------------------------------------------------------------------------
  def self.[](mixer_name)
    unless @mixers.has_key?(mixer_name)
      @mixers[mixer_name] = Mixer.new(mixer_name)
    end
    return @mixers[mixer_name]
  end
  #-----------------------------------------------------------------------------
  # * Frame update
  #-----------------------------------------------------------------------------
  def self.update
    @mixers.each_value {|mixer| mixer.update }
  end
  #-----------------------------------------------------------------------------
  # * Simplified method for making calls directly to the Media Command Interface
  #-----------------------------------------------------------------------------
  def self.mci_eval(command)
    data = "\0" * 256
    MCISendString.call(command, data, 256, 0)
    return data.delete("\0")
  end
  #-----------------------------------------------------------------------------
  # * Iterator for the Audio mixers
  #-----------------------------------------------------------------------------
  def self.each_mixer
    @mixers.each_value {|mixer| yield mixer }
  end
  #-----------------------------------------------------------------------------
  # * Object initialization
  #-----------------------------------------------------------------------------
  def self.init
    if @mixers != nil
      # Don't remove this, it prevents memory leaks when F12 us used to restart
      MCISendString.call('close all', nil, 0, 0)
    end
    @mixers = {}
    ['BGM', 'BGS', 'ME', 'SE'].each {|name| @mixers[name] = Mixer.new(name) }
  end 
end

#===============================================================================
# ** Graphics
#-------------------------------------------------------------------------------
# Syncs the audio update used for fade effects with the frame update
#===============================================================================
module Graphics
 
  class << self
   
    alias mci_player_update update
    def update
      mci_player_update
      Audio.update
    end
  end
end

#===============================================================================
# ** RTP
#-------------------------------------------------------------------------------
# Provides functions for getting the games RTP path(s) and files
#===============================================================================

module RTP
 
  # RMXP
  if Audio::RPG_VERSION == 0
    SUBFOLDERS = [
      'Graphics/Animations', 'Graphics/Autotiles', 'Graphics/Battlebacks',
      'Graphics/Battlers', 'Graphics/Characters', 'Graphics/Fogs',
      'Graphics/Gameovers', 'Graphics/Icons', 'Graphics/Panoramas',
      'Graphics/Pictures', 'Graphics/Tilesets', 'Graphics/Titles',
      'Graphics/Transitions', 'Graphics/Windowskins', 'Audio/BGM',
      'Audio/BGS', 'Audio/ME', 'Audio/SE'
    ]
  # RMVX
  elsif Audio::RPG_VERSION == 1
    SUBFOLDERS = [
      'Graphics/Animations', 'Graphics/Battlers', 'Graphics/Characters',
      'Graphics/Faces', 'Graphics/Parallaxes', 'Graphics/Pictures',
      'Graphics/System', 'Audio/BGM', 'Audio/BGS', 'Audio/ME', 'Audio/SE'
    ]
  # RMVXA
  elsif Audio::RPG_VERSION == 2
    SUBFOLDERS = [
      'Graphics/Animations', 'Graphics/Battlers', 'Graphics/Characters',
      'Graphics/Faces', 'Graphics/Parallaxes', 'Graphics/Pictures',
      'Graphics/System', 'Audio/BGM', 'Audio/BGS', 'Audio/ME', 'Audio/SE'
    ]
  end
  #-----------------------------------------------------------------------------
  # * Object initialization
  #-----------------------------------------------------------------------------
  def self.init
    @ini = Win32API.new('kernel32', 'GetPrivateProfileStringA', 'PPPPLP', 'L')
    @library = "\0" * 256
    @ini.call('Game', 'Library', '', @library, 256, '.\\Game.ini')
    @library.delete!("\0")
    @rtp_path = Win32API.new(@library, 'RGSSGetRTPPath', 'L', 'L')
    @path_with_rtp = Win32API.new(@library, 'RGSSGetPathWithRTP', 'L', 'P')
    @directories = {}
    SUBFOLDERS.each {|folder| @directories[folder] = entries(folder) }
    @initialized = true
  end
  #-----------------------------------------------------------------------------
  # * Returns an array of the full paths of all the game's installed RTPs
  #-----------------------------------------------------------------------------
  def self.paths
    paths = [1, 2, 3].collect {|id| @path_with_rtp.call(@rtp_path.call(id)) }
    paths = paths.find_all {|path| path != '' }
    # This is kind of a crappy way of doing this until the RMVX call works...
    common = File.join(ENV['CommonProgramFiles'], 'Enterbrain')
    common = case Audio::RPG_VERSION
    when 0 then File.join(common, 'RGSS', 'Standard')
    when 1 then File.join(common, 'RGSS2', 'RPGVX')
    when 2 then File.join(common, 'RGSS3', 'RPGVXAce')
    end
    if !paths.include?(common) && File.directory?(common)
      paths.push(common)
    end
    return paths
  end
  #-----------------------------------------------------------------------------
  # * Gives hash-like access to the RTP subfolders
  #-----------------------------------------------------------------------------
  def self.[](folder)
    return subfolder?(folder) ? @directories[folder] : []
  end
  #-----------------------------------------------------------------------------
  # * Returns true/false if the given subfolder exists
  #-----------------------------------------------------------------------------
  def self.subfolder?(folder)
    return @directories.has_key?(folder)
  end
  #-----------------------------------------------------------------------------
  # * Get a complete list of full paths of files found in the given subfolder
  #   subfolder   : The RTP folder whose files you want to get
  #-----------------------------------------------------------------------------
  def self.entries(subfolder)
    files = []
    paths.each {|path|
      dir = path + '\\' + subfolder
      if File.directory?(dir)
        files = (Dir.entries(dir) - ['.', '..']).collect {|f| dir + '\\' + f }
      end
    }
    return files
  end
end

#===============================================================================
# ** Game_System
#===============================================================================

class Game_System
  #-----------------------------------------------------------------------------
  # * Public Instance Variables
  #-----------------------------------------------------------------------------
  attr_accessor :memorized_audio
  #-----------------------------------------------------------------------------
  # * Memorize Audio
  #      channels : Names of channels, or omit argument to memorize all channels
  #-----------------------------------------------------------------------------
  def memorize_audio(*channels)
    @audio_memory = {}
    if channels.empty?
      Audio.each_mixer {|m|
        data = [m.filepath, m.volume, m.speed, m.repeat, m.position]
        @audio_memory[m.name] = data
      }
    else
      channels.each {|channel|
        m = Audio[channel]
        data = [m.filepath, m.volume, m.speed, m.repeat, m.position]
        @audio_memory[channel] = data
      }
    end
  end
  #-----------------------------------------------------------------------------
  # * Restore Audio
  #      channels : Names of channels, or omit argument to restore all channels
  #-----------------------------------------------------------------------------
  def restore_audio(*channels)
    unless @audio_memory == nil || @audio_memory.empty?
      keys = channels.empty? ? @audio_memory.keys : channels
      keys.each {|name|
        data = @audio_memory[name]
        if data != nil && data[0] != nil
          Audio[name].play(data[0], data[1], data[2], data[3])
          Audio[name].seek(data[4])
          @audio_memory.delete(name)
        end
      }
    end
  end
end

# Intialize the MCI Player
RTP.init
Audio.init


by Blizzard: If you have issues with SE channel, here's an additional snippet that won't stop playing SEs when new SEs are started. Put it before the line that says RPG.init

Spoiler: ShowHide

module Audio

  class << self
   
    @@counter = 0
   
    def mixer_play(mixer_name, filename, volume, pitch, repeat, start = 0)
      if ['BGM', 'BGS'].include?(mixer_name)
        return if self[mixer_name].filename == filename
      end
      if mixer_name != 'SE'
        self[mixer_name].play(filename, volume, pitch, repeat, start)
      else
        @@counter += 1
        mixer = Mixer.new("#{mixer_name}_#{@@counter}")
        mixers = self[mixer_name]
        mixers.push(mixer)
        mixer.play(filename, volume, pitch, repeat, start)
      end
    end
   
    def se_stop
      MCI_DEFAULT ? @mixers['SE'].each {|mixer| mixer.stop} : mci_se_stop
    end
   
  end
 
  def self.[](mixer_name)
    unless @mixers.has_key?(mixer_name)
      if mixer_name != 'SE'
        @mixers[mixer_name] = Mixer.new(mixer_name)
      else
        @mixers[mixer_name] = []
      end
    end
    return @mixers[mixer_name]
  end
 
  def self.update
    self.each_mixer {|mixer| mixer.update }
    @mixers.each {|key, mixer|
      if key != 'SE'
        mixer.update
      else
        removed_mixers = []
        mixer.each {|se_mixer|
          se_mixer.update
          removed_mixers.push(se_mixer) if !se_mixer.playing?
        }
        removed_mixers.each {|se_mixer|
          se_mixer.close
          mixer.delete(se_mixer)
        }
      end
    }
  end
 
  def self.each_mixer
    @mixers.each {|key, mixer|
      if key != 'SE'
        yield mixer
      else
        mixer.each {|se_mixer| yield se_mixer }
      end
    }
  end

  def self.init
    if @mixers != nil
      # Don't remove this, it prevents memory leaks when F12 us used to restart
      MCISendString.call('close all', nil, 0, 0)
    end
    @mixers = {}
    ['BGM', 'BGS', 'ME'].each {|name| @mixers[name] = Mixer.new(name) }
    @mixers['SE'] = []
  end 
 
end



Instructions

Simply set the code in the configuration to what version of RPG Maker you are using.
See script for detailed instructions on scrip calls available to you, and demo for examples of a few.

On some systems, audio can continue to play after the RGSS player has closed. To prevent this, add the following line to the botton of "Main", after all the code:

Audio.mci_eval('close all')




Compatibility


  • Not tested on Linux running under Wine. I don't have a VM installed at the present time, so if anyone tests this, let me know.

  • High chance of incompatibility with programs that encrypt audio files

  • Due to vast differences in how the format is handled, some of this player's features do not work with MIDI, most notably volume control, which also effects fading. I have created alternate controls to control MIDI volume, but they can only work with the sacrifice of many other functions, and the volume applies to ALL playing MIDIs, not just the one the volume is applied to. I decided this was not worth it, so I omitted volume control of MIDI by default, but if you are willing to make these sacrifices, there is a setting to enable it. If you your game relies heavily on MIDI, but you still would like to use this script, there are conversion programs available, which I can assist you with if need be.




Credits and Thanks


  • ForeverZer0, for the script

  • Blizzard, for the additional SE patch




Author's Notes

If you are looking for a good codec pack, I recommend K-Lite Codec Pack. This is a single package that will cover pretty much every standard audio format available, and even a few exotics (especially with the Mega-Pack).

Changing pitch will be different. MCI does not have a function for this, so I am changing the speed as a generic substitute. Changing the speed does change the pitch, but it true sound pitch alters the sampling rate as well, which this player does not. You have a couple alternatives if you absolutely need the pitch change:


  • Edit the files using an external editor and import it

  • Use the default system to play such sounds using the alias names



For more information about using MCI commands, please see the full documentation at MSDN.

Most audio formats should play by default on most systems, but most notably is a lack of an OGG codec that will be used by default.
If your OGG files fail to play, download and install the codec found here.

OpenCodecs (2.53 MB)(x86/x64)
35
I know this is more of a a general Ruby question, but it part of a script I was messing around with.
Basically I'm making a wrapper for mciSendString to invoke Windows audio library using Win32API so that I can make a replacement Audio module for XP/VX that has a lot more functions to it. All went pretty well, and most of the actual functionality is complete, I even made a little wrapper for the default Audio module so that it works with the current functions, but I ran into a bug that I have been trying to figure out for the past few hours to no avail.

What's happening is when a sound effect is played (it likely does it with everything, just stands out the most with SE), it sounds as if the file is being played twice in rapid succession, milliseconds from each other. I have stared at my code and looked at it repeatedly, and cannot see anywhere that that the file is being played twice.

If someone with a fresh set of eyes and a basic understanding of mciSendString could take a look and see what I am doing wrong, I would be most grateful. I have it set so that you can press CTRL to play the cursor SE, or simply open the menu and scroll through the options to hear what I am talking about. The majority of the code is in the Audio::Channel script, and the two method that need picked on are "open" and "play".

Here's a link to the demo.  http://www.mediafire.com/?5499pygnqkbwaaq
36
RMXP Script Database / [XP][VX] Data Backup Utility
April 15, 2012, 10:51:27 pm
Data Backup Utility
Authors: ForeverZer0
Version: 1.0
Type: File Backup Utility
Key Term: Game Utility



Introduction

Simple script for creating backups of your game each time the game is ran in debug mode that I pulled out of the archives. Its runs very quickly and there is practically no slowdown, even with large games. There isn't really a whole lot else to talk about.


Features


  • Place script anywhere above "Main"

  • Configure the number of backups you would like to keep.

  • Backups will be stored in the "Backups" folder in the main game directory, and are always listed in order of newest to oldest




Screenshots

None.


Demo

None.


Script

Spoiler: ShowHide
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
# Data Backup Utility
# Author: ForeverZer0
# Date: 4.15.2012
# Version: 1.0
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
#
# Explanation:
#   Simple script for creating backups of your game each time the game is ran
#   in debug mode. Its runs very quickly and there is practically no slowdown,
#   even with large games.
#
# Features:
#   - Backups your Data folder automatically each debug run
#   - Configurable number of backups
#   - Runs on a separate thread and invokes system functions for the actual
#     processing to prevent any slowdown
#
# Instructions:
#   - Place script anywhere above "Main"
#   - Configure the number of backups you would like to keep.
#   - Backups will be stored in the "Backups" folder in the main game directory,
#     and are always listed in order of newest to oldest
#
# Credit/Thanks:
#   - ForeverZer0, for the script
#
# Authors Notes:
#   - Please report any bugs issues at www.chaos-project.com
#
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:

module Backup
 
  MAX_BACKUPS = 10
 
  def self.create
    system("rd /s/q \"Backups\\Backup #{MAX_BACKUPS}\"")
    (1...MAX_BACKUPS).to_a.reverse.each {|i|
      dir_name = "Backups/Backup #{i}"
      Dir.mkdir(dir_name) unless File.directory?(dir_name)
      File.rename(dir_name, "Backups/Backup #{i + 1}")
    }
    system('xcopy Data "Backups\\Backup 1" /Y/D/I')
  end
end

if $DEBUG
  Thread.new { Backup.create }
end



Instructions


  • Place script anywhere above "Main"

  • Configure the number of backups you would like to keep.

  • Backups will be stored in the "Backups" folder in the main game directory, and are always listed in order of newest to oldest




Compatibility

Will work with any Windows system, so long as your game contains a "Data" folder.


Credits and Thanks


  • ForeverZer0, for the script




Author's Notes

Please report any bugs issues at www.chaos-project.com.
Enjoy!
37
RMXP Script Database / [XP] Item Weight
April 15, 2012, 07:13:11 pm
Item Weight
Authors: ForeverZer0
Version: 1.0
Type: Item/Equipment Add-On
Key Term: Player / Party / Troop Add-on



Introduction

This system provides your game with an inventory "weight" feature. Every item and piece of equipment can be configured with an individual weight that provides a different dynamic to collecting items, since the player will have to manage their inventories instead of just collecting everything in sight. Settings for can be made for managing it on a "per actor basis", and various states can be applied when a character/party is "overweight".


Features


  • States can be applied to the whole party or individual actor basis

  • Every item, weapon, and armor can have a unique weight

  • Unlimited number of states

  • Can us a dynamic weight capacity that grows with actor power, or static capacity that you can control yourself via simple script calls

  • Automatic setting of game variables that are equal to the party's current weight and total capacity

  • Configurable modifier that allows for defining the rate of dynamic weight capacity based off actor strength

  • Automatic adding of weight to item descriptions if desired so that the player is always aware of each item's weight

  • Configuration for allowing or not items to be picked up by party or equipped by actors if weight would exceed capacity




Screenshots

None.


Demo

None.


Script

Spoiler: ShowHide
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
# Item Weight
# Author: ForeverZer0
# Date: 4.15.2012
# Version: 1.0
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
#                           VERSION HISTORY
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
# v.1.0
#   - Original release
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
#
# Explanation:
#   This system provides your game with an inventory "weight" feature. Every
#   item and piece of equipment can be configured with an individual weight that
#   provides a different dynamic to collecting items, since the player will have
#   to manage their inventories instead of just collecting everything in sight.
#   Settings for can be made for managing it on a "per actor basis", and various
#   states can be applied when a character/party is "overweight".
#
# Features:
#   - States can be applied to the whole party or individual actor basis
#   - Every item, weapon, and armor can have a unique weight
#   - Unlimited number of states
#   - Can us a dynamic weight capacity that grows with actor power, or static
#     capacity that you can control yourself via simple script calls
#   - Automcatic setting of game variables that are equal to the party's current
#     weight and total capacity
#   - Configurable modifier that allows for defining the rate of dynamic weight
#     capacity based off actor strength
#   - Automatic adding of weight to item descriptions if desired so that the
#     player is always aware of each item's weight
#   - Configuration for allowing or not items to be picked up by party or
#     equipped by actors if weight would exceed capacity
#    
# Instructions:
#   - Place script below default scripts, and above "Main"
#   - See below and find the "Weight" module. There are a few simple settings
#     that can be made with detailed descriptions of each
#   - Configure item weights in the RPG::Item, RPG::Weapon, and RPG::Armor
#     classes found below
#   - When using STATIC_CAPACITY and you would like to change an actor's
#     carrying capacity, use these script calls:
#
#         $game_party.actors[ACTOR_INDEX].weight_capacity = VALUE
#                         OR
#         $game_actors[ACTOR_ID].weight_capacity = VALUE
#
#
#
# Compatibility:
#   - Custom CMS's (specifically the equip part of it), could possibly cause
#     problems, and would require minor edits to ensure that items that are too
#     heavy could not be equipped when OVERWEIGHT_ACTOR is false.
#
# Credits/Thanks:
#   - ForeverZer0, for the script
#   - Bigfoot, for requesting it
#
# Author's Notes:
#   - Please report any bugs/issues to www.chaos-project.com or via email:
#     foreverzer0@chaos-project.com
#
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
#                          BEGIN CONFIGURATION
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:

#===============================================================================
# Weight
#-------------------------------------------------------------------------------
# Module for configuring various weight settings
#===============================================================================

module Weight
 
 # Set to true/false if actor weight capacity grows with the actor's
 # strength, or remains a fixed number (can be changed via script call)
 DYNAMIC_CAPACITY = false
 
 # Define the modifier for the DYNAMIC_CAPACITY. This value will be multiplied
 # by the actor's strength to determine their carrying capacity. Ignore this
 # setting if DYNAMIC_CAPACITY is false.
 DYNAMIC_MODIFIER = 1.5
 
 # Define the static carrying capacity that actors begin with. This value can
 # only be changed via script call, and will not grow with the actor's power.
 # Ignore this setting if DYNAMIC_CAPACITY is true.
 STATIC_CAPACITY = 4.0
 
 # Include the IDs of any states that will be applied when
 #cweight exceeds maximum capacity.
 OVERWEIGHT_STATES = [2, 3]
 
 # Set to true/false if individual actors can become overweight, or if it is
 # only on a "whole party" basis. The entire party will still be afflicted with
 # states if the total weight exceeds the party's capacity. In other words,
 # define if actor's can equip items that are too heavy for them.
 OVERWEIGHT_ACTOR = true
 
 # Determines if items/equipment can still be gained when current weight would
 # exceed total carrying capacity after picking it up. The maximum number that
 # can be added will still be received if this is false and receiving multiple
 # quantities. In other words, can items still be picked up that are too
 # heavy for the party.
 OVERWEIGHT_PARTY = false
 
 # Set the ID of the variable that will be equal to the party's current weight
 CURRENT_VARIABLE = 10
 
 # Set the ID of the variable that will be equal to the party's total capacity
 CAPACITY_VARIABLE = 11
 
 # Set to true/false if item weights should automatically be added to the
 # description for help menu's, etc.
 WEIGHT_DESCRIPTION = true
 
 # Determines the modification of the item's description. Ignore if
 # WEIGHT_DESCRIPTION is false.
 # EXAMPLE: "[#{weight} lbs] #{text}"
 def self.description(text, weight)
   return "#{text} (#{weight} kg)"
 end
end

#===============================================================================
# * RPG::Item
#===============================================================================
module RPG
 class Item
   #---------------------------------------------------------------------------
   # * weight
   #     Define the weights of items (when ITEM_ID then WEIGHT)
   #---------------------------------------------------------------------------
   def weight
     return case @id
     when 1 then 0.5
     when 2 then 0.75
     when 3 then 1.0
     when 4 then 1.0
     when 5 then 1.0
     when 6 then 1.0
     when 7 then 1.0
     when 8 then 1.0
     when 9 then 1.0
     when 10 then 1.0
     else 1.0
     end
   end
   #---------------------------------------------------------------------------
   # * description
   #     Returns the modified description when WEIGHT_DESCRIPTION is true
   #---------------------------------------------------------------------------
   def description
     return !Weight::WEIGHT_DESCRIPTION ? @description :
       Weight.description(@description, weight)  
   end
 end
#===============================================================================
# * RPG::Weapon
#===============================================================================
 class Weapon
   #---------------------------------------------------------------------------
   # * weight
   #     Define the weights of weapons (when WEAPON_ID then WEIGHT)
   #---------------------------------------------------------------------------
   def weight
     return case @id
     when 1 then 1.0
     when 2 then 1.0
     when 3 then 1.0
     when 4 then 1.0
     when 5 then 1.0
     when 6 then 1.0
     when 7 then 1.0
     when 8 then 1.0
     when 9 then 1.0
     when 10 then 1.0
     else 1.0
     end
   end
   #---------------------------------------------------------------------------
   # * description
   #     Returns the modified description when WEIGHT_DESCRIPTION is true
   #---------------------------------------------------------------------------
   def description
     return !Weight::WEIGHT_DESCRIPTION ? @description :
       Weight.description(@description, weight)  
   end
 end
#===============================================================================
# * RPG::Armor
#===============================================================================
 class Armor
   #---------------------------------------------------------------------------
   # * weight
   #     Define the weights of armors (when ARMOR_ID then WEIGHT)
   #---------------------------------------------------------------------------
   def weight
     return case @id
     when 1 then 1.0
     when 2 then 1.0
     when 3 then 1.0
     when 4 then 1.0
     when 5 then 1.0
     when 6 then 1.0
     when 7 then 1.0
     when 8 then 1.0
     when 9 then 1.0
     when 10 then 1.0
     when 29 then 2.0
     else 1.0
     end
   end
   #---------------------------------------------------------------------------
   # * description
   #     Returns the modified description when WEIGHT_DESCRIPTION is true
   #---------------------------------------------------------------------------
   def description
     return !Weight::WEIGHT_DESCRIPTION ? @description :
       Weight.description(@description, weight)  
   end
 end
end

#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
#                            END CONFIGURATION
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:

#===============================================================================
# * Game_Actor
#===============================================================================

class Game_Actor
 #-----------------------------------------------------------------------------
 # * initailize
 #     Aliased method to add capacity variable to Game_Actor, which is used
 #     when using STATIC_CAPACITY.
 #-----------------------------------------------------------------------------
 alias inventory_weight_init initialize
 def initialize(actor_id)
   inventory_weight_init(actor_id)
   @capacity = Weight::STATIC_CAPACITY
 end
 #-----------------------------------------------------------------------------
 # * weight
 #     Returns the total weight of all equipped items the actor has
 #-----------------------------------------------------------------------------
 def weight
   weight = 0
   equipment = [
     $data_weapons[@weapon_id],
     $data_armors[@armor1_id],
     $data_armors[@armor2_id],
     $data_armors[@armor3_id],
     $data_armors[@armor4_id]
   ]
   equipment.each {|item| weight += (item != nil ? item.weight : 0) }
   return weight
 end
 #-----------------------------------------------------------------------------
 # * weight_capacity=
 #     Sets the carrying capacity of the actor when using STATIC_CAPACITY
 #-----------------------------------------------------------------------------
 def weight_capacity=(capacity)
   @capacity = capacity
 end
 #-----------------------------------------------------------------------------
 # * weight_capacity
 #     Returns the amount of weight the actor can carry
 #-----------------------------------------------------------------------------
 def weight_capacity
   if Weight::DYNAMIC_CAPACITY
     return base_str * Weight::DYNAMIC_MODIFIER
   else
     return @capacity
   end
 end
 #-----------------------------------------------------------------------------
 # * within_capacity?
 #     Factors in weight when determining if piece of equipment is equippable
 #     or not.
 #-----------------------------------------------------------------------------
 def equippable_weight?(item)
   return true if item == nil || Weight::OVERWEIGHT_ACTOR
   actor_weight = self.weight + item.weight
   if item.is_a?(RPG::Weapon)
     weapon = $data_weapons[@weapon_id]
     actor_weight -= (weapon == nil ? 0 : weapon.weight)
   elsif item.is_a?(RPG::Armor)
     case item.kind
     when 0 # Armor
       armor = $data_armors[@armor1_id]
     when 1 # Shield
       armor = $data_armors[@armor2_id]
     when 2 # Helmet
       armor = $data_armors[@armor3_id]
     when 3 # Accessory
       armor = $data_armors[@armor4_id]
     end
     actor_weight -= (armor == nil ? 0 : armor.weight)
   end
   return actor_weight <= weight_capacity
 end
 #-----------------------------------------------------------------------------
 # * equip
 #     Refreshes party weight and states after item change
 #-----------------------------------------------------------------------------
 alias item_weight_equip equip
 def equip(kind, id)
   item = kind == 0 ? $data_weapons[id] : $data_armors[id]
   if equippable_weight?(item)
     item_weight_equip(kind, id)
     $game_party.refresh_weight
   end
 end
end

#===============================================================================
# * Game_Party
#===============================================================================

class Game_Party
 #-----------------------------------------------------------------------------
 # * weight_capacity
 #     Returns the cumulative weight capacity of all current party members
 #-----------------------------------------------------------------------------
 def weight_capacity
   weight = 0
   @actors.each {|actor| weight += actor.weight_capacity }
   return weight
 end
 #-----------------------------------------------------------------------------
 # * actor_weight
 #     Returns the total weight of all equipment worn by party members
 #-----------------------------------------------------------------------------
 def actor_weight
   weight = 0
   @actors.each {|actor| weight += actor.weight }
   return weight
 end
 #-----------------------------------------------------------------------------
 # * item_weight
 #     Returns the total weight of all items in inventory
 #-----------------------------------------------------------------------------
 def item_weight
   weight = 0
   @items.each_pair {|id, qty| weight += $data_items[id].weight * qty }
   return weight
 end
 #-----------------------------------------------------------------------------
 # * weapon_weight
 #     Returns the total weight of all weapons in inventory
 #-----------------------------------------------------------------------------
 def weapon_weight
   weight = 0
   @weapons.each_pair {|id, qty| weight += $data_weapons[id].weight * qty }
   return weight
 end
 #-----------------------------------------------------------------------------
 # * armor_weight
 #     Returns the total weight of all armors in inventory
 #-----------------------------------------------------------------------------
 def armor_weight
   weight = 0
   @armors.each_pair {|id, qty| weight += $data_armors[id].weight * qty }
   return weight
 end
 #-----------------------------------------------------------------------------
 # * total_weight
 #     Returns the total weight of all inventory and equipment that is
 #     equipped by the party members
 #-----------------------------------------------------------------------------
 def total_weight
   return actor_weight + item_weight + weapon_weight + armor_weight
 end
 #-----------------------------------------------------------------------------
 # * gain_item
 #     Aliased method to determine if party can add an item to inventory when
 #     ALLOW_OVERWHEIGHT is set to false. The maximum quantity that can fit
 #     will be added out of the total quanity if capacity would be exceeded.
 #-----------------------------------------------------------------------------
 alias item_weight_gain_item gain_item
 def gain_item(id, quantity)
   if Weight::OVERWEIGHT_PARTY
     item_weight_gain_item(id, quantity)
   else
     item = $data_items[id]
     weight = item == nil ? 0 : item.weight
     if !enough_capacity?(weight * quantity)
       allowed = (weight_capacity - total_weight) / weight
       item_weight_gain_item(id, allowed.floor)
     else
       item_weight_gain_item(id, quantity)
     end
   end
   refresh_weight
 end
 #-----------------------------------------------------------------------------
 # * gain_weapon
 #     Aliased method to determine if party can add a weapon to inventory when
 #     ALLOW_OVERWHEIGHT is set to false. The maximum quantity that can fit
 #     will be added out of the total quanity if capacity would be exceeded.
 #-----------------------------------------------------------------------------
 alias item_weight_gain_weapon gain_weapon
 def gain_weapon(id, quantity)
   if Weight::OVERWEIGHT_PARTY
     item_weight_gain_weapon(id, quantity)
   else
     weapon = $data_weapons[id]
     weight = weapon == nil ? 0 : weapon.weight
     if !enough_capacity?(weight * quantity)
       allowed = (weight_capacity - total_weight) / weight
       item_weight_gain_weapon(id, allowed.floor)
     else
       item_weight_gain_weapon(id, quantity)
     end
   end
   refresh_weight
 end
 #-----------------------------------------------------------------------------
 # * gain_armor
 #     Aliased method to determine if party can add an armor to inventory when
 #     ALLOW_OVERWHEIGHT is set to false. The maximum quantity that can fit
 #     will be added out of the total quanity if capacity would be exceeded.
 #-----------------------------------------------------------------------------
 alias item_weight_gain_armor gain_armor
 def gain_armor(id, quantity)
   if Weight::OVERWEIGHT_PARTY
     item_weight_gain_armor(id, quantity)
   else
     armor = $data_armors[id]
     weight = armor == nil ? 0 : armor.weight
     if !enough_capacity?(weight * quantity)
       allowed = (weight_capacity - total_weight) / weight
       item_weight_gain_armor(id, allowed.floor)
     else
       item_weight_gain_armor(id, quantity)
     end
   end
   refresh_weight
 end  
 #-----------------------------------------------------------------------------
 # * add_actor
 #     Refreshes party weight and states when actor is added to party
 #-----------------------------------------------------------------------------
 alias item_weight_add_actor add_actor
 def add_actor(actor_id)
   item_weight_add_actor(actor_id)
   refresh_weight
 end
 #-----------------------------------------------------------------------------
 # * remove_actor
 #     Refreshes party weight and states when actor is removed from party
 #-----------------------------------------------------------------------------
 alias item_weight_remove_actor remove_actor
 def remove_actor(actor_id)
   item_weight_remove_actor(actor_id)
   refresh_weight
 end
 #-----------------------------------------------------------------------------
 # * enough_capacity?
 #     Returns true/false if given weight would not exceed capacity
 #-----------------------------------------------------------------------------
 def enough_capacity?(weight)
   return (total_weight + weight) <= weight_capacity
 end
 #-----------------------------------------------------------------------------
 # * refresh_weight
 #     Refreshes the weight variables and adds/removes weight states
 #-----------------------------------------------------------------------------
 def refresh_weight
   total, capacity = total_weight, weight_capacity
   $game_variables[Weight::CURRENT_VARIABLE] = total
   $game_variables[Weight::CAPACITY_VARIABLE] = capacity
   # Add/remove states to party as a whole
   if Weight::OVERWEIGHT_PARTY && total > capacity
     @actors.each {|actor|
       Weight::OVERWEIGHT_STATES.each {|state_id| actor.add_state(state_id) }
     }
   # Add/remove individual states for actors
   elsif Weight::OVERWEIGHT_ACTOR
     @actors.each {|actor|
       if actor.weight > actor.weight_capacity
         Weight::OVERWEIGHT_STATES.each {|state_id| actor.add_state(state_id) }
       else
         Weight::OVERWEIGHT_STATES.each {|state_id| actor.remove_state(state_id) }
       end
     }
   else
     @actors.each {|actor|
       Weight::OVERWEIGHT_STATES.each {|state_id| actor.remove_state(state_id) }
     }
   end
 end
 #-----------------------------------------------------------------------------
 # * setup_starting_members
 #     Alias method to set the game variables at the beginning of the game
 #-----------------------------------------------------------------------------
 alias item_weight_setup_starting_members setup_starting_members
 def setup_starting_members
   item_weight_setup_starting_members
   refresh_weight
 end
end

#===============================================================================
# * Scene_Equip
#-------------------------------------------------------------------------------
# This needs to be here more or less just to what can only be considered either
# bad coding or a bug in RMXP. The "equip" method of Game_Actor is constantly
# called whenever an item is highlighted in Scene_Equip, and this is kind of
# a little bypass for that.
#===============================================================================

class Scene_Equip
 #-----------------------------------------------------------------------------
 # * update_item
 #     Cancels equipping item if configured to do so and item would put
 #     actor overweight
 #-----------------------------------------------------------------------------
 alias item_weight_update_item update_item
 def update_item
   if Input.trigger?(Input::C)
     item = @item_window.item
     unless @actor.equippable_weight?(item)
       $game_system.se_play($data_system.buzzer_se)
       return
     end
   end
   item_weight_update_item
 end
end

   




Add-Ons

These are some add-ons to the system to either augment the script, or fix conflicts with other scripts. Unless otherwise instructed, these add-ons will all be placed under the main script in the editor.

Default Shop System Fix
This add-on will prevent the purchasing of items that would put the party overweight when OVERWEIGHT_PARTY is false. It also adds a nice display to the shop screen that will show the player the weight/capacity ratio of the selected quantity.

Screenshot: ShowHide

Script: ShowHide
#===============================================================================
# * Scene_Shop
#===============================================================================

class Scene_Shop
 #-----------------------------------------------------------------------------
 # * update_number
 #     Prevents purchasing of items when OVERWEIGHT_PARTY is true and number
 #     of items to buy would exceed maximum weight
 #-----------------------------------------------------------------------------
 alias item_weight_update_number update_number
 def update_number
   unless Weight::OVERWEIGHT_PARTY
     if Input.trigger?(Input::C) && @command_window.index == 0
       weight = @item.weight * @number_window.number
       weight += $game_party.total_weight
       if weight > $game_party.weight_capacity
         $game_system.se_play($data_system.buzzer_se)
         return
       end
     end
   end
   item_weight_update_number
 end
end

#===============================================================================
# * Window_ShopNumber
#===============================================================================

class Window_ShopNumber
 #-----------------------------------------------------------------------------
 # * refresh
 #     Adds a weight display to the number screen at the shop
 #-----------------------------------------------------------------------------
 alias item_weight_refresh refresh
 def refresh
   item_weight_refresh
   weight = (@item.weight * @number) + $game_party.total_weight
   capacity = $game_party.weight_capacity
   self.contents.draw_text(4, 192, 72, 32, 'Weight:')
   color = weight > capacity ? crisis_color : normal_color
   self.contents.font.color = color
   self.contents.draw_text(76, 192, 64, 32, weight.to_s, 2)
   self.contents.font.color = normal_color
   self.contents.draw_text(144, 192, 64, 32, '/ ' + capacity.to_s)
 end
end


Default Menu Display
Adds a display to the default menu system that shows the weight/capacity of each actor.

Screenshot: ShowHide

Script: ShowHide
#===============================================================================
# * Window_Base
#===============================================================================

class Window_Base
 #-----------------------------------------------------------------------------
 # * draw_actor_weight
 #     Draws the actor's weight/capacity at given location
 #-----------------------------------------------------------------------------
 def draw_actor_weight(actor, x, y, width = 144)
   self.contents.font.color = system_color
   self.contents.draw_text(x, y, 32, 32, 'WT')
   color = actor.weight > actor.weight_capacity ? crisis_color : normal_color
   self.contents.font.color = color
   if width - 32 >= 108
     wt_x = x + width - 108
     flag = true
   elsif width - 32 >= 48
     wt_x = x + width - 48
     flag = false
   end    
   self.contents.draw_text(wt_x, y, 48, 32, actor.weight.to_s, 2)
   if flag
     self.contents.font.color = normal_color
     self.contents.draw_text(wt_x + 48, y, 12, 32, '/', 1)
     self.contents.draw_text(wt_x + 60, y, 48, 32, actor.weight_capacity.to_s)
   end
 end
end

#===============================================================================
# * Window_MenuStatus
#===============================================================================

class Window_MenuStatus
 #-----------------------------------------------------------------------------
 # * refresh
 #     Draws each actor's weight/capacity on the menu
 #-----------------------------------------------------------------------------
 alias item_weight_refresh refresh
 def refresh
   item_weight_refresh
   $game_party.actors.each_index {|i|
     draw_actor_weight($game_party.actors[i], 300, i * 116) }
 end
end


Simple HUD
This is a simple HUD that can be displayed on the screen in the location of your choice. It can either be as a small window, or simple text on the screen. The font can also be changed as desired, and there is a script call for hiding/showing it.

Screenshot - No Window: ShowHide

Screenshot - Window: ShowHide

Script: ShowHide
#===============================================================================
# * WeightHUD
#===============================================================================

class WeightHUD < Window_Base
 
  # Set true/false if windowskin should be used or not. If not, text will simply
  # be displayed on the screen.
  WINDOWED = true
 
  # Set the location of the HUD. [X, Y, WIDTH, HEIGHT]
  # I recommend a small X and Y offset if WINDOWED is set to false to have
  # the text placed properly and not to far off the edge of the screen.
  LOCATION = [0, 0, 144, 64]
 
  # Set the font used for the HUD. [FONT_NAME, FONT_SIZE]
  # A value of nil for either setting will have it simply use the default font
  FONT = ['Calibri', 20]
 
  # Script Calls:
  #   hide_weightHUD(true/false) - Sets the hidden state of the weight HUD
 
  #-----------------------------------------------------------------------------
  # * initialize
  #     Creates a new instance of the HUD
  #-----------------------------------------------------------------------------
  def initialize
    super(*LOCATION)
    self.windowskin = nil unless WINDOWED
    self.contents = Bitmap.new(width - 32, height - 32)
    self.contents.font.name = FONT[0] == nil ? Font.default_name : FONT[0]
    self.contents.font.size = FONT[1] == nil ? Font.default_size : FONT[1]
    refresh
  end
  #-----------------------------------------------------------------------------
  # * refresh
  #   Clears and redraws the HUD
  #-----------------------------------------------------------------------------
  def refresh
    self.contents.clear
    self.contents.font.color = system_color
    self.contents.draw_text(0, 0, 32, 32, 'WT')
    weight, capacity = $game_party.total_weight, $game_party.weight_capacity
    color = weight > capacity ? crisis_color : normal_color
    self.contents.font.color = color
    self.contents.draw_text(32, 0, 42, 32, weight.to_s, 2)
    self.contents.font.color = normal_color
    self.contents.draw_text(74, 0, 8, 32, '/', 1)
    self.contents.draw_text(82, 0, 42, 32, capacity.to_s)
  end
end

#===============================================================================
# * Game_Party
#===============================================================================

class Game_Party
  #-----------------------------------------------------------------------------
  # * refresh_weight
  #     Tells Scene_Map that the HUD needs refresh when the values change
  #-----------------------------------------------------------------------------
  alias weight_hud_refresh_weight refresh_weight
  def refresh_weight
    weight_hud_refresh_weight
    if $scene.is_a?(Scene_Map)
      $scene.refresh_weightHUD
    end
  end
end

#===============================================================================
# * Scene_Map
#===============================================================================

class Scene_Map
  #-----------------------------------------------------------------------------
  # * main
  #     Creates the HUD and disposes it when the scene ends
  #-----------------------------------------------------------------------------
  alias item_weight_main main
  def main
    @weight_hud = WeightHUD.new
    item_weight_main
    @weight_hud.dispose
  end
  #-----------------------------------------------------------------------------
  # * hide_weightHUD
  #     Hides/Shows the weight HUD if it is present and not disposed
  #-----------------------------------------------------------------------------
  def hide_weightHUD(bool)
    if @weight_hud != nil && !@weight_hud.disposed?
      @weight_hud.visible = bool
    end
  end
  #-----------------------------------------------------------------------------
  # * refresh_weightHUD
  #     Refreshes the weight HUD if it is present and not disposed
  #-----------------------------------------------------------------------------
  def refresh_weightHUD
    if @weight_hud != nil && !@weight_hud.disposed?
      @weight_hud.refresh
    end
  end
end

#===============================================================================
# * Interpreter
#===============================================================================

class Interpreter
  #-----------------------------------------------------------------------------
  # * hide_weightHUD
  #     Hides/Shows the weight HUD if it is present and not disposed
  #-----------------------------------------------------------------------------
  def hide_weightHUD(value = true)
    if $scene.is_a?(Scene_Map)
      $scene.hide_weightHUD(value)
    end
  end
end




Instructions

Simple configuration, which can be found in the script.


Compatibility

Possible compatibility issues with actor equipping issues in custom menu systems. (See script for explanation)
If you have a problem with a custom CMS, make a post about it and see if it can be fixed, which should be quite simple.


Credits and Thanks


  • ForeverZer0, for the script

  • Bigfoot, for requesting it




Author's Notes

Please report any issues/bugs you may come across so they can be addressed.
Enjoy! Main
38
Chat / WTF...
April 12, 2012, 06:02:38 pm
Seriously. Here is my latest email from DropBox...

Spoiler: ShowHide


I have no what "excessive" traffic my DropBox is getting, but this is bullshit.
39
Pandora's Box




Introduction

This is an extremely large collection of resources for RPG Maker. I did not create, nor compile this collection, that credit goes to Guyver IV, the creator of the video. I have seen the link posted about the forum in various places, but have not seen a dedicated topic to it, so here we are. The original collection was posted on YouTube video, which can be found here. There collection consists of basically every resource found around the RM community in one package, so it is a nice one-stop-shop.



Statistics

Total Size: 5.79 GB (uncompressed)
Total Folders: 1,487
Total Files: 140,588

Key:
Resource Type: Number of files (Size on disk)

Animations: 1,140 (450 MB)
Audio Files: 27,573 (1.15 GB)
Autotiles: 3,124 (16.3 MB)
Backgrounds: 965 (138 MB)
Battlers: 11,760 (341 MB)
Characters: 18,008 (361 MB)
Faces: 2,860 (104 MB)
Fogs: 160 (19.3 MB)
Gameovers: 182 (40.3 MB)
Icons: 24,920 (122 MB)
Pictures: 613 (33.7 MB)
Scripts: 422 (342 MB)
Tilesets: 13,417 (1.32 GB)
Titles: 25 (13 MB)
Transitions: 367 (66.3 MB)
Windowskins: 769 (14.7 MB)
Game Rips (Various): 34,283 (1.26 GB)



Download Links

The first download links are ones I created myself. Here are the changes I made:


  • All JPEG, GIF, and bitmap files have been converted to PNG

  • I ran every PNG file (a few hundred thousand...) through PngOptimizer which reduces the file size. This is a great little program that removes usless information from PNG files and can shrink them without any quality loss.

  • I converted all MP3 and WAV files to OGG, which is a much more efficient format for games. The audio quality has been unchanged, just the format changed. MIDI files have been left alone

  • I used WinUHA for audio compression, because it gets a higher compression level than for media formats, even better than 7zip under "Ultra" settings and a large dictionary/word size

  • Aside from these changes, everything has been left untouched, but the overall size of the download is more than a 1 GB less

  • The download is a self-extracting archive, so no program will be required for decompression. Simply click and extract to where you want.



Torrent Download
I have also created a torrent download for the file, since it is a much more suited protocol for large downloads. The more people that download and seed, the faster the download will go. If you need a torrent client, I highly recommend utorrent, which is completely free and in my opinion the best.

Torrent Download


Original Links from YouTube
The following are the original links on the YouTube page. All downloads are through 4shared. The files are in .7z format and split into 7 files. You will need to download 7-zip, WinRAR, or similar file archiver to combine and decompress the archives. 7zip is free to everyone, and there is absolutely no cost. You will also need to register an account with 4shared to download from these links, which is also free, albeit annoying.
Part 1 • Part 2 • Part 3 • Part 4 • Part 5 • Part 6 • Part 7
40
Core Development / Wow, do I feel rusty...
March 18, 2012, 02:46:01 pm
So I opened up the solution for the editor today, and I forget soooo much. It may take a few days or a week to get back in full rhythm, so bear with me, please.

On another note, since my last time working on this, I reinstalled my OS, VS2010, Python, and libraries, etc, etc.
It seems I am rather retarded, because I cannot get the project to start a test-run. It keeps complaining about a failed DLL load for _PyXAL. I believe I have everything set back up correctly, and yet it is still doing it. Am I missing something?
41
RMXP Script Database / [XP][VX] Screen Module
March 11, 2012, 12:03:23 am
Screen Module
Authors: ForeverZer0
Version: 1.0
Type: Game Window Add-On
Key Term: Game Utility



Introduction

I was playing around with some API functions, and I thought of this. It is a static module for creating some various effects on the actual RGSS Player window instead of the game screen. This is not for every game obviously, but I'm sure someone might find it useful. There are only a few effects at the moment, but if I can think of anymore that might actually apply to a game, I'll add them in real quick.


Features


  • Move screen

  • Vibrate screen (same as screen shake, but for the window)

  • Get name of game

  • Possible more to come




Screenshots




Demo

Here be a demo link.


Script

Here be a script: ShowHide
#+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
# Screen Module
# Author: ForeverZer0
# Version: 1.0
# Date: 3.10.2012
#+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
#
# Introduction:
#   This is a static module for creating some various effects on the actual
#   RGSS Player window instead of the game screen.
#
# Features:
#   - Move screen
#   - Vibrate screen
#   - Get name of game
#   - Possible more to come
#
# Instructions:
#   - Use the following script calls:
#
# Screen.move(X, Y[, HANDLE])
# - Moves the screen to the given location
# X : The x-coordinate on the screen to move to
# Y : The y-coordinate on the screen to move to
# HANDLE : Optional argument to choose the window to move. If omitted
# the game window will be used
#
# Screen.shake(POWER, SPEED, DURATION[, HANDLE])
# - Shakes the window, using same formula as RGSS, but with vertical shake
# POWER : The amount of pixels the window can move
# SPEED : The speed to apply the shake
# DURATION : The number of frames to shake the window for
# HANDLE : Optional argument to choose the window to move. If omitted
# the game window will be used
#
#   Screen.name
# - Gets the name of the game found in the Game.ini file
#
# Screen.shaking?
# - Returns true/false if window is shaking
#
# Compatibility:
#   No compatibility issues with other scripts. Some effects either won't work
# or appear strange when game is full screen mode. (Alt + Enter)
#
# Credits/Thanks:
#   - ForeverZer0, for the script
#
#+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+


#==============================================================================
# ** Screen
#------------------------------------------------------------------------------
#  This module performs calls the the underlying Windows API for commands
#  to the external window(s) on the platform
#==============================================================================

module Screen
 
 # Defines the calls to the Windows API

 MoveWindow = Win32API.new('user32', 'MoveWindow', 'LLLLL', 'I')
 GetWindowRect = Win32API.new('user32','GetWindowRect', 'LP', 'I')
 FindWindow = Win32API.new('user32', 'FindWindow', 'PP', 'I')
 GetPrivateProfileString = Win32API.new('kernel32',
   'GetPrivateProfileString','PPPPLP', 'L')
 
 #--------------------------------------------------------------------------
 # Initialize the module
 #--------------------------------------------------------------------------
 def self.init
   # Find the handle for the RMXP window and store it
   @title = "\0" * 256
   GetPrivateProfileString.call('Game', 'Title', '', @title, 256, '.\\Game.ini')
   @title.delete!("\0")
   @hwnd = FindWindow.call('RGSS Player', @title)
   @shaking = false
 end
 #--------------------------------------------------------------------------
 # Get the name of the game
 #--------------------------------------------------------------------------
 def name
   return @title
 end
 #--------------------------------------------------------------------------
 # Start shaking
 #     power : The strength of the shake
 #     speed : The speed of the movement
 #     duration : The number of frames the shake lasts
 #--------------------------------------------------------------------------
 def self.shake(power, speed, duration, handle = @hwnd)
   # If screen is already shaking, end method, else set flag
   return if @shaking
   @shaking = true
   # Calculate milliseconds of a game frame
   delay = 1.0 / Graphics.frame_rate
   # Represents the upper-left and bottom-right corners of a RECT structure
   x1, y1, x2, y2 = self.window_rect
   width, height = x2 - x1, y2 - y1
   # Set initial values for the shake process
   shake_x, shake_y = 0, 0
   direction_x = direction_y = 1
   power_y = (power * 8) / 7
   # Process movement on an asynchronous thread
   Thread.new do
     # Loop until duration reaches 0
     while duration > 0
       # Calcluate the movement on the x-axis
       if duration >= 1 || shake_x != x1
         delta = (power * speed * direction_x) / 10.0
         if duration <= 1 && shake_x * (shake_x + delta) < 0
           shake_x = x1
         else
           shake_x += delta
         end
         direction_x = -1 if shake_x  > power * 2
         direction_x = 1 if shake_x < - power * 2
       end
       # Calcluate the movement on the y-axis
       if duration >= 1 || shake_y != y1
         delta = (power_y * (speed + 1) * direction_y) / 10.0
         if duration <= 1 && shake_y * (shake_y + delta) < 0
           shake_y = y1
         else
           shake_y += delta
         end
         direction_y = -1 if shake_y > power_y * 1.5
         direction_y = 1 if shake_y < -power_y * 1.5
       end
       # Decrement the duration, move the window, and delay the thread
       duration -= 1
       MoveWindow.call(@hwnd, x1 + shake_x, y1 + shake_y, width, height)
       sleep(delay)
     end
     # Ensure window is back in its original place and disable flag
     MoveWindow.call(@hwnd, x1, y1, width, height)
     @shaking = false
   end
 end
 #--------------------------------------------------------------------------
 # Is screen shaking?
 #--------------------------------------------------------------------------
 def self.shaking?
   return @shaking
 end
 #--------------------------------------------------------------------------
 # Get a handle's RECT structure
 #     handle : The window handle to get the RECT of
 #--------------------------------------------------------------------------
 def self.window_rect(handle = @hwnd)
   rect = [0, 0, 0, 0].pack('l4')
   GetWindowRect.call(handle, rect)  
   return rect.unpack('l4')
 end
 #--------------------------------------------------------------------------
 # Moves a window to the specified coordinates
 #     x : The screen coordinate on the horizontal axis
 #     y : The screen coordinate on the vertical axis
 #     handle : A handle for a window
 #--------------------------------------------------------------------------
 def self.move_window(x, y, handle = @hwnd)
   x1, y1, x2, y2 = self.window_rect
   MoveWindow(handle, x, y, x2 - x1, y2 - y1)
 end
end

Screen.init



Instructions

In the script.


Compatibility

No known script incompatibilities, though possible with certain custom resolution scripts.
These effects are designed to be used in windowed mode, not fullscreen. They may appear strange when used in fullscreen or not work at all.


Credits and Thanks


  • ForeverZer0




Author's Notes

If you find any bugs or have an idea for an additional feature, be sure to let me know.
42
Development Tools / [C#] Spritesheet Splitter
March 09, 2012, 07:08:58 pm
Spritesheet Splitter
Authors: ForeverZer0
Version: 1.1



Introduction

This is actually something I made a some time ago, but never released. It is pretty simple, it allows you to split large tile sheets into individual files. Essentially does the same thing as this script I wrote, except it has some additional file formats for output and a GUI. My plan back then was to include the "combining" feature, but I never got around to it, hence the program was forgotten about and I never posted.


Features


  • Splits large spritesheets into individual files in the blink of an eye

  • 6 supported input/output formats: PNG, JPEG, GIF, Icon, TIFF, and Bitmap

  • Can split file using either width and height of tiles, or by number of rows and columns

  • Easy to use interface

  • Awesome icon




Screenshots

Spoiler: ShowHide

Spoiler: ShowHide



Download

ImageSplitter.exe (178 KB)


Compatibility

Requires Microsoft's .NET Framework 2.0 or higher.


Credits and Thanks


  • ForeverZer0




Author's Notes

I will likely not be updating this project at all, unless it is an overlooked bug that renders it unusable. If you do find such a bug, please let me know.
Enjoy!

EDIT:
I lied. I added a progress bar real quick and have the conversion on a separate asynchronous thread now. This will keep the application from locking up during a large conversion.
43
Development Tools / RMXP MapExtractor - BETA
February 22, 2012, 12:40:45 am
MapExtractor
Authors: ForeverZer0
Version: 0.93
Type: Advanced Map Image Extractor



Introduction

This is small utility program I wrote in C# to easily extract maps from RPG Maker XP's .rxdata files and convert them to images to use for screenshots or whatever else you may need them for. It supports 7 different output formats and batch conversions. The program also is completely portable and does not write data anywhere to your registry, AppData folder, etc. There are numerous features (see below) that allow for altering the appearance of the map before saving, without actually having to change the map in the RMXP editor.



Features


  • Seven different output formats: PNG, JPEG, GIF, ICO, BMP, TIFF, WMF

  • Enable/Disable event display

  • Enable/Disable fog display

  • Enable/Disable panorama display

  • Change screen tone

  • Supports event hue, opacity, and blend type (Subtraction blend mode is not yet finished)

  • Tree structure for selecting maps just as it is RMXP

  • Different sizing methods for the map display, including center, zoom, stretch, and fill

  • Intuitive interface for easy use

  • Load projects simply by dropping them onto the form

  • Easily create full-sized screenshots of your maps without using scripts

  • More to come!




Screenshots

Main Form: ShowHide

Batch Conversion: ShowHide

Screen Tone: ShowHide



Download

MapExtractor 0.90 (1.88 MB)(Self-extracting archive)


Dependencies

Requires Microsoft's .NET Framework 4.0


Compatibility

The "Subtraction" blend mode for sprites is not yet finished. I implemented a "negative" of the images for now, which is not an accurate conversion.


Credits and Thanks


  • ForeverZer0

  • Blizzard and winkio, for some help with sprite blend type



Author's Notes

This is a BETA version, and is still incomplete. I do have a few more features I would like to include in addition to fixing the blending issue.

  • Resizing of map images and saving to those dimensions

  • Cropping

  • Importing individual Map###.rxdata files without loading a whole project (maybe)

  • Possible use of a rendering library to improve map speed instead of simply using the built-in GDI+



If you have a any ideas I would be happy to hear them. Keep in mind I have no intention of creating a whole new editor, so suggestions like adding new events, building maps, creating new layers, etc. will be ignored.

Please be sure to report any bugs. I tried a new method of combining many of the libraries into a single executable, which required a lot of trial and error to get a stable build. I did some debugging to try and ensure its stability, but it is possible a few bugs persist, so let me know about any you find.
44
General Discussion / Sprite Blend Mode
February 20, 2012, 06:12:47 pm
I am trying to emulate a similar feature to that of RMXP's "blend_type" for the Sprite class, and I can't seem to get it quite right.  I was curious, does anyone know the calculation that is performed to do the addition and subtraction blends on an image?  I'm using C#, and have been getting familiar with the ColorMatrix class, have created functions for altering brightness, saturation, color blending, opacity, color shearing, contrast, etc., but fail at this seemingly simple function.

I am using for creating a small utility for RMXP, and it is kinda important that it is accurate to the method that RMXP uses. This is basically the final thing to implement, and I can finish up pretty quickly after that.
45
General Discussion / Free File-Sharing Sites
January 21, 2012, 02:46:10 pm
With the closing of MegaUpload, many of you may need to find a new preferred upload site to use.  I'm compiling a small list of the more common ones to help you decide on whats best for you.


  • Dropbox
    This is my personal favorite. You start with 2 GB (2.25 GB if you use the above link), and can earn more. This sets up a folder on your PC that syncs to an online account, so anything you add or change is automatically uploaded to your account. It also has shell integration with Windows, so you can quickly get the download link simply by right-clicking the file and selecting "Copy Public Link". There are a few ways of earning more storage space, the most common way is through referrals, which you will get 250 MB for every person you get to join, up to 8 GB. I currently have 10.75 GB, which you can learn more about maxing it out by checking out this site

  • MediaFire
    Popular site that gives you a free 200 MB of storage. Has a nice interface for uploading and browsing your files, as well.

  • Sendspace
    Pretty straightforward upload site. A free account gets you 500 MB of storage. The website uses simple drag-drop method of uploading files, which is pretty handy.

  • File Factory
    I have never personally used this one, but you get a free 500 MB of storage. There are some minor annoyances with this site for downloaders, such as the infamous "Please wait for 45 seconds for your link" and whatnot, but hey, its free.

  • 4shared
    Never used this one either, but it promises 10 GB of free storage, and seems to be pretty popular.

  • RapidShare
    Offers 500 MB of storage for free. There are limits on maximum file size, and download limits per hour, etc., as well as having to wait for your download.



This not even close to a comprehensive list, just a few of the most popular ones that are easy to join and get started. I'll update with any suggestions or good finds that anyone has to offer.
46
Welcome! / I'm still here.
December 21, 2011, 04:05:59 pm
Sorry for my inactivity the past week, life has been a bit hectic, and I haven't really had the time to be on my PC a lot. I have been busy preparing for Christmas, having multiple birthdays in the family, parties, and fixing my car in the garage, so its not anything bad, just a lot to do.

Never fear, once Christmas is over, life will return to normal and I will pick up my activity. ;)
47
ARC Welder / Scintilla Issues
December 10, 2011, 12:08:49 am
There are a few issues we need to address regarding SciLexer before release.  They are all just cosmetic issues with Ruby syntax highlighting in Ruby. The problem is with the actual library, and is not fixed. Unfortunately, this bug has been present for a while, and there is no future outlook on it being fixed, as can be seen here where one of the developers basically says he has no interest in fixing it.

Here is a little list of the syntax highlighting errors that occur:

  • Keywords after the keyword "def" do not colorize, specifically "def self.method_name".

  • The keywords "if", "unless", "until", and "while" do not colorize when used after the first word of a line.

  • In Ruby range operators ".." and "...", the first dot inherits the color of a number, not an operator.



Now we all know that these issues are fixable, as RMXP and most other programs that use SciLexer have the issue fixed, but unfortunately I cannot fix this on the Python side. The problem is with the optimized way Scintilla searches for what it need to colorize, not any type of rule that can be defined via its Python wrapper, at least as far as I know. As you may have noticed, Gemini suffered from the same problem. I tried replacing the build of SciLexer with the each one of RMXP ,RMVX, and Notepad++ SciLexers, all to no avail. Although some bugs like the "def self.whatever" were fixed, it caused a slew of other coloring bugs, so I didn't use it. 

Anyways, I'm just posting this up to make you all aware. Hopefully SOMEONE on the team who is good with C++ can check into what it would take to get this fixed. ;)
48
ARC Welder / ARCed Audio Player
November 19, 2011, 03:50:58 pm
Alright, so I have been working on the audio player, using pyglet's media module, and have come to the conclusion that it is insufficient for what we need.


  • First and foremost (I should have looked into this sooner), MIDI is not a supported format, neither through pyglet, nor AVbin.

  • I *think* in order for AVbin to play, you need to first start the pyglet loop with "pyglet.app.run()", which we cannot do obviously, we are using wxPython.

  • It basically requires a hack to have events fire properly. Normally, "dispath_events()", which must be called regularly to have events you have binded actually fire, is called via the pyglet app's loop. I already had to make a wxTimer to handle updating for such a minor thing that is handled better in other audio add-ons.
  • Playback is often times very buggy, especially when files are paused, then restarted.

  • I really wanted to have an audio module that better supported reading raw data a little better that I could convert easily into numpy arrays. The reason for this is I planned on implementing a simple spectrogram to provide a visual representation of the stream. Most other audio modules make this conversion relatively simple to do, even pygame's built in audio module, but pyglet lacks any clean way of doing this.



I have been looking into some other modules, but all seem to have a few pros and cons. Here's a a quick summary of a few I found so far.

PyGame.Mixer module
Has the easiest way of converting data to numpy arrays with its sndarray function. Has seek/volume functions, and supports all the file formats that we plan to utilize, and is pretty easy to use. The only real con is missing support of changing pitch. This can still be done by manipulating the arrays, though something a bit cleaner would be nice. If changing pitch gets dropped for the engine, this won't be a ordeal at all. :P

AudioLab
Probably has the most amount of actual function, most of which we won't be using. Biggest drawback is that it is an addon to a SciPy, which is quite q large package that would also need to be included. The current version is only 0.1, so it is also rather immature, though in practice, it seems to work pretty well.

PyAudiere
A rather immature audio module. It really doesn't offer much of anything over the previous two.

PyAudio
A wrapper for PortAudio, a cross-platform audio library. I haven't looked as deep into this one, so I don't have much to say about it yet.


If you can't tell by my descriptions, I am leaning towards PyGame as the player of choice.


Here is a screenshot of what I had for the audio player.
Spoiler: ShowHide

The spectrograph is copy-paste edit, but it will look very similar with a quick plot using matplotlib

49
ARC Welder / Character/Battler Graphics in ARCed
November 14, 2011, 07:00:37 pm
This pertains to displayed graphics in the editor, such as what is found on RMXP's Actor and Enemy panels.

A few exampled of different methods using the same over-sized image in the same-sized box. Keep in mind ARC panels can be resized, and scaling/cropping will be recalculated depending on the window size.

Cropped: ShowHide

Scaled: ShowHide

Bit of Both (RMXP's method): ShowHide
50
Development Tools / [C#] RGB2Hex
October 29, 2011, 12:08:40 am
RGB2Hex
Authors: ForeverZer0
Version: 1.2
Type: Color Converter/Picker



Introduction

This is a basic little app I made some time ago, and just rediscovered on my harddrive. It simply converts color RGB values to hexadecimal ones and vice-versa. There are many little added features that make it quite handy, hence I decided to post it up and share it.


Features


  • Easily converts values between their RGB and hexadecimal values

  • Support for alpha channel

  • Integrated color picker that allows you to simply click a color anywhere on the screen to pick/convert it

  • Integrated color wheel to choose your color from

  • Ability to automatically add prefixes to hexadecimal values (#- and 0x-)

  • Ability to insert various separators between RGB values, as well as surrounding in parenthesis

  • "Copy to Clipboard" button for easy pasting into whatever you need

  • Toggle to enable an "always on top" feature to keep the window from being hidden




Screenshots

Convert RGB to Hex: ShowHide

Convert Hex to RGB: ShowHide



Download

RGB2Hex.exe (213 KB)


Compatibility

Requires Microsoft .NET Framework 2.0 or higher.
51
ARC Welder / Crash When Increasing Capacity
October 14, 2011, 09:17:48 pm
I found a small problem with extending the maximum capacity for actors, classes, weapons, etc. in the editor.  Although it works, there is a limitation on how many objects can be added at one time using the "Change Maximum" method.

I found that when you try to increase the capacity by much more than 1,000 at a time, the application will crash. I capped the maximum size at 9999, but it is not possible to simple go from say, 200 actors, to 2,000 or more without a crash. It works fine if you add 1,000, which will simply cause an expected second or two of lag while the Actor objects are being created and the list is being populated.

I don't if this information is pertinent or not, but 1,000 actor objects translates into roughly 10 MB of RAM.
52
Event Command Panels




Description

Create windows for all the various event commands that can be used in the editor.



Priority

Medium. They will provide much of the actual functionality to the editor.



Prerequisites

None.



Assigned

ForeverZer0



Everything else

Simply follow the same conventions found in this task.
53
Tasks / [ARCed] Creating Functionality for Database Events
September 25, 2011, 04:38:20 pm
Creating Functionality for Database Events




Description

Obviously, the controls in the database need to reflect the values they represent, and change them accordingly. The events need to be written to provide actual functionality for this by storing the data when values are changed, calling dialogs when buttons are pressed, and writing the data to file when it is saved.



Priority

Medium.



Prerequisites

Database Panels - Finished
MsgPack serialization modules for Python and Ruby - Finished
Editor Dialogs - Finished
Action Framework - Incomplete



Assigned

ForeverZer0



Everything else

This will be a pretty simple task to accomplish once all the prerequisites are met. There is just a lot of events, which will be tedious and repetitive.
54
Finished Tasks / [Finished] [ARCed] Dialogs Layout
September 25, 2011, 04:24:28 pm
Dialogs Layout




Description

There are many different dialogs the editor uses. These need lain out using wxFormBuilder just like the Database panels. All classes need to follow the same naming conventions and have events bound to them to be overridden in their derived classes.



Priority

Medium. They will provide much of the actual functionality to the editor.



Prerequisites

None.



Assigned

ForeverZer0



Everything else

Simply follow the same conventions found in this task.
55
Core Development / Sorry for being lazy for so long.
September 25, 2011, 11:32:09 am
I just wanted to apologize for my few months of not contributing a damn thing to ARC.  I just recently starting working on this again as you all know, and the more I get into it, the worse I feel for being lazy for so long. I just want to state for the record that it will not happen again, and I plan to remain committed to this project until it is done. That means no more starting other side-projects to distract me, they are all going to the back-burner while ARC is still in development.

Once again, I am sorry.
56
ARC Welder / Min/Max Values
September 22, 2011, 08:08:36 pm
I know we plan to eliminate most boundaries and limitations in the editor, and allow for values to be input into it that RMXP does not permit. Obviously, these values are need to have SOME type of limitation though, however crazy high/low it may be.

This can really be broken into a few categories.

String Length: Max number of characters for names, descriptions, ect.
Parameters: ATK, PDEF, etc.  I was thinking using -65535..65535
Percentages: Currently its 0..200. We can obviously bump the max for this up to something more like 1000 ro 10000 at least.
"The skies the limit" values": Things like price, level, gold, experience, etc. We can allow for these to be obsenely high. I suggest the max value of a Ruby Fixnum on an x86 system (2147483647)(I think, I have x64, but did the math...). I would have no argument applying this cap to the parameters category I listed above either. Keeping it a Fixnum will maintain performance and precision.

I understand that in many cases values these high would be ludicrous, but somebody, at some point, is going to want to use them, and since ARC is all about removing the limitations, we should allow for them through the front-end GUI instead of via a custom script, as I am sure you would all agree.

Thoughts or ideas?
57
Core Development / wxForms is a bitch.
September 08, 2011, 05:59:10 pm
Seriously. I don't understand what the hell is going wrong with it.  I got the hang of the sizers so that things expand/contract as they should, but it I am having a problem with the "minimum size" of the panels.  Everything will look good in the editor, but once you start a test run, it initializes all big, and will not let you resize the window to any smaller.  I even went through and set every last object's minimum size to "1, 1", and it still did not work.

The reason I ask is this:  How important is the ability to have the editor panels resizable?  I understand that certain specific panels like the script editor and what not will be nice to have the function, but for the main database panels like Actors, Classes, Items, etc., what is the real benefit?  To be quite honest I have already made a few, and in my personal opinion I am unhappy with them.  

My proposal is that we make the main panels in the editor static frames.  Thoughts?

EDIT:
If we go static, I will have all the panels done within the next day (not all the actual function, obviously).  

EDIT:
:facepalm:
I started making a "static" panel, then realized my approach has been wrong.  I've been making panels, and not frames.  In my attempt to make it static, I just made a dynamically sizable one that behaves perfectly, all on accident.  I'll just continue to follow this style.  

Ah, the wonders of learning as you go... 
I still hope to get some serious work done on the editor now.  I'm not starting another project until this is done, I'm sick of my own procrastination.  I apologize for my lack of contribution lately.
58
Development Tools / [C#] Gemini - RGSS/RGSS2 Script Editor
September 08, 2011, 01:21:23 am
Gemini Script Editor

Authors: ForeverZer0 & Zeus81
Version: 2.0.0
Type: RGSS/RGSS2 Script Editor



Introduction


Gemini, named after the Zodiac Twins (RMXP/RMVX)(and now VX Ace!), is a feature-rich script editor designed purposefully for the RPG Maker community.  It can directly read and write archived Scripts.r*data files, which allows you to use the power of an external IDE without the trouble of importing/exporting scripts to and from the built-in editor.  


Features


  • Uses the popular SciLexer library for syntax highlighting

  • Custom color and font styles for parsing Ruby syntax

  • Auto-Complete function to help improve productivity, letting you choose default words, or create your own list

  • Auto-Indentation which follows standard Ruby conventions

  • "Script-Structuring" to apply proper format to your script with the click of a button

  • Batch comment/uncomment selected lines

  • Line highlighter with custom style as an added visual guide

  • Indentation guides for easily seeing the start/end of blocks

  • Brace-matching for tracking down the elusive missing parenthesis...

  • Powerful Find/Replace function, as well as incremental search

  • Tabbed-style editor for quickly switching between open scripts

  • Automatic updater built-in so you can make sure you have the latest version

  • Debug games directly from the editor, with choice to run normally or in DEBUG/TEST mode

  • Character map for using special Unicode character sets

  • Simple and intuitive interface

  • Portable, no-install application

  • Much more!




Screenshots

Spoiler: ShowHide

Spoiler: ShowHide

Spoiler: ShowHide

Spoiler: ShowHide



Download

Gemini.zip (12.84)
Direct

Gemini.exe (Self-Extracting archive)(12.54 MB)
Direct

Do to a lack of time to fix bugs, and for the benefit of others, I am open-sourcing Gemini, and I welcome anyone with knowledge of .NET to fix/add anything they wish, under the following conditions, which I respectfully ask be followed:


  • Gemini is to remain non-commercial

  • Original credit is to be given, although feel free to add yourself for any changes that are made

  • Please notify me if you decide to host it anywhere other than where I already have



Gemini 1.1.6 - Source (17.8 MB)(Self-Extracting Archive)
Gemini 1.1.6 - Source (19.2 MB)(ZIP)
Gemini 2.0.0 - Source (22.0 MB)(Self-Extracting Archive)
Gemini 2.0.0 - Source (41.2 MB)(ZIP)

Older Versions
Gemini 1.1.6
Gemini 1.1.6 (Source)


Compatibility

Requires Microsoft .NET Framework 4.0 (Web Installer) or higher.


Credits and Thanks


  • ForeverZer0 and Zeus81, for the application

  • Chaos-Project, for support and feedback

  • Javier "TDS" Cabrera, for testing




Author's Notes

As of version 2.0, there are as of yet no know bugs or issues. Please report any that you may find, thanks! ;)
59
class Scene_Title
 
  alias zer0_main main
  def main
   
    bitmap = Bitmap.new(640, 480)
    bitmap.fill_rect(0, 0, 640, 480, Color.new(128, 128, 255))
    viewport = Viewport.new(0, 0, 640, 480)
   
    viewport.z = 90 # Behind window
    #viewport.z = 120 # Above window, and you can't see the window
   
    sprite = Sprite.new(viewport)
    sprite.bitmap = bitmap
   
    zer0_main
   
    [bitmap, sprite, viewport].each {|obj| onj.dispose }
  end
end


This works, 100% guaranteed.  If it doesn't, you have another script screwing stuff up.
60
In case anyone has not seen the Zlib discussion a short bit ago, I mentioned I am making an enhanced script editor for RMXP/RMVX.  I already have, implemented quite a few nice features into it that the default script editor is lacking, and I plan to add some more.  I would say currently I am about 70% done (at least with the hard stuff), and now I more working on design and the extra little goodies that come with any IDE.  This brings me to the point of my thread:  What do scripters out there want out of an IDE built specifically for the RPG Maker community?  I would like some feedback on what is most important to each person.

Working Features So Far (or mostly working)

  • Can directly edit script archives for RMXP and RMVX

  • Ability to run game from the editor, either in DEBUG/TEST mode, or release mode

  • Syntax highlighting, with configuration for tweaking the lexer to how you see fit, including custom colors, fonts, and styles

  • Autocomplete for Ruby constants and classes, same with RMXP (autocomplete for RMVX not quite done yet)

  • Brace matching

  • Multiple tabbed documents open for quick selecting between them

  • Drag and drop game project files for easy loading

  • Drag and drop other files for quick import of scripts

  • Folding code for classes, methods, blocks, etc

  • Guidelines

  • Batch commenting/uncommenting

  • Auto-Indenting

  • Current line highlighting



Planned Features

  • New project creation

  • And more



What I will NOT be Adding

  • Active syntax checking, although I might add a "Click to Test Code" type of feature or something

  • Full blown Intellisense with dynamically adding autocomplete words for your custom classes, variables, etc. will likely not happen anytime soon

  • Support for other game makers

  • I may include a snippet manager, but macros are out of the question



Other than what I listed as "will nots", I'm open for any ideas.  Please keep in my mind that I am not a professional, and I do this as a hobby.  I will not be creating the most bad-ass IDE that ever was made, so please keep your ideas more on the simple side, and design ideas.  

Well without further talk, here's a link to the current build.  Do not mind the all the files inside, they will be merged before final release. For nor, the only one of concern is "ScriptEditor.exe".

RPG Maker Script Editor (2.22 MB)


This application is dependent on Microsoft .NET Framework 2.0 or higher.

P.S.  I sooo used the download pic from DM in case you're wondering. ;)