Envision, Create, Share

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

Scripter's corner : Snippets, Classes, Tips and more

Zeriab

Sponsor

And first now I realize that I released the encrypted version >_<
I did it to make it simpler for non-scripters to use. But this is the Scripter's corner so it was a mistake to upload that version here.
Here is an unencrypted version: http://bb.xieke.com/files/RemoveComments.rar
Note that only the Scripts.rxdata is included, so you'll have to provide the missing files if you want to upon it in the editor.
Feel free to mess around with it. ^^

Thanks for the nice comments Kain :cute:
I am happy to hear that it didn't mess anything up. My motivation to make it was indeed to see if you could increase the speed, both loading time, but also at runtime. I admit I didn't know whether it will have an effect other than speeding up the initial load time. (So my main focus was to remove parts which had no semantic significance)
I totally agree that you should only use it for the version you publish. It does decrease the value of the scripts due to the lack of comments.

Encrypting the data would be silly because one would have to decrypt the data again which requires modification of the DLL file.
Obfuscation is another matter, which I believe is what you actually mean.
With my other projects that I prioritize higher I won't have time to work on it for a very long time, but feel free to work on it.
You can see how I work with the library I include which makes everything loads easier.

@rey: There are no compilation of the scripts to any intermediary format. There are in version 1.9.x, but not in the version XP and VX uses. That is why this is interesting. More interesting is that the speed up seems to be actually noticeable.
I believe it's lexing, parsing and then interpreting, but I am not sure. Luckily the library means I don't have to understand how it works.

*hugs*
- Zeriab
 
Yeah the only thing performance-wise that was improved was going from Scene_A to Scene_B and all that; ie your menu opens quicker when you call it, with the code compressed, than it would without deleting comments and excess whitespace. My theory is that it takes a nanosecond more to skip past all our optional human-readable notes and spacing while initializing an object, but without all that extra baggage the object gets created and sent to its respectable variable quicker.

I doubt this would improve the FPS on your map or anything, especially if you have a laggy event or some script bogging your project down it'll still drag it down with or without compressing the code in this fashion. My speculation is, again, it just speeds up the 'initialize' of the object, nothing less nothing more.
 
After some recent experimentation, I've realized that I had an interesting tip for scripters. I've been playing around with the interpreter, and I realized that the event's "Call Script..." function actually behaves as though the script you were calling is a part of the interpreter class. Actually, to be more specific, your script is contained within the call script method in the Interpreter class. Now, this presents both opportunities and potential problems.

First off, lets list the opportunities. Since the call script function is interpreted as part of the interpreter, that means you can call any method in the Interpreter class. This means that, if you wanted to, you could call custom methods inserted into the class. You can even call methods already there, such as the one used to get the instance of any character or event on the current map.

Now, there are potential issues with this as well. For example, if you call any of the other interpreter commands, it will probably crash, because it tries to read the necessary data from the current event command, which is call script. When it tries that, it will fail. Guaranteed. Another point to be raised is that if you ever modify the @index variable, you can do one of several things. You can set the event into a loop, by putting the index at a point its already passed. You could also crash it by putting it to a point where there are no commands for it to process. Or, you could crash it by making it into a data type other than an integer.

All of this and probably more is possible with a little bit of creative thinking, and it's simple enough to actually do.
 
I've got some cool stuff for RPG::MapInfos. Mostly this is for traversing the data tree that you see in the editor, which might look like:

Code:
- Overworld

    Town 1

  - Town 2

      Inn

      Mayor's House

  + Town 3

Now, you can find $data_mapinfos[map_id].parent to figure out that if you're in the Mayor's House, you're actually in Town 2, or you can iterate through each sibling ($data_mapinfos.each_sibling {|sibling| print sibling.name}), or find out how many children a map has (Town 2 has 2 children) with $data_mapinfos.children.size. There is also a bit of regular expression to read bracketed data and remove it from the name of the map when it is returned for, say, a location script.

Code:
#===============================================================================

# ** RPG::MapInfo

#-------------------------------------------------------------------------------

#    Read many things from the name of a map

#===============================================================================

 

class RPG::MapInfo

  attr_accessor :id # This element did not exist before

  #-----------------------------------------------------------------------------

  # * Returns the parent MapInfo

  #-----------------------------------------------------------------------------

  def parent(data_hash = $data_mapinfos)

    return data_hash[self.parent_id]

  end

  #-----------------------------------------------------------------------------

  # * Returns a hash containing all sibling MapInfos

  #-----------------------------------------------------------------------------

  def siblings(data_hash = $data_mapinfos)

    output = {}

    each_sibling(data_hash) { |sibling| output[sibling.id] = sibling }

    return output

  end

  #-----------------------------------------------------------------------------

  # * Iterate through all sibling MapInfos

  #-----------------------------------------------------------------------------

  def each_sibling(data_hash = $data_mapinfos)

    data_hash.each_value do |mapinfo|

      yield mapinfo if self != mapinfo and self.parent_id == mapinfo.parent_id

    end

  end

  #-----------------------------------------------------------------------------

  # * Returns a hash containing all child MapInfos

  #-----------------------------------------------------------------------------

  def children(data_hash = $data_mapinfos)

    output = {}

    each_child(data_hash) { |child| output[child.id] = child }

    return output

  end

  #-----------------------------------------------------------------------------

  # * Iterate through all child MapInfos

  #-----------------------------------------------------------------------------

  def each_child(data_has = $data_mapinfos)

    data_hash.each_value { |mapinfo| yield mapinfo if id == mapinfo.parent_id }

  end

  #-----------------------------------------------------------------------------

  # * Name without any bracketed information

  #-----------------------------------------------------------------------------

  def name

    return @name.gsub(/\[[^\]]*\]/) {""}

  end

  #-----------------------------------------------------------------------------

  # * Name including bracketed information

  #-----------------------------------------------------------------------------

  def name!

    return @name

  end

  #-----------------------------------------------------------------------------

  # * Returns Integer from [#xx] where # is variable

  #-----------------------------------------------------------------------------

  def bracketed(definer)

    return nil unless @name =~ /\[#{definer}[ ]*([0-9]+)\]/i

    return $1.to_i

  end

  #=============================================================================

  # Example methods for getting data from map name

  #=============================================================================

  #-----------------------------------------------------------------------------

  # * Name contains [OV], meaning it's an overworld map

  #-----------------------------------------------------------------------------

  def overworld?

    return @name.include?("[OV]")

  end

  #-----------------------------------------------------------------------------

  # * Name contains [Loop-Map], meaning it's a looping map

  #-----------------------------------------------------------------------------

  def loop_map?

    return @name.include?("[Loop-Map]")

  end

  #-----------------------------------------------------------------------------

  # * Returns Slant, ex. [#40]

  #-----------------------------------------------------------------------------

  def slant

    return bracketed('#')

  end

  #-----------------------------------------------------------------------------

  # * Returns Encounter rate, ex. [encounter-rate: 50]

  #-----------------------------------------------------------------------------

  def level

    return bracketed('encounter-rate:')

  end

end

# Here we define the global data variable, and set the :id value for each one

$data_mapinfos = load_data('Data/MapInfos.rxdata')

$data_mapinfos.each { |key, mapinfo| mapinfo.id = key }

 

Also, expanding on the GSM module, here is an entire User32 module. It definitely doesn't include all of the User32 functions, but it has all of the ones I was using for resolution changing, mouse input keyboard input, and part of a debug console window (making a console window is kernel32, but I wanted to bring the main window back to the front afterward and that's SetForegroundWindow in user32). It also conveniently defines HWND as User32::HWND. If you "include User32" in your class or module, you can do something like SetWindowPos.call(HWND, HWND_TOP, 0, 0, width, height, SWP_NOMOVE | SWP_SHOWWINDOW) in order to bring the window to the top and change its width and height, but not change its position, and show the window.

Code:
#===============================================================================

# ** User32

#-------------------------------------------------------------------------------

#    Wrapper for user32.dll functions. Use "include User32" to get the constants

#===============================================================================

 

module User32

  GSM                 = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')

  SetWindowLong       = Win32API.new('user32', 'SetWindowLong', 'LIL', 'L')

  SetWindowPos        = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')

  Keybd_Event         = Win32API.new('user32', 'keybd_event', 'LLLL', '')

  FindWindow          = Win32API.new('user32', 'FindWindow', 'PP', 'L')

  SetForegroundWindow = Win32API.new('user32', 'SetForegroundWindow', 'L', 'L')

  GetCursorPos        = Win32API.new('user32', 'GetCursorPos', 'P', 'I')

  ShowCursor          = Win32API.new('user32', 'ShowCursor', 'L', 'L')

  ScreenToClient      = Win32API.new('user32', 'ScreenToClient', 'LP', 'I')

  GetKeyState         = Win32API.new('user32', 'GetKeyState', 'I', 'I')

  GetAsyncKeyState    = Win32API.new('user32', 'GetAsyncKeyState', 'I', 'I')

  

  HWND = FindWindow.call('RGSS Player', Settings["Title"])

  

  # GSM constants. For more complete descriptions, see Microsoft's website:

  # [url=http://msdn.microsoft.com/en-us/library/ms724385(VS.85]http://msdn.microsoft.com/en-us/library/ms724385(VS.85[/url]).aspx

  SM_CXSCREEN      = 0  # Width of the current master screen resolution

  SM_CYSCREEN      = 1  # Height of the current master screen resolution

  

  SM_CXVSCROLL     = 2  # Width of a vertical scroll bar

  SM_CYHSCROLL     = 3  # Height of a horizontal scroll bar

  

  SM_CYCAPTION     = 4  # Height of a caption area

  

  SM_CXBORDER      = 5  # Width of a window border

  SM_CYBORDER      = 6  # Height of a window border

  

  SM_CXDLGFRAME    = 7

  SM_CXFIXEDFRAME  = 7  # Width of non-resizable captioned window frame

  SM_CYDLGFRAME    = 8

  SM_CYFIXEDFRAME  = 8  # Height of non-resizable captioned window frame

  

  SM_CYVTHUMB      = 9  # Height of a thumb button on vertical scrollbars

  SM_CXHTHUMB      = 10 # Width of a thumb button on horizontal scrollbars

  

  SM_CXICON        = 11 # Default width of an icon

  SM_CYICON        = 12 # Default height of an icon

  

  SM_CXCURSOR      = 13 # Width of a cursor

  SM_CYCURSOR      = 14 # Height of a cursor

  

  SM_CYMENU        = 15 # Height of a single-line menu bar

  

  SM_CXFULLSCREEN  = 16 # Width of client rect for a full-screen window

  SM_CYFULLSCREEN  = 17 # Height of client rect for a full-screen window

  

  SM_CYKANJIWINDOW = 18 # Height of kanji window at bottom of screen, if there

  

  SM_MOUSEPRESENT  = 19 # Non-zero if mouse is present; 0 if not

  

  SM_CYVSCROLL     = 20 # Height of the arrow bitmap on vertical scrollbars

  SM_CXHSCROLL     = 21 # Width of the arrow bitmap on horizontal scrollbars

  

  SM_DEBUG         = 22 # Non-zero if debug User.exe is installed; 0 if not

  SM_SWAPBUTTON    = 23 # Non-zero if mouse button values are swapped

  

  SM_CXMIN         = 28 # Minimum width of a window

  SM_CYMIN         = 29 # Minimum height of a window

  

  SM_CXSIZE        = 30 # Width of a button in a window caption or title bar

  SM_CYSIZE        = 31 # Height of a button in a window caption or title bar

  

  SM_CXFRAME       = 32

  SM_CXSIZEFRAME   = 32 # Width of the sizing border around a resizable window

  SM_CYFRAME       = 33

  SM_CYSIZEFRAME   = 33 # Height of the sizing border around a resizable window

  

  SM_CXMINTRACK    = 34 # Minimum "tracking" width of a window

  SM_CYMINTRACK    = 35 # Minimum "tracking" height of a window

  

  SM_CXDOUBLECLK   = 36 # Width of rect which second click must be in for double

  SM_CYDOUBLECLK   = 37 # Hght of rect which second click must be in for double

  

  SM_CXICONSPACING = 38 # Width of a grid cell for items in large icon view

  SM_CYICONSPACING = 39 # Height of a grid cell for items in large icon view

  

  SM_MENUDROPALIGNMENT = 40 # 0 if drop-down menus are left-aligned...

  

  SM_PENWINDOWS    = 41 # Non-zero if Microsoft Windows for Pen computing

                        #  extensions are installed; 0 if not

  

  SM_DBCSENABLED   = 42 # Non-zero if user32.dll supports DBCS; 0 if not

  

  SM_CMOUSEBUTTONS = 43 # Number of available mouse buttons, or 0 for no mouse

  

  SM_SECURE        = 44 # Always returns 0

  

  SM_CXEDGE        = 45 # Width of a 3-D style border

  SM_CYEDGE        = 46 # Height of a 3-D style border

  

  SM_CXMINSPACING  = 47 # Width of a grid cell for minimized windows

  SM_CYMINSPACING  = 48 # Height of a grid cell for minimized windows

  

  SM_CXSMICON      = 49 # Recommended width of a small icon

  SM_CYSMICON      = 50 # Recommended height of a small icon

  

  SM_CYSMCAPTION   = 51 # Height of a small caption

  SM_CXSMSIZE      = 52 # Width of small caption buttons

  SM_CYSMSIZE      = 53 # Height of small caption buttons

  SM_CXMENUSIZE    = 54 # Width of menu bar buttons

  SM_CYMENUSIZE    = 55 # Height of menu bar buttons

  

  SM_ARRANGE       = 56 # Flags about how system the arranges minimized windows

  SM_CXMINIMIZED   = 57 # Width of a minimized window

  SM_CYMINIMIZED   = 58 # Height of a minimized window

  

  SM_CXMAXTRACK    = 59 # Default maximum width of resizable windows

  SM_CYMAXTRACK    = 60 # Default maximum height of resizable windows

  SM_CXMAXIMIZED   = 61 # Default width of maximized top-level window

  SM_CYMAXIMIZED   = 62 # Default height of maximized top-level window

  

  SM_NETWORK       = 63 # The least significant bit is set if a network is

                        #  present; otherwise, it is cleared

  

  SM_CLEANBOOT     = 67 # System boot type; 0:Normal, 1:Safe, 2:Safe w/network

  

  SM_CXDRAG        = 68

  SM_CYDRAG        = 69 # Number of pixels mouse can move before initiating drag

  

  SM_SHOWSOUNDS    = 70 # Non-zero if user requires visible output; 0 if not

  

  SM_CXMENUCHECK   = 71 # Width of the default menu check-mark bitmap

  SM_CYMENUCHECK   = 72 # Height of the default menu check-mark bitmap

  

  SM_SLOWMACHINE   = 73 # Non-zero if system has a slow processor; 0 if not

                        #  No, seriously, that's what Microsoft said!

  

  SM_MIDEASTENABLED = 74 # Non-zero if system can use Hebrew, Arabic languages

  

  SM_MOUSEWHEELPRESENT = 75 # Nonzero mouse has vertical scroll wheel; 0 if not 

  

  SM_XVIRTUALSCREEN    = 76 # Coordinates of the left side of the virtual screen

  SM_YVIRTUALSCREEN    = 77 # Coordinates of the top of the virtual screen

  SM_CXVIRTUALSCREEN   = 78 # Virtual width of all screens put together

  SM_CYVIRTUALSCREEN   = 79 # Virtual height of all screen put together

  SM_CMONITORS         = 80 # Numbers of display monitors on a desktop

  SM_SAMEDISPLAYFORMAT = 81 # Non-zero if all screen use same color depth...

  

  # SetWindowPos constants

  HWND_NOTOPMOST      = -2  # Make window not always on top (and bring to front)

  HWND_TOPMOST        = -1  # Put window in front and make it always on top

  HWND_TOP            = 0   # Put window in front of all non-topmost windows

  HWND_BOTTOM         = 1   # Put window behind all other windows

  

  SWP_NOSIZE          = 0x0001 # Keep current size (ignores w and h)

  SWP_NOMOVE          = 0x0002 # Keep current position (ignores X and Y)

  SWP_NOZORDER        = 0x0004 # Keep current Z order (ignores hWndInsertAfter)

  SWP_NOREDRAW        = 0x0008 # Does NOT redraw changes

  SWP_NOACTIVATE      = 0x0010 # Does NOT automatically activate the window

  SWP_FRAMECHANGED    = 0x0020 # Applies new frame styles set with SetWindowLong

  SWP_SHOWWINDOW      = 0x0040 # Displays the window

  SWP_HIDEWINDOW      = 0x0080 # Hides the window

  SWP_NOCOPYBITS      = 0x0100 # Discards the entire contents of the client area

  SWP_NOOWNERZORDER   = 0x0200 # Doesn't change the window display order

  SWP_NOSENDCHANGING  = 0x0400 # Don't send WM_WINDOWPOSCHANGING

  SWP_DEFERERASE      = 0x2000 # Prevents generation of the WM_SYNCPAINT message

  SWP_ASYNCWINDOWPOS  = 0x4000 # Use if calling thread does not own the window

end

 
 
I've been working on a new RMXP Tilemap script. It didn't work for what I needed it for (because it lags horribly when you zoom the whole thing out) and I haven't checked its speed against SephirothSpawn's original rewrite, but here it is. It does priorities correctly, unlike any rewrite before it, and it does this by making a Sprite for each 32x32 square. It also has animated autotiles. It is a Ruby equivalent to the built-in Tilemap class. The built-in is faster, of course, but can't zoom or have automatic Plane-like capabilities. Do with this what you will; it's probably best for educational purposes.

[rgss]#===============================================================================
# ** Tilemap
#-------------------------------------------------------------------------------
# rey meustrus and SephirothSpawn
# Version 2.0
# 2010-02-02
# SDK : Version 2.0+, Parts I & II
#-------------------------------------------------------------------------------
# * Credits :
#
#   Thanks to Trickster for conversion formula for Hexidecimal to rgb.
#   Thanks to trebor777 for helping with the priority bug from the 0.9 version.
#-------------------------------------------------------------------------------
# * Version History :
#
#   Version 0.9 -------------------------------------------------- (??????????)
#   Version 1 ---------------------------------------------------- (2007-05-30)
#    Version 1.1 ------------------------------------------------- (2007-07-20)
#     - Update : Removed pointless block. Move RPG::Cache.autotile to MACL.
#    Version 1.11 ------------------------------------------------ (2007-07-31)
#    Version 2.0 ------------------------------------------------- (2010-02-02)
#-------------------------------------------------------------------------------
# * Description :
#
#   This script was designed to re-write the default RGSS Hidden Tilemap class.
#   The script has many added features via read/write variables.
#-------------------------------------------------------------------------------
# * Instructions :
#
#   Place The Script Below the SDK and Above Main.
#-------------------------------------------------------------------------------
# * Syntax :
#
#   Get Autotile Tile Bitmap
#    - RPG::Cache.autotile_tile(autotile_filename, tile_id[, hue[, frame_id]])
#
#      autotile_filename   : Filename of autotile
#      tile_id             : ID of tile (Found from RPG::Map.data)
#      hue (Optional)      : Hue for tile
#      frame_id (Optional) : Frame of tile (for animated autotiles)
#
# * Tilemap Syntax
#
#   - tile(tile_id)     : Gets bitmap for tile_id
#   - tile(x, y, z)     : Gets bitmap at coordinates using @map_data
#   - priority(tile_id) : Gets Z value for tile_id
#   - priority(x, y, z) : Gets Z value at coordinates
#
#   Readable Attributes :
#    - viewport         : Viewport used for sprites
#    - width            : Total pixel width of the Tilemap
#    - height           : Total pixel height of the Tilemap
#
#   Readable/Writable Attributes :
#    - map_data         : 3D Table of Tile ID Data
#    - flash_data       : 3D Table of Tile Color Data
#    - priorities       : 3D Table of Tile Priorities
#    - hue              : Hue adjustment for all tiles
#    - ox, oy           : Tilemap layer offsets
#    - zoom             : Zoom value as fraction
#    - tilesize         : Zoom value as size of individual tile (normal is 32.0)
#    - tileset_name     : Name of Bitmap
#    - autotile_names   : Array of Autotile Filenames
#    - visible          : Tilemap Visible Flag
#    - static           : Static Flag (no animated autotiles)
#    - is_a_plane       : Behaves like a Plane (loops around edges)
#===============================================================================
 
#-------------------------------------------------------------------------------
# SDK Log
#-------------------------------------------------------------------------------
SDK.log('Tilemap', 'rey meustrus and SephirothSpawn', 2.0, '2010-02-02')
 
#===============================================================================
# ** RPG::Cache
#===============================================================================
 
module RPG::Cache
  #-----------------------------------------------------------------------------
  # * Constants
  #-----------------------------------------------------------------------------
  Animated_Autotile_Frames = 16
  Empty_Bitmap = Bitmap.new(32, 32)
  Default_Rect = Rect.new(0, 0, 32, 32)
  Autotiles = [
    [[26, 27, 32, 33], [ 4, 27, 32, 33], [26,  5, 32, 33], [ 4,  5, 32, 33],
     [26, 27, 32, 11], [ 4, 27, 32, 11], [26,  5, 32, 11], [ 4,  5, 32, 11]],
    [[26, 27, 10, 33], [ 4, 27, 10, 33], [26,  5, 10, 33], [ 4,  5, 10, 33],
     [26, 27, 10, 11], [ 4, 27, 10, 11], [26,  5, 10, 11], [ 4,  5, 10, 11]],
    [[24, 25, 30, 31], [24,  5, 30, 31], [24, 25, 30, 11], [24,  5, 30, 11],
     [14, 15, 20, 21], [14, 15, 20, 11], [14, 15, 10, 21], [14, 15, 10, 11]],
    [[28, 29, 34, 35], [28, 29, 10, 35], [ 4, 29, 34, 35], [ 4, 29, 10, 35],
     [38, 39, 44, 45], [ 4, 39, 44, 45], [38,  5, 44, 45], [ 4,  5, 44, 45]],
    [[24, 29, 30, 35], [14, 15, 44, 45], [12, 13, 18, 19], [12, 13, 18, 11],
     [16, 17, 22, 23], [16, 17, 10, 23], [40, 41, 46, 47], [ 4, 41, 46, 47]],
    [[36, 37, 42, 43], [36,  5, 42, 43], [12, 17, 18, 23], [12, 13, 42, 43],
     [36, 41, 42, 47], [16, 17, 46, 47], [12, 17, 42, 47], [ 0,  1,  6,  7]]
  ]
  #-----------------------------------------------------------------------------
  # * Normal or Autotile Tile
  #-----------------------------------------------------------------------------
  def self.tile!(tileset_name, autotile_names, tile_id, hue = 0)
    return Empty_Bitmap if tile_id == 0
    return self.tile(tileset_name, tile_id, hue) if tile_id >= 384
    # After this point, we are an autorile
    filename = autotile_names[tile_id / 48 - 1]
    autotile = self.autotile(filename)
    # Reconfigure Tile ID
    tile_id %= 48
    # Creates Key
    key = [filename, tile_id, hue]
    # If Key Not Found
    if not @cache.has_key?(key) or @cache[key].disposed?
      # Creates Bitmap
      bitmap = Bitmap.new(autotile.width / 3, 32)
      # Collects Auto-Tile Tile Layout
      tiles = Autotiles[tile_id / 8][tile_id % 8]
      # Draws Auto-Tile Rects
      tiles.each_with_index do |tile_position, i|
        for frame_id in 0..(autotile.width / 96)
          src_rect = Rect.new(tile_position % 6 * 16 + frame_id * 96,
            tile_position / 6 * 16, 16, 16)
          bitmap.blt(i % 2 * 16 + frame_id * 32, i / 2 * 16, autotile, src_rect)
        end
      end
      # Saves Autotile to Cache
      @cache[key] = bitmap
      # Change Hue
      @cache[key].hue_change(hue)
    end
    @cache[key]
  end
  #-----------------------------------------------------------------------------
  # * Tile Rect
  #-----------------------------------------------------------------------------
  def self.tile_rect(tileset_name, autotile_names, tile_id)
    return Default_Rect if tile_id == 0 or tile_id >= 384
    autotile = self.autotile(filename = autotile_names[tile_id / 48 - 1])
    # Configures Animation Offset
    fc = (Graphics.frame_count/Animated_Autotile_Frames) % (autotile.width/96)
    @cache[fc] = Rect.new(fc * 32, 0, 32, 32) if not @cache.has_key?(fc)
    @cache[fc]
  end
end
 
#===============================================================================
# ** Game_Character
#-------------------------------------------------------------------------------
#    Remove $game_map.screen_y from Z processing so Tilemap doesn't have to
#    process Z value every time screen_y changes
#===============================================================================
 
class Game_Character
  #-----------------------------------------------------------------------------
  # * Get Screen Z-Coordinates
  #     height : character height
  #-----------------------------------------------------------------------------
  def screen_z(height = 0)
    # If display flag on closest surface is ON
    if @always_on_top
      # 999, unconditional
      return 999
    end
    # Get screen coordinates from real coordinates and map display position
    z = (@real_y + 3) / 4 + 32
    # If tile
    if @tile_id > 0
      # Add tile priority * 32
      return z + $game_map.priorities[@tile_id] * 32
    # If character
    else
      # If height exceeds 32, then add 31
      return z + ((height > 32) ? 31 : 0)
    end
  end
end
 
#===============================================================================
# ** Spriteset_Map
#===============================================================================
 
class Spriteset_Map
  #-----------------------------------------------------------------------------
  # * Alias Listings
  #-----------------------------------------------------------------------------
  alias_method :seph_tilemap_ssmap_inittm, :init_tilemap
  #-----------------------------------------------------------------------------
  # * Tilemap Initialization
  #-----------------------------------------------------------------------------
  def init_tilemap
    # Original Tilemap Initialization
    seph_tilemap_ssmap_inittm
    # Set Tilemap Settings
    @tilemap.tileset_name = $game_map.tileset_name
    @tilemap.autotile_names = $game_map.autotile_names
  end
end
 
#===============================================================================
# ** Tilemap
#===============================================================================
 
class Tilemap
  #-----------------------------------------------------------------------------
  # * Tilemap Options
  #-----------------------------------------------------------------------------
  Viewport_Padding  = 2   # Number of tiles beyond viewport to refresh
  Flash_Alpha       = 64  # Alpha value of the color of flash data
  #-----------------------------------------------------------------------------
  # * Public Instance Variables
  #-----------------------------------------------------------------------------
  attr_reader   :viewport       # Viewport for all sprites
  attr_reader   :map_data       # 3D Table of Tile Settings
  attr_reader   :flash_data     # 3D Table of Sprite Flash Colors
  attr_reader   :priorities     # 3D Table of Tileset Priorities
  attr_reader   :hue            # Hue Adjustment Value
  attr_accessor :eek:x             # Bitmap Offsets      
  attr_accessor :eek:y             # Bitmap Offsets      
  attr_reader   :zoom           # Zoom Fraction        
  attr_reader   :tileset_name   # Tileset Filename
  attr_reader   :autotile_names # Array of Autotile Filenames
  attr_reader   :visible        # Tilemap Visibility
  attr_accessor :static         # No Animated Autotiles
  attr_accessor :is_a_plane     # Loops around edges
  attr_accessor :tileset        # Deprecated
  attr_accessor :autotiles      # Deprecated
  #-----------------------------------------------------------------------------
  # * Object Initialization                            
  #-----------------------------------------------------------------------------
  def initialize(viewport = nil)                    
    @viewport          = viewport
    @map_data          = nil
    @flash_data        = nil
    @priorities        = nil
    @hue               = 0
    @ox                = 0
    @oy                = 0
    @zoom              = 1.0
    @tileset_name      = nil
    @autotile_names    = []
    @visible           = true
    @static            = false
    @is_a_plane        = false
    @sprites           = {}
    @disposed          = false
    @refresh_autotiles = true
    @autotiles         = []
  end
  #-----------------------------------------------------------------------------
  # * Total pixel width
  #-----------------------------------------------------------------------------
  def width
    return 0 if @map_data.nil?
    @map_data.xsize * 32
  end
  #-----------------------------------------------------------------------------
  # * Total pixel height
  #-----------------------------------------------------------------------------
  def height
    return 0 if @map_data.nil?
    @map_data.ysize * 32
  end
  #-----------------------------------------------------------------------------
  # * Set Map Data
  #-----------------------------------------------------------------------------
  def map_data=(map_data)
    return if @map_data == map_data
    @map_data = map_data
    refresh
  end
  #-----------------------------------------------------------------------------
  # * Set Flash Data
  #-----------------------------------------------------------------------------
  def flash_data=(flash_data)
    return if @flash_data == flash_data
    @flash_data = flash_data
    @sprites.each do |key, sprite|
      if not flash_data.nil? and (hex = flash_data[*key]) != 0
        sprite.color.red   = (hex / 256) * 16
        sprite.color.green = ((hex / 16) % 16) * 16
        sprite.color.blue  = (hex % 16) * 16
        sprite.color.alpha = Flash_Alpha
      else
        sprite.color.alpha = 0
      end
    end
    Graphics.frame_reset
  end
  #-----------------------------------------------------------------------------
  # * Set Priorities
  #-----------------------------------------------------------------------------
  def priorities=(priorities)
    return if @priorities == priorities
    @priorities = priorities
    refresh
  end
  #-----------------------------------------------------------------------------
  # * Set Hue
  #-----------------------------------------------------------------------------
  def hue=(hue)
    return if @hue == hue
    @hue = hue
    refresh
  end
  #-----------------------------------------------------------------------------
  # * Set OX value
  #-----------------------------------------------------------------------------
  def ox=(ox)
    return if @ox == ox
    @ox = ox
    @sprites.each { |key, sprite| sprite.ox = ox }
  end
  #-----------------------------------------------------------------------------
  # * Set OX value
  #-----------------------------------------------------------------------------
  def oy=(oy)
    return if @oy == oy
    @oy = oy
    @sprites.each { |key, sprite| sprite.oy = oy }
  end
  #-----------------------------------------------------------------------------
  # * Get Tile Size
  #-----------------------------------------------------------------------------
  def tilesize
    (zoom * 32).to_i
  end
  #-----------------------------------------------------------------------------
  # * Set Tile Size
  #-----------------------------------------------------------------------------
  def tilesize=(tilesize)
    self.zoom = tilesize / 32.0
  end
  #-----------------------------------------------------------------------------
  # * Set Zoom Fraction
  #-----------------------------------------------------------------------------
  def zoom=(zoom)
    return if @zoom == zoom
    @zoom = zoom
    @sprites.each do |key, sprite|
      sprite.zoom_x = sprite.zoom_y = zoom
      sprite.x = key.at(0) * tilesize
      sprite.y = key.at(1) * tilesize
    end
    Graphics.frame_reset
  end
  #-----------------------------------------------------------------------------
  # * Set Visibility
  #-----------------------------------------------------------------------------
  def visible=(visible)
    return if @visible == visible
    @visible = visible
    @sprites.each_value { |sprite| sprite.visible = visible }
  end
  #-----------------------------------------------------------------------------
  # * Set Tileset Name
  #-----------------------------------------------------------------------------
  def tileset_name=(name)
    return if @tileset_name == name
    @tileset_name = name
    refresh
  end
  #-----------------------------------------------------------------------------
  # * Set Autotile Names
  #-----------------------------------------------------------------------------
  def autotile_names=(names)
    return if @autotile_names == names
    @autotile_names = names
    refresh
  end
  #-----------------------------------------------------------------------------
  # * Get bitmap at coordinates
  #-----------------------------------------------------------------------------
  def tile(*args)
    RPG::Cache.tile!(@tileset_name, @autotile_names, args_to_id(*args), @hue)
  end
  #-----------------------------------------------------------------------------
  # * Get bitmap rect at coordinates
  #-----------------------------------------------------------------------------
  def tile_rect(*args)
    RPG::Cache.tile_rect(@tileset_name, @autotile_names, args_to_id(*args))
  end
  #-----------------------------------------------------------------------------
  # * Get priority at coordinates
  #-----------------------------------------------------------------------------
  def priority(x, y, z)
    priority = @priorities[@map_data[x, y, z]]
    return 0 if priority == 0
    (y + priority) * 32 + 64
  end
  #-----------------------------------------------------------------------------
  # * Find tile_id from args
  #-----------------------------------------------------------------------------
  def args_to_id(*args)
    if args.size == 1
      return args[0]
    elsif args.size == 3
      return @map_data[*args]
    else
      raise ArgumentError, "Only one (tile_id) or three (x, y, z) args allowed"
    end
  end
  #-----------------------------------------------------------------------------
  # * Dispose
  #-----------------------------------------------------------------------------
  def dispose
    # Dispose Sprites
    @sprites.each_value { |sprite| sprite.dispose }
    # Set Disposed Flag to True
    @disposed = true
  end
  #-----------------------------------------------------------------------------
  # * Disposed?
  #-----------------------------------------------------------------------------
  def disposed?
    @disposed
  end
  #-----------------------------------------------------------------------------
  # * Frame Update
  #-----------------------------------------------------------------------------
  def update
    if @is_a_plane
      # Get Visible X Tiles
      x1 = @ox / 32 - Viewport_Padding
      x2 = @ox / 32 + @viewport.rect.width / tilesize + Viewport_Padding
      # Get Visible Y Tiles
      y1 = @oy / 32 - Viewport_Padding
      y2 = @oy / 32 + @viewport.rect.height / tilesize + Viewport_Padding
      # Wrapped values
      _x1 = x1 % @map_data.xsize
      _x2 = x2 % @map_data.xsize
      _y1 = y1 % @map_data.ysize
      _y2 = y2 % @map_data.ysize
      # Behave like a Plane
      tsize = tilesize
      each_visible_sprite do |x, y, z, sprite|
        if x > x2 and x >= _x1
          sprite.x = (x - @map_data.xsize) * tsize
        elsif x < x1 and x <= _x2
          sprite.x = (x + @map_data.xsize) * tsize
        else
          sprite.x = x * tsize
        end
        if y > y2 and y >= _y1
          sprite.y = (y - @map_data.ysize) * tsize
        elsif y < y1 and y <= _y2
          sprite.y = (y + @map_data.ysize) * tsize
        else
          sprite.y = y * tsize
        end
      end
    end
    # If Not Static and Autotile Reset Frame
    if Graphics.frame_count % RPG::Cache::Animated_Autotile_Frames == 0
      refresh_autotiles unless @static
    end
  end
  #-----------------------------------------------------------------------------
  # * Refresh
  #-----------------------------------------------------------------------------
  def refresh
    return if @map_data.nil? or @tileset_name.nil? or @autotile_names.size < 7
    @sprites.each_value { |sprite| sprite.dispose }
    @sprites.clear
    # Passes Through X Coordinates
    for x in 0...@map_data.xsize
      # Passes Through Z Coordinates
      for y in 0...@map_data.ysize
        # Passes Through Layers
        for z in 0...@map_data.zsize
          # Collects Tile ID
          id = @map_data[x, y, z]
          # Skip if 0 tile
          next if id == 0
          sprite = find_sprite(x, y, z)
          # Draw Tile
          sprite.bitmap = tile(id)
          sprite.src_rect = tile_rect(id)
          sprite.z = priority(x, y, z)
        end
      end
    end
    Graphics.frame_reset
  end  
  #-----------------------------------------------------------------------------
  # * Refresh Auto-Tiles; only affects visible animated autotiles
  #-----------------------------------------------------------------------------
  def refresh_autotiles
    each_visible_sprite do |x, y, z, sprite|
      # Collects Tile ID
      id = @map_data[x, y, z]
      # Skip if 0 tile, or if not autotile
      next if id == 0 or id >= 384
      # Skip If Non-Animated Tile
      bitmap = RPG::Cache.autotile(@autotile_names[id / 48 - 1])
      next unless bitmap.width / 96 > 1
      # Draw Tile
      find_sprite(x, y, z).src_rect = tile_rect(id)
    end
    Graphics.frame_reset
  end    
  #-----------------------------------------------------------------------------
  # * Find or create sprite at coordinates
  #-----------------------------------------------------------------------------
  def find_sprite(x, y, z, create = true)
    return @sprites[[x, y, z]] if @sprites.has_key?([x, y, z])
    return nil unless create
    sprite = Sprite.new(@viewport)
    sprite.visible = @visible
    sprite.x = x * tilesize
    sprite.y = y * tilesize
    sprite.ox = @ox
    sprite.oy = @oy
    sprite.zoom_x = sprite.zoom_y = @zoom
    @sprites[[x, y, z]] = sprite
  end
  #-----------------------------------------------------------------------------
  # * Dispose of sprite at coordinates
  #-----------------------------------------------------------------------------
  def dispose_sprite(x, y, z)
    return unless @sprites.has_key?([x, y, z])
    @sprites[[x, y, z]].dispose
    @sprites.delete([x, y, z])
  end
  #-----------------------------------------------------------------------------
  # * Iterate through visible sprites
  #-----------------------------------------------------------------------------
  def each_visible_sprite
    # Get Visible X Tiles
    x1 = (@ox / 32 - Viewport_Padding) % @map_data.xsize
    x2 = (@ox / 32 + @viewport.rect.width / tilesize + Viewport_Padding) %
         @map_data.xsize
    # Get Visible Y Tiles
    y1 = (@oy / 32 - Viewport_Padding) % @map_data.ysize
    y2 = (@oy / 32 + @viewport.rect.height / tilesize + Viewport_Padding) %
         @map_data.ysize
    @sprites.each do |key, sprite|
      send_sprite = true
      if x1 < x2
        send_sprite &= key.at(0).between?(x1, x2)
      else
        send_sprite &= key.at(0) > x1 || key.at(0) < x2
      end
      if y1 < y2
        send_sprite &= key.at(1).between?(y1, y2)
      else
        send_sprite &= key.at(1) > y1 || key.at(1) < y2
      end
      yield key.at(0), key.at(1), key.at(2), sprite if send_sprite
    end
  end
end
 
[/rgss]

EDIT: Added flash data, which is criminally easy with this approach.
 
Stupid but useful...

how to swap variables without the use of a temporary variable? MAke use of parallel assignement !
[rgss] 
x,y = y,x
 
[/rgss]
 

Zeriab

Sponsor

It is definitely useful trebor ^^

I don't know how many of you know __END__.
The rest of that section will not be run. In fact I believe the parser will stop at __END__ and therefore won't even build the abstract syntax tree for what comes afterwards. (An effect is the lack of syntax checking)
This can be used for preventing the inclusion of test code except when you want to use it.

Here is a conceived example:
Code:
class Medal

  include Comparable

  attr_reader :titel, :time

  def initialize(titel, time)

    unless time.is_a?(Numeric)

      raise ArgumentError.new("Time must be a numeric")

    end

    @titel = titel

    @time = time

  end

  

  def <=>(medal)

    return time <=> medal.time

  end

end

 

__END__

 

class TestError < StandardError; end

 

bronze = Medal.new('Bronze', 180)

bronze2 = Medal.new('Bronze', 180)

bronze3 = Medal.new('Bronze3', 180)

silver = Medal.new('Silver', 105)

gold = Medal.new('Gold', 87.5)

 

unless (bronze == bronze2)

  raise TestError.new("Medal.== does not compare #{bronze.inspect} " +

                      "and #{bronze2.inspect} properly")

end

 

unless (bronze == bronze3)

  raise TestError.new("Medal.== does not ignore the title")

end

 

unless (silver <=> bronze) == -1

  raise TestError.new("Medal.<=> does not return -1 when its time is less" +

                      " than the medal compared to")

end

 

unless (silver <=> gold) == 1

  raise TestError.new("Medal.<=> does not return 1 when its time is greater" +

                      " than the medal compared to")

end

 

unless (bronze <=> gold) == 1

  raise TestError.new("Medal.<=> does not preserve transitivity.\n" +

                      "I.e. <=> is highly problematic.")

end

                    

p 'Medal testing completed successfully'

Just comment the __END__ when you want to test.

*hugs*
 
A neat little equipment optimizer. Can be customized for each actor, so aluxes may like weapons with atk, but hilda prefers int.

[rgss]#==============================================================================
# ** Equipment Optimzer
#------------------------------------------------------------------------------
# SephirothSpawn
# Version 1.0
# 2010-02-18
#==============================================================================
 
module EquipmentOptimzer
  #--------------------------------------------------------------------------
  # * Weapon Priorities
  #
  #     Defines stat priorities looking for when passing through equipment
  #
  #   Weapon_Priorities[actor_id] = [:stat_name, ...]
  #--------------------------------------------------------------------------
  Weapon_Priorities = {}
  Weapon_Priorities.default = [
    :atk, :str_plus, :pdef, :mdef, :dex_plus, :agi_plus, :int_plus
  ]
  #--------------------------------------------------------------------------
  # * Armor Priorities
  #
  #     Defines stat priorities looking for when passing through equipment
  #
  #   Armor_Priorities[actor_id] = [:stat_name, ...]
  #--------------------------------------------------------------------------
  Armor_Priorities = {}
  Armor_Priorities.default = [
    :pdef, :mdef, :eva, :dex_plus, :str_plus, :agi_plus, :int_plus
  ]
  #--------------------------------------------------------------------------
  # * Optimize Weapon
  #--------------------------------------------------------------------------
  def self.optimze_weapon(actor)
    # Return if actor cannot equip
    return if actor.equip_fix?(0)
    # Unequip current weapon
    actor.equip(0, 0)
    # Gather equippable weapons list
    weapons = []
    for weapon in $data_weapons
      next if weapon == nil
      next unless actor.equippable?(weapon)
      if $game_party.weapon_number(weapon.id) > 0
        weapons << weapon
      end
    end
    # Stop if no weapons found
    return if weapons.size == 0
    # Equip if only 1 weapon found
    if weapons.size == 1
      actor.equip_item(weapons[0])
      return
    end
    # Pass through priority list
    Weapon_Priorities[actor.id].each do |stat|
      # Get new list based off priority
      weapons = self.best_stat(weapons, stat)
      # Stop cycle if only 1 weapon found
      break if weapons.size == 1
    end
    # Equip Item
    actor.equip_item(weapons[0])
  end
  #--------------------------------------------------------------------------
  # * Optimize Armor
  #--------------------------------------------------------------------------
  def self.optimze_armor(actor, kind)
    # Return if actor cannot equip
    return if actor.equip_fix?(kind + 1)
    # Unequip current armor
    case kind
    when 0 ; actor.equip(1, 0)
    when 1 ; actor.equip(2, 0)
    when 2 ; actor.equip(3, 0)
    when 3 ; actor.equip(4, 0)
    end
    # Gather equippable armors list
    armors = []
    for armor in $data_armors
      next if armor == nil
      next if armor.kind != kind
      next unless actor.equippable?(armor)
      if $game_party.armor_number(armor.id) > 0
        armors << armor
      end
    end
    # Stop if no armors found
    return if armors.size == 0
    # Equip if only 1 armor found
    if armors.size == 1
      actor.equip_item(armors[0])
      return
    end
    # Pass through priority list
    Armor_Priorities[actor.id].each do |stat|
      # Get new list based off priority
      armors = self.best_stat(armors, stat)
      # Stop cycle if only 1 armor found
      break if armors.size == 1
    end
    # Equip Item
    actor.equip_item(armors[0])
  end
  #--------------------------------------------------------------------------
  # * Filter list by max result
  #--------------------------------------------------------------------------
  def self.best_stat(list, stat)
    # Get max value
    max = (list.collect {|x| x.send(stat)}).max
    # Start new list
    a = []
    # Add item to list if max == stat
    list.each {|x| a << x if x.send(stat) == max}
    # Return list
    return a
  end
end
 
#==============================================================================
# ** Game_Actor
#==============================================================================
 
class Game_Actor
  #--------------------------------------------------------------------------
  # * Equip Item
  #--------------------------------------------------------------------------
  def equip_item(item)
    # Branch by item type
    case item
    when RPG::Weapon
      # Return if fixed
      return if equip_fix?(0)
      # Return unless equippable
      return unless equippable?(item)
      # Equip
      equip(0, item.id)
    when RPG::Armor
      # Return if fixed
      return if equip_fix?(item.kind + 1)
      # Return unless equippable
      return unless equippable?(item)
      # Equip
      equip(item.kind + 1, item.id)
    end
  end
  #--------------------------------------------------------------------------
  # * Optimize
  #
  #   type: -1 (all), 0 (weapon), 1-4 (armors)
  #--------------------------------------------------------------------------
  def optimize(type = -1)
    # Branch by type
    case type
    when -1
      # Optimize weapon
      EquipmentOptimzer.optimze_weapon(self)
      # Optimize all armor
      for i in 0..3
        EquipmentOptimzer.optimze_armor(self, i)
      end
    when 0
      # Optimize weapon
      EquipmentOptimzer.optimze_weapon(self)
    else
      # Optimize armor
      EquipmentOptimzer.optimze_armor(self, type - 1)
    end
  end
end
[/rgss]

Horray for filtering. :box:
 
Nice one.

I bring you another scriptlet for map names. Since we already now that we should forget about using more $variables than the ones the Maker loads if possible, this solution might help you a lot. Actually it works for both, XP and VX.

[rgss]module Map
  NAME = load_data(Dir.glob('Data/MapInfos*').to_s)
 
  def self.name(map_id); NAME[map_id].name.sub(/@.*/, '') end
end
[/rgss]

Script call:

Map.name(id) #=> Dark Castle
 
Ok. Here's a little something I wanted to try out. Basically works like an animated message window, but made this into a single sprite class and made it pretty easy to use.

Code:
#==============================================================================

# ** AnimatedTextSprite

#------------------------------------------------------------------------------

# SephirothSpawn

# Version 1.0

# 2010-02-18

#==============================================================================

 

class AnimatedTextSprite < Sprite

  #--------------------------------------------------------------------------

  # * Object Initialization

  #--------------------------------------------------------------------------

  def initialize(width, height, viewport = nil)

    super(viewport)

    self.bitmap = Bitmap.new(width, height)

    @text, @speed = [], 6

  end

  #--------------------------------------------------------------------------

  # * Refresh

  #--------------------------------------------------------------------------

  def refresh(text, speed = @speed, max_height = true)

    # Clear bitmap

    self.bitmap.clear

    # Save speed

    @speed = [speed, 1].max

    # Start text lines

    @lines = [[]]

    # Start x counter

    x = 0

    # Start text array

    @text = [[]]

    # Space width

    space_width = self.bitmap.text_size(' ').width

    # Pass through each word

    for word in text.split(' ')

      # Gets word width

      width = self.bitmap.text_size(word).width

      # If word cannot fit in line

      if x + width > self.bitmap.width

        # If x is 0

        if x == 0

          # Add word to line anyways

          word.split('').each {|s| @text.last << s}

          @text << []

          next

        end

        # Set x to width

        x = width + space_width

        # Add word to new line

        @text << []

        word.split('').each {|s| @text.last << s}

        @text.last << ' '

        next

      end

      # Add width and word

      x += width + space_width

      word.split('').each {|s| @text.last << s}

      @text.last << ' '

    end

    # Save text position and update

    @text_x = 0

    @text_y = 0

    @text_h = self.bitmap.font.size + 2

    # Max bitmap height

    max_bitmap_height if max_height

    update

  end

  #--------------------------------------------------------------------------

  # * Maximize Bitmap Height

  #--------------------------------------------------------------------------

  def max_bitmap_height

    # Get current number of text lines

    lines = @text.size

    # Get min height

    height = lines * @text_h

    # Resize bitmap if neccessary

    if self.bitmap.height < height

      self.bitmap = Bitmap.new(self.bitmap.width, height)

    end

  end

  #--------------------------------------------------------------------------

  # * Frame Update

  #--------------------------------------------------------------------------

  def update

    # Return if text is empty

    return if @text.empty?

    # Return if not draw frame

    return unless Graphics.frame_count % @speed == 0

    # Get current line of text

    line = @text.first

    # If empty line

    if line.empty?

      # Remove curremt line

      @text.shift

      # Return if empty

      return if @text.empty?

      # Adjust text position

      @text_x = 0

      @text_y += @text_h

    end

    # Get next character

    t = @text.first.shift

    # Draw character

    w = self.bitmap.text_size(t).width

    self.bitmap.draw_text(@text_x, @text_y, w + 2, @text_h, t)

    @text_x += w

  end

end

You create your sprite like always, and when you want to draw the animated text, just call
your_sprite.refresh(text, speed, resize)

text is just your long line of text. speed is just a simple Graphics.frame_count % speed == 0 test. Higher the speed, the slower the text. Resize is a checker I added that will resize the sprites height to make sure the text will be drawn on the bitmap.

If you want to test it:
Code:
$test = AnimatedTextSprite.new(320, 32)

$test.z = 999

 

class Scene_Title

  alias update2 update

  def update

    $test.update

    $test.refresh('This is about as long of line of text i could bare to type. just rambling here but whatever. i hope this works. blah blah blah.', rand(4) + 1) if Input.trigger?(Input::ALT)

    update2

  end

end

Just press alt when you are in the title screen. Works like a charm.
 
After seeing like 10 version of people and their Table classes, decided to simply this. Maybe I am just under thinking Tables, but I think people are over complicating them. So here is what I just came up with:
Code:
class Table

  Default = 0

  attr_reader :default

  def initialize(default = Default)

    @data = {}

    @data.default = default

  end

  def default=(default)

    @data.default = default

  end

  def [](*args)

    return @data[args]

  end

  def []=(*args)

    v = args.pop

    @data[args] = v

  end

  def each(&block)

    @data.each(&block)

  end

  def each_value(&block)

    @data.each_value(&block)

  end

end

It doesn't do anything special at all. It's just a wrapper of the Hash instead of an array. Supports unlimited dimensions (actually, all it does create a bunch of keys).
 
Here there are some silly but still useful methods for Sprite and Scene_Base classes...

[rgss]class Sprite
  def x_y(x, y); self.x, self.y = x, y; end
end
[/rgss]

[rgss]def exit?
    if Input.trigger?(Input::B) # If B button was pressed
      $game_system.se_play($data_system.cancel_se) # Play cancel SE
      $scene = Scene_Map.new # Switch to map screen
      return
    end
  end
[/rgss]

Normally, Sprite class wouldn't allow you to define the x and y coordinates while initializing it, so you would need to do something like this...

@sprite = Sprite.new(viewport)# if needed, otherwise don't include viewport
@sprite.x, @sprite.y = 0, 0

...but the last line would be different if you include the method I posted above...

@sprite.x_y(0,0)

It'd be just easier to setup the coordinates.

The exit? method is just a simple way to include the Cancel button in any scene script in the main update method so now we don't need to include the same 4 lines in every single script but just a single method call to exit to Scene_Map.
 
I like it. However, I kinda prefer a mixin for any class with x & y.

Code:
module Pos

  def set_pos(x, y)

    @x, @y = x, y

  end

  def pos

    return @x, @y

  end

end

 

class Sprite

  include Pos

end

 

class Window

  include Pos

end

I do like the exit update as well, however I suggest making it update_exit as methods with a ? typically only return true or false and do not have processing in them.
 
Right, or I could call it exit_scene_update or anything else. I forgot about the '?', I know I shouldn't have included that...

Well, then it'd also be a good idea to include this...

[rgss]module Pos
  def active_visible=(boolean)
    self.active, self.visible = boolean, boolean
  end
end
[/rgss]

Well, it could also be named w/o any = sign in between. That would be a good method to get rid of some inactive command menu for a while.
 
SephirothSpawn":2j5dysr9 said:
After seeing like 10 version of people and their Table classes, decided to simply this. Maybe I am just under thinking Tables, but I think people are over complicating them. So here is what I just came up with:
Code:
class Table

  Default = 0

  attr_reader :default

  def initialize(default = Default)

    @data = {}

    @data.default = default

  end

  def default=(default)

    @data.default = default

  end

  def [](*args)

    return @data[args]

  end

  def []=(*args)

    v = args.pop

    @data[args] = v

  end

  def each(&block)

    @data.each(&block)

  end

  def each_value(&block)

    @data.each_value(&block)

  end

end

It doesn't do anything special at all. It's just a wrapper of the Hash instead of an array. Supports unlimited dimensions (actually, all it does create a bunch of keys).

That's probably faster than all those complicated things, too, since Hash is actually faster than Array. What is missing, though, is a _dump and _load method that understands the Marshal serialization format of the built-in class. Those methods would be extremely useful for anybody trying to write an editor replacement.

Oh, and hi Seph.
 
Today I bring you 2 new (very similar) methods for the Array class.

[rgss]class Array
  def next
    @next = (@next.nil? or @next == self.size-1) ? 0 : @next+1
    return self[@next]
  end
  alias :succ :next
 
  def previous
    @prev = (@prev.nil? or @prev == 0) ? self.size-1 : @prev-1
    return self[@prev]
  end
  alias :prev :previous
end
[/rgss]

I know I configured it to create 2 separate instance variables, but you can use a single one instead, i.e. @pos instead of @next and @prev but it may work in a very different way than I'd expect.

Examples:

a = [1,4,9,7,5,2,4,8,9]
a.next #=> 1
a.next #=> 4
# a few extra lines in between
a.next #=> 9
a.next #=> 1
a.next #=> 4

The same would be valid for the "previous" method.

a.prev #=> 9
a.prev #=> 8
a.prev #=> 4
 
I really like that kyonides. Neat little idea to keep track of current index and provides a uniq way to pass through array objects.



Ok. While working on a Resolution System, I realized I had to redo the Graphics.transition effects process. So I made a little tool that transforms one bitmap into another (right now, just for sprites, but can be made a mixin pretty easily).

Code:
class Bitmap

  def dup

    dummy = Bitmap.new(width, height)

    dummy.blt(0, 0, self, self.rect)

    return dummy

  end

end

 

class Sprite

  alias_method :seph_spritetrans_update, :update

  def update

    if @transition != nil

      @transition.update

      @transition = nil if @transition.done?

    end

    seph_spritetrans_update

  end

  def transition(target_bitmap, transition_file = '001-Blind01', 

                 frames = 10, stretch = true)

    self.bitmap = self.bitmap.dup

    @transition = Sprite::Transition.new(self.bitmap, target_bitmap, transition_file, frames, stretch)

  end

end

 

class Sprite::Transition

  def initialize(old_bitmap, target_bitmap, transition_file, frames, stretch)

    @old_bitmap = old_bitmap

    @target_bitmap = target_bitmap

    bitmap = RPG::Cache.load_bitmap("Graphics/Transitions/", transition_file)

    @tranisition_bitmap = Bitmap.new(@target_bitmap.width, @target_bitmap.height)

    if stretch

      @tranisition_bitmap.stretch_blt(@tranisition_bitmap.rect, bitmap, bitmap.rect)

    else

      @tranisition_bitmap.blt(0, 0, bitmap, bitmap.rect)

    end

    @frame = 0

    @frames = frames

    @dpf = 255.0 / @frames

  end

  def dist(color)

    n = 0

    n += color.red

    n += color.green

    n += color.blue

    return (n / 3.0)

  end

  def update

    @frame += 1

    min_d = (@frame - 1) * @dpf

    max_d = @frame * @dpf

    for x in 0...@tranisition_bitmap.width

      for y in 0...@tranisition_bitmap.height

        d = dist(@tranisition_bitmap.get_pixel(x, y))

        next unless d.between?(min_d, max_d)

        @old_bitmap.set_pixel(x, y, @target_bitmap.get_pixel(x, y))

      end

    end

  end

  def done?

    return @frame >= @frames

  end

end

It is slow because it passes through each pixel for each time for each frame it undergoes the transition. I tried keeping a list of pixels to skip if they have been set (x/y coordinates) but that actually slowed it down significantly. The best thing I could do is add a min_d value, and only continue to pixel mods when it was between the min_d and max_d variables.

The algorithm I came up was pretty simple: each pixel is given a "d" value (why I choose name d, just because) from 0 to 255. The d is equal to

(red + green + blue) / 3.0

It finds the average rgb on a 0 to 255 scale

The original bitmap must be duplicated to prevent modifications to the bitmaps stored in RPG::Cache

It passes through each pixel on the transition bitmap and gets the d value. If the d value if set for the current frame (between last frame "d" and current frame "d", where frame "d" = 255.0 / @frames * frame), it gets the target bitmap pixel at same position and sets it on the old bitmap as the same position.


EDIT: If you want to see a sample:
Code:
class Scene_Title

  alias_method :seph_test_main,   :main

  alias_method :seph_test_update, :update

  def main

    @test_sprite = Sprite.new

    @test_sprite.z = 999

    @test_sprite.bitmap = RPG::Cache.battler('085-Elemental03', 0)

    seph_test_main

    @test_sprite.dispose

  end

  def update

    if Input.trigger?(Input::ALT)

      target = RPG::Cache.battler('060-Aquatic02', 0)

      @test_sprite.transition(target)

    end

    @test_sprite.update

    seph_test_update

  end

end

Just press Alt on the title screen.
 
That looks good, Seph. Have you tried the User32 mix-in module I made? Speaking of which, I've made some additions to it that make SetWindowLong that much more useful:

[rgss]#===============================================================================
# ** User32
#-------------------------------------------------------------------------------
#    Wrapper for user32.dll functions. Use "include User32" to get the constants
#===============================================================================
 
module User32
  GSM                 = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')
  SetWindowPos        = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')
  SetWindowLong       = Win32API.new('user32', 'SetWindowLong', 'LIL', 'L')
  Keybd_Event         = Win32API.new('user32', 'keybd_event', 'LLLL', '')
  FindWindow          = Win32API.new('user32', 'FindWindow', 'PP', 'L')
  GetDesktopWindow    = Win32API.new('user32', 'GetDesktopWindow', '', 'L')
  GetWindowInfo       = Win32API.new('user32', 'GetWindowInfo', 'LP', 'I')
  SetForegroundWindow = Win32API.new('user32', 'SetForegroundWindow', 'L', 'L')
  GetCursorPos        = Win32API.new('user32', 'GetCursorPos', 'P', 'I')
  ShowCursor          = Win32API.new('user32', 'ShowCursor', 'L', 'L')
  ScreenToClient      = Win32API.new('user32', 'ScreenToClient', 'LP', 'I')
  GetKeyState         = Win32API.new('user32', 'GetKeyState', 'I', 'I')
  GetAsyncKeyState    = Win32API.new('user32', 'GetAsyncKeyState', 'I', 'I')
 
  HWND = FindWindow.call('RGSS Player', Settings['Title'])
 
  # GSM constants. For more complete descriptions, see Microsoft's website:
  # http://msdn.microsoft.com/en-us/library/ms724385(VS.85).aspx
  SM_CXSCREEN      = 0  # Width of the current master screen resolution
  SM_CYSCREEN      = 1  # Height of the current master screen resolution
 
  SM_CXVSCROLL     = 2  # Width of a vertical scroll bar
  SM_CYHSCROLL     = 3  # Height of a horizontal scroll bar
 
  SM_CYCAPTION     = 4  # Height of a caption area
 
  SM_CXBORDER      = 5  # Width of a window border
  SM_CYBORDER      = 6  # Height of a window border
 
  SM_CXDLGFRAME    = 7
  SM_CXFIXEDFRAME  = 7  # Width of non-resizable captioned window frame
  SM_CYDLGFRAME    = 8
  SM_CYFIXEDFRAME  = 8  # Height of non-resizable captioned window frame
 
  SM_CYVTHUMB      = 9  # Height of a thumb button on vertical scrollbars
  SM_CXHTHUMB      = 10 # Width of a thumb button on horizontal scrollbars
 
  SM_CXICON        = 11 # Default width of an icon
  SM_CYICON        = 12 # Default height of an icon
 
  SM_CXCURSOR      = 13 # Width of a cursor
  SM_CYCURSOR      = 14 # Height of a cursor
 
  SM_CYMENU        = 15 # Height of a single-line menu bar
 
  SM_CXFULLSCREEN  = 16 # Width of client rect for a full-screen window
  SM_CYFULLSCREEN  = 17 # Height of client rect for a full-screen window
 
  SM_CYKANJIWINDOW = 18 # Height of kanji window at bottom of screen, if there
 
  SM_MOUSEPRESENT  = 19 # Non-zero if mouse is present; 0 if not
 
  SM_CYVSCROLL     = 20 # Height of the arrow bitmap on vertical scrollbars
  SM_CXHSCROLL     = 21 # Width of the arrow bitmap on horizontal scrollbars
 
  SM_DEBUG         = 22 # Non-zero if debug User.exe is installed; 0 if not
  SM_SWAPBUTTON    = 23 # Non-zero if mouse button values are swapped
 
  SM_CXMIN         = 28 # Minimum width of a window
  SM_CYMIN         = 29 # Minimum height of a window
 
  SM_CXSIZE        = 30 # Width of a button in a window caption or title bar
  SM_CYSIZE        = 31 # Height of a button in a window caption or title bar
 
  SM_CXFRAME       = 32
  SM_CXSIZEFRAME   = 32 # Width of the sizing border around a resizable window
  SM_CYFRAME       = 33
  SM_CYSIZEFRAME   = 33 # Height of the sizing border around a resizable window
 
  SM_CXMINTRACK    = 34 # Minimum "tracking" width of a window
  SM_CYMINTRACK    = 35 # Minimum "tracking" height of a window
 
  SM_CXDOUBLECLK   = 36 # Width of rect which second click must be in for double
  SM_CYDOUBLECLK   = 37 # Hght of rect which second click must be in for double
 
  SM_CXICONSPACING = 38 # Width of a grid cell for items in large icon view
  SM_CYICONSPACING = 39 # Height of a grid cell for items in large icon view
 
  SM_MENUDROPALIGNMENT = 40 # 0 if drop-down menus are left-aligned...
 
  SM_PENWINDOWS    = 41 # Non-zero if Microsoft Windows for Pen computing
                        #  extensions are installed; 0 if not
 
  SM_DBCSENABLED   = 42 # Non-zero if user32.dll supports DBCS; 0 if not
 
  SM_CMOUSEBUTTONS = 43 # Number of available mouse buttons, or 0 for no mouse
 
  SM_SECURE        = 44 # Always returns 0
 
  SM_CXEDGE        = 45 # Width of a 3-D style border
  SM_CYEDGE        = 46 # Height of a 3-D style border
 
  SM_CXMINSPACING  = 47 # Width of a grid cell for minimized windows
  SM_CYMINSPACING  = 48 # Height of a grid cell for minimized windows
 
  SM_CXSMICON      = 49 # Recommended width of a small icon
  SM_CYSMICON      = 50 # Recommended height of a small icon
 
  SM_CYSMCAPTION   = 51 # Height of a small caption
  SM_CXSMSIZE      = 52 # Width of small caption buttons
  SM_CYSMSIZE      = 53 # Height of small caption buttons
  SM_CXMENUSIZE    = 54 # Width of menu bar buttons
  SM_CYMENUSIZE    = 55 # Height of menu bar buttons
 
  SM_ARRANGE       = 56 # Flags about how system the arranges minimized windows
  SM_CXMINIMIZED   = 57 # Width of a minimized window
  SM_CYMINIMIZED   = 58 # Height of a minimized window
 
  SM_CXMAXTRACK    = 59 # Default maximum width of resizable windows
  SM_CYMAXTRACK    = 60 # Default maximum height of resizable windows
  SM_CXMAXIMIZED   = 61 # Default width of maximized top-level window
  SM_CYMAXIMIZED   = 62 # Default height of maximized top-level window
 
  SM_NETWORK       = 63 # The least significant bit is set if a network is
                        #  present; otherwise, it is cleared
 
  SM_CLEANBOOT     = 67 # System boot type; 0:Normal, 1:Safe, 2:Safe w/network
 
  SM_CXDRAG        = 68
  SM_CYDRAG        = 69 # Number of pixels mouse can move before initiating drag
 
  SM_SHOWSOUNDS    = 70 # Non-zero if user requires visible output; 0 if not
 
  SM_CXMENUCHECK   = 71 # Width of the default menu check-mark bitmap
  SM_CYMENUCHECK   = 72 # Height of the default menu check-mark bitmap
 
  SM_SLOWMACHINE   = 73 # Non-zero if system has a slow processor; 0 if not
                        #  No, seriously, that's what Microsoft said!
 
  SM_MIDEASTENABLED = 74 # Non-zero if system can use Hebrew, Arabic languages
 
  SM_MOUSEWHEELPRESENT = 75 # Nonzero mouse has vertical scroll wheel; 0 if not
 
  SM_XVIRTUALSCREEN    = 76 # Coordinates of the left side of the virtual screen
  SM_YVIRTUALSCREEN    = 77 # Coordinates of the top of the virtual screen
  SM_CXVIRTUALSCREEN   = 78 # Virtual width of all screens put together
  SM_CYVIRTUALSCREEN   = 79 # Virtual height of all screen put together
  SM_CMONITORS         = 80 # Numbers of display monitors on a desktop
  SM_SAMEDISPLAYFORMAT = 81 # Non-zero if all screen use same color depth...
 
  # SetWindowPos constants
  HWND_NOTOPMOST      = -2  # Make window not always on top (and bring to front)
  HWND_TOPMOST        = -1  # Put window in front and make it always on top
  HWND_TOP            = 0   # Put window in front of all non-topmost windows
  HWND_BOTTOM         = 1   # Put window behind all other windows
 
  SWP_NOSIZE          = 0x0001 # Keep current size (ignores w and h)
  SWP_NOMOVE          = 0x0002 # Keep current position (ignores X and Y)
  SWP_NOZORDER        = 0x0004 # Keep current Z order (ignores hWndInsertAfter)
  SWP_NOREDRAW        = 0x0008 # Does NOT redraw changes
  SWP_NOACTIVATE      = 0x0010 # Does NOT automatically activate the window
  SWP_FRAMECHANGED    = 0x0020 # Applies new frame styles set with SetWindowLong
  SWP_SHOWWINDOW      = 0x0040 # Displays the window
  SWP_HIDEWINDOW      = 0x0080 # Hides the window
  SWP_NOCOPYBITS      = 0x0100 # Discards the entire contents of the client area
  SWP_NOOWNERZORDER   = 0x0200 # Doesn't change the window display order
  SWP_NOSENDCHANGING  = 0x0400 # Don't send WM_WINDOWPOSCHANGING
  SWP_DEFERERASE      = 0x2000 # Prevents generation of the WM_SYNCPAINT message
  SWP_ASYNCWINDOWPOS  = 0x4000 # Use if calling thread does not own the window
 
  # SetWindowLong constants
  GWL_USERDATA        = -21 # Sets data reserved for use by the application
  GWL_EXSTYLE         = -20 # Sets a new extended window style
  GWL_STYLE           = -16 # Sets a new window style
  GWL_ID              = -12 # Sets a new identifier of the window
  GWL_HWNDPARENT      = -8  # Sets a new parent hWnd
  GWL_HINSTANCE       = -6  # Sets a new application instance handle
  GWL_WNDPROC         = -4  # Sets a new addr for the window calling procedure
  # Only available when the hWnd parameter identifies a dialog box:
  DWL_MSGRESULT       = 0   # Sets the return message of the dialog box proc
  DWL_DLGPROC         = 4   # Sets the new address of the dialog box proc
  DWL_USER            = 8   # Sets new extra information private to application
 
  # Window Styles (SetWindowLong(hWnd, GWL_STYLE, WS_*))
  WS_OVERLAPPED       = 0x00000000 # Overlapped window has title and border
  WS_TABSTOP          = 0x00010000 # Can receive focus from TAB key
  WS_GROUP            = 0x00020000 # First control of group of controls
  WS_MAXIMIZEBOX      = 0x00010000 # Has a mazimize button
  WS_MINIMIZEBOX      = 0x00020000 # Has a minimize button
  WS_THICKFRAME       = 0x00040000 # Has sizing border
  WS_SYSMENU          = 0x00080000 # Has buttons on title bar (reqs WS_CAPTION)
  WS_HSCROLL          = 0x00100000 # Has horizontal scroll bar
  WS_VSCROLL          = 0x00200000 # Has vertical scroll bar
  WS_DLGFRAME         = 0x00400000 # Dialog-style border. Cannot have title bar
  WS_BORDER           = 0x00800000 # Thin border
  WS_CAPTION          = 0x00C00000 # Has a title bar (implies WS_BORDER)
  WS_MAXIMIZE         = 0x01000000 # Initially maximized
  WS_CLIPCHILDREN     = 0x02000000 # Exclude area for children when drawing
  WS_CLIPSIBLINGS     = 0x04000000 # Exclude sibling client rects when drawing
  WS_DISABLED         = 0x08000000 # Initially disabled (no input)
  WS_VISIBLE          = 0x10000000 # Initially visible
  WS_MINIMIZE         = 0x20000000 # Initially minimized
  WS_CHILD            = 0x40000000 # Child cannot have menu bar or WS_POPUP
  WS_POPUP            = 0x80000000 # Popup window
  # Window style aliases
  WS_OVERLAPPEDWINDOW = WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|
                        WS_MINIMIZEBOX|WS_MAXIMIZEBOX
  WS_POPUPWINDOW      = WS_POPUP|WS_BORDER|WS_SYSMENU
  WS_CHILDWINDOW      = WS_CHILD
  WS_TILED            = WS_OVERLAPPED
  WS_ICONIC           = WS_MINIMIZE
  WS_SIZEBOX          = WS_THICKFRAME
  WS_TILEDWINDOW      = WS_OVERLAPPEDWINDOW
end
 
[/rgss]

Example usage (using the SetResolution dll by Selwyn which is defined as constant Set_Res):

[rgss]  def self.fullscreen
    @default_size = size
    SetWindowLong.call(HWND, GWL_STYLE, WS_VISIBLE|WS_CLIPSIBLINGS)
    SetWindowPos.call(HWND, HWND_TOPMOST, 0, 0, @width, @height, SWP_SHOWWINDOW)
    Set_Res.call(@width, @height, 4)
    @fullscreen = true
  end
  def self.default
    SetWindowLong.call(HWND, GWL_STYLE, WS_VISIBLE|WS_CLIPSIBLINGS|
                                        WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX)
    w = @width + (2 * GSM.call(SM_CXFIXEDFRAME))
    h = @height + (2 * GSM.call(SM_CYFIXEDFRAME)) + GSM.call(SM_CYCAPTION)
    x = (@default_size[0] - w) / 2
    y = (@default_size[1] - h) / 2
    SetWindowPos.call(HWND, HWND_TOP, x, y, w, h, SWP_SHOWWINDOW)
    Set_Res.call(@default_size[0], @default_size[1], 0)
    @fullscreen = false
  end
 
[/rgss]

But I'm here to add a feature to RGSS that was thankfully built into RGSS2: Sprite#viewport=. It was actually rather difficult, and the process of changing viewport is time-consuming (as it has to create a new sprite and copy all of the attributes over) but this solution should drop in with only minimal hit to resources:

[rgss]#===============================================================================
# ** Sprite
#-------------------------------------------------------------------------------
#    In order to provide a viewport= method, this class has been heavily
#    reworked as a "server" class which keeps a Sprite::Binding object which
#    it calls methods on.
#===============================================================================
 
class Sprite
  #-----------------------------------------------------------------------------
  # * Create a duplicate class Sprite::Binding
  #-----------------------------------------------------------------------------
  Binding = Sprite.dup
  Attributes = [ 'bitmap', 'src_rect', 'visible', 'x', 'y', 'z', 'ox', 'oy',
                 'zoom_x', 'zoom_y', 'angle', 'mirror', 'bush_depth', 'opacity',
                 'blend_type', 'color', 'tone' ]
  #-----------------------------------------------------------------------------
  # * For each instance method, redefine the method to send to the binding
  #-----------------------------------------------------------------------------
  instance_methods(false).each do |symbol|
    define_method(symbol) do |*args|
      begin
        @_binding.__send__(symbol, *args)
      rescue Exception
        # Remove from the backtrace the four entries pointing to this block
        3.times { $!.backtrace.shift }
        raise $!
      end
    end
  end
  #-----------------------------------------------------------------------------
  # * Create the binding on initialization
  #-----------------------------------------------------------------------------
  def initialize(viewport = nil)
    @_binding = Binding.new(viewport)
  end
  #-----------------------------------------------------------------------------
  # * Set new viewport; dispose existing sprite and create new one with viewport
  #-----------------------------------------------------------------------------
  def viewport=(viewport)
    # Skip if binding already uses this viewport
    return @_binding.viewport if @_binding.viewport == viewport
    old = @_binding                   # Cache old binding
    @_binding = Binding.new(viewport) # Create a new sprite with this viewport
    # Copy attributes over from the old binding
    Attributes.each { |sym| @_binding.__send__(sym + '=', old.__send__(sym)) }
    old.dispose                       # Dispose old binding
    @_binding.viewport                # Return new viewport
  end
end
 
[/rgss]

What that does is it copies the Sprite class into Sprite::Binding, then proceeds to rewrite all of the Sprite methods to redirect to a @_binding object created at initialization! It really does work, even with classes which extend the Sprite class. Just make sure you put that code at the top, before anything that makes a Sprite, or the Sprite created before this code will fail.
 
I like the User32 module. The only thing I do differently is rather than creating constants, I create methods instead that send api arguments and call arguments to a method within a parent API module that creates Win32API objects and lowers amount of API calls (and multiple constants sharing the same method.

Code:
#============================================================================== 

# ** API

#------------------------------------------------------------------------------

# SephirothSpawn

# 2010-03-12

#------------------------------------------------------------------------------

# * Library

#

# API:

# ---------------------------------------------------------------------------

# API.call

# API.hwnd

#==============================================================================

 

module API

  #-------------------------------------------------------------------------

  # * Create API Function List

  #-------------------------------------------------------------------------

  @functions = {}

  #-------------------------------------------------------------------------

  # * Name      : Call API Function

  #   Version   : 1.0

  #   Author    : SephirothSpawn

  #   Call Info : API Arguments, Function Arguments

  #

  #   API.call(['dll', 'function', 'args', 'return'], function_args)

  #-------------------------------------------------------------------------

  def self.call(api_arguments, function_arguments)

    # If key not found

    unless @functions.has_key?(api_arguments)

      @functions[api_arguments] = Win32API.new(*api_arguments)

    end

    # Call Function

    @functions[api_arguments].call(*function_arguments)

  end

  #-------------------------------------------------------------------------

  # * Name      : Handel

  #   Version   : 1.0

  #   Author    : SephirothSpawn

  #   Call Info : Gets Game Handel

  #-------------------------------------------------------------------------

  def self.hwnd

    # Return if already found

    return @hwnd if @hwnd != nil

    # Find Handel

    hwnd = "\0" * 256

    call_args = ['Game', 'Title', '', hwnd, 255, ".\\Game.ini"]

    API::Kernel32.GetPrivateProfileString(*call_args)

    hwnd.delete!("\0")

    @hwnd = API::User32.FindWindow('RGSS Player', hwnd)

  end

end

Essientialy, rather than have

User32::Method_Name.call(args)

API::User32.method_name(args)



But love all the neat little constants. I tried looking for them myself, but that was back when I really wasn't into API all that much.


Love the sprite#viewport= binding. I almost did that same thing as well without the binding aspect, but your way is hella sexy. Very nice.
 
I kind of like that idea for an API module. And you are wrapping that with individual functions like User32.SetWindowLong(args) and User32.FindWindow(args)? I guess you are since I see that in your hwnd function. I would still prefer to define HWND once as a constant, though.

I've gotten into the habit of using certain functions instead of others due to "performance" reasons, such as using object.nil? (presumably defined as def nil? ; false ; end in Object and overloaded in NilClass as def nil? ; true ; end) instead of object == nil (which presumably checks nil values first, but it's a much larger function that tends to get overloaded in other objects, some of which might have forgotten to check for nil values if they're particularly stupid). Another is to not use "return" on the last line of a function. It's stylistically consistent with most of the rest of the Ruby world, though I can only speculate as to whether it's faster or not.

I found this file that has a lot of Windows constants defined. There are a lot of constants in there I haven't added yet, because I haven't needed to use them yet. It's not like this is some kind of comprehensive User32 wrapper class that defines everything you might ever possibly need. It does the stuff that one might need to messing with the game window, the mouse, or the keyboard.
 

Thank you for viewing

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

Discord

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

Content

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