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.

MACL - Method and Class Library 2.3

I'll be more clear: you usually have a window with a list of commands and browse through the list with UP and DOWN. With this add-on you can set two commands to be selected with RIGHT and LEFT, respectively. Say, you press LEFT and the cursor moves directly to the specified command.

I use this in my CTB in such a way that LEFT automatically selects the Guard/Defend command:
Code:
    @actor_command_window.set_left_shortcut($data_system.words.guard)
 
I would think that Window_Command.update would be better served by having the super at the end of your additions.  Then you wouldn't have to update_help and update_cursor_rect (which ends up calling them twice!).  The right and left commands in Window_Selectable only work if @column_max >= 2 anyway.
 
I agree. Updated. (EDIT: ah, my copy and paste fever...  :tongue2:)
The user is supposed to use this feature with 1-column command windows only. Otherwise I could put the code in the update method inside an "if @column_max==1" block.
 
That and you have Window_HorizCommand too, but thats another story.

I do see what you're saying now though, I was thinking of adding a columns thing to my Window_Commands too, but they'd be slidable columns, where the one command slides off and the other command slides in when you push Right/Left (while the other commands remain where they are.) If thats what you're talking about, and you're doing it, keep doing it, we could use it if it turns out good.

Here is my contributions for the day...

Lets say you want to specify a window at the Top/Bottom/Left/Right, or the appropriate corners, or even center, you can just do the following.

@window.position(0) for Center
@window.position(2) for Center Bottom
@window.position(4) for Center Left
@window.position(7) for Top Left
@window.position(3) for Low Right

etc, etc, if you know your directional numpad then you're smart enough to use this snippet (at least we all hope.)

Also, for whatever side/corner you place it on, setting the offset is as simple as...

@window.position(4, 16)

Which means it'll be Center at the Left edge of the screen, and offset away from the edge would be 16 pixels. However, doing something like

@window.position(5, 16) or @window.position(0, 16)

Won't get you anywhere, because 5 and 0 are just Center, whats the point in offsetting the center?.

Code:
class Window_Base
  #-----------------------------------------------------------------------------
  # * Set Position
  #-----------------------------------------------------------------------------
  def position(edge = 0, offset = 16)
    if edge.is_a?(Integer) ; edge = 0 if edge == 5
    else ; return
    end
    o = offset.is_a?(Integer) ? offset : 0
    case edge
    when 0 # Center
      self.x, self.y = (320 - (self.width / 2)) , (240 - (self.height / 2))
    when 2 # Center Bottom
      self.x, self.y = (320 - (self.width / 2)) , (480 - (self.height))
      unless o.zero? ; self.y -= o ; end
    when 4 # Center Left
      self.x, self.y = 0                        , (240 - (self.height / 2))
      unless o.zero? ; self.x += o ; end
    when 6 # Center Right
      self.x, self.y = (640 - self.width)       , (240 - (self.height / 2))
      unless o.zero? ; self.x -= o ; end
    when 8 # Center Top
      self.x, self.y = (320 - (self.width / 2)) , 0
      unless o.zero? ; self.y += o ; end
    when 1 # Lower Left
      self.x, self.y = (0)                      , (480 - self.height)
      unless o.zero? ; self.x += o ; self.y -= o ; end
    when 3 # Lower Right
      self.x, self.y = (640 - self.width)       , (480 - self.height)
      unless o.zero? ; self.x -= o ; self.y -= o ; end
    when 7 # Upper Left
      self.x, self.y = 0                        , 0
      unless o.zero? ; self.x += o ; self.y += o ; end
    when 9 # Upper Right
      self.x, self.y = 640 - self.width         , 0
      unless o.zero? ; self.x -= o ; self.y += o ; end
    end
  end
end

All windows placed on all sides/corners and center with simple code, at an offset from the edge of 16 pixels. View next spoiler to see how simple it is!

http://i224.photobucket.com/albums/dd28 ... Image1.png[/img]

Code:
@w0 = Window_Base.new(0,0,128,128)
@w1 = Window_Base.new(0,0,128,128)
@w3 = Window_Base.new(0,0,128,128)
@w7 = Window_Base.new(0,0,128,128)
@w9 = Window_Base.new(0,0,128,128)
@w2 = Window_Base.new(0,0,128,128)
@w4 = Window_Base.new(0,0,128,128)
@w6 = Window_Base.new(0,0,128,128)
@w8 = Window_Base.new(0,0,128,128)
@w0.position(5,16)
@w2.position(2,16)
@w4.position(4,16)
@w6.position(6,16)
@w8.position(8,16)
@w1.position(1,16)
@w3.position(3,16)
@w7.position(7,16)
@w9.position(9,16)

Code:
MACL::Loaded << 'RGSS.Party'

#===============================================================================
# ** Game_Party
#-------------------------------------------------------------------------------
#   Added some simple methods for gaining/losing all items & equipment.
#===============================================================================

class Game_Party
  #-----------------------------------------------------------------------------
  # * Gain All (Type, -Quantity)
  #-----------------------------------------------------------------------------
  def gain_all(type, quantity = 99)
    if type.is_a?(Fixnum)
      case type
      when -1
        for i in 0...$data_items.size   ; gain_item(i,   quantity) ; end
        for i in 0...$data_weapons.size ; gain_weapon(i, quantity) ; end
        for i in 0...$data_armors.size  ; gain_armor(i,  quantity) ; end
      when 0 ; for i in 0...$data_items.size   ; gain_item(i,   quantity) ; end
      when 1 ; for i in 0...$data_weapons.size ; gain_weapon(i, quantity) ; end
      when 2 ; for i in 0...$data_armors.size  ; gain_armor(i,  quantity) ; end
      end
    end
  end
  #-----------------------------------------------------------------------------
  # * Lose All (Type, -Quantity)
  #-----------------------------------------------------------------------------
  def lose_all(type, quantity = 99)
    if quantity > 0 ; quantity *= -1 ; end
    gain_all(type, quantity)
  end
end

With this script, you use the syntax listed like so...

$game_party.gain_all(0, 5) #<--Gain all Items (x5).
$game_party.gain_all(1)     #<--Gain all Weapons (x99 since you didn't specify a quantity)
$game_party.gain_all(-1)    #<--Gains all Items, Weapons and Armor (x99 again, no second arg)

Then you have '$game_party.lose_all()' which is basically a reverse of the example method.

Code:
  #-------------------------------------------------------------------------
  # * Name      : Exists?
  #   Info      : Tests to see if Map exists
  #   Author    : Kain Nobel
  #   Call Info : id = Map ID in question
  #-------------------------------------------------------------------------
  def exists?(id)
    if    id.between?(100, 999) ; filename = "Data/Map"   + id.to_s + ".rxdata"
    elsif id.between?( 10,  99) ; filename = "Data/Map0"  + id.to_s + ".rxdata"
    elsif id.between?(  1,   9) ; filename = "Data/Map00" + id.to_s + ".rxdata"
    else                        ; return false
    end
    return FileTest.exist?(filename)
  end

Basically, this returns the name of the specified map in question to a string. The arg is optional, by default it pulls the current player's map ID, but you can specify an arg to pull a name from a certain map.

Code:
class Game_Map
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_reader :map_id
  attr_reader :map_name
  #--------------------------------------------------------------------------
  # * Name      : Map Name
  #   Info      : Sends name of the map in question to a string
  #   Author    : Kain Nobel
  #   Call Info : id = Optional arg, returns name of specified ID
  #--------------------------------------------------------------------------
  def map_name(id = @map_id)
    @map_name = load_data("Data/MapInfos.rxdata") 
    return @map_name[id].name
  end
end

I made these simple additions for fun, hopefully you'll find them useful! :thumb:
 
It's possible to write your gain_all and lose_all functions so much more simply using Ruby's syntax.  For example, instead of writing:
Code:
        for i in 0...$data_items.size   ; gain_item(i,   quantity) ; end
You could write:
Code:
        $data_items.each_index {|i| gain_item(i, quantity)}
Instead of:
Code:
    if quantity > 0 ; quantity *= -1 ; end
You could write:
Code:
    quantity *= -1 if quantity > 0

Aside from that, I'd say the lose_all function could be pretty useful, especially if it could store the items that you lost in an array and return them to the party later.
 
better than
Code:
 quantity *= -1 if quantity > 0
could be
Code:
 quantity = -quantity.abs

Code:
  def map_name(id = @map_id)
    @map_name = load_data("Data/MapInfos.rxdata") 
    return @map_name[id].name
  end

better and faster:
Code:
  def map_name(id = @map_id)
    @map_info ||= load_data("Data/MapInfos.rxdata") 
    return @map_info[id].name
  end

info: it exist a string iternal for 3 length
 
That's even better.  I'm just excited about using .each do statements myself, since I've only started working with them in my recent bout of scripting ;)
 
Glad to see everybody teaming together to clean up my code!

I noticed you changed...
Code:
@map_name = load_data("Data/MapInfos.rxdata")
to...
Code:
@map_name ||= load_data("Data/MapInfos.rxdata")
What is that supposed to do? o.O

Here, I updated RGSS.Party with your suggestions, and added something for easily obtaining any average stat from the game party's actors. Here's a simple example.

Code:
$game_party.average('MaxHP') #<--Obtains average MaxHP of all actors (in your party.)


Code:
MACL::Loaded << 'RGSS.Party'

#===============================================================================
# ** Game_Party
#-------------------------------------------------------------------------------
#   Added some simple methods for checking party averages and some other stuff.
#===============================================================================

class Game_Party
  #-----------------------------------------------------------------------------
  # * Average
  #-----------------------------------------------------------------------------
  def average(stat, float = false)
    avg   = float ? 0.0 : 0
    case stat.downcase!
    when 'hp'    ; @actors.each_index {|i| avg += @actors[i].hp}
    when 'maxhp' ; @actors.each_index {|i| avg += @actors[i].maxhp}
    when 'sp'    ; @actors.each_index {|i| avg += @actors[i].sp}
    when 'maxsp' ; @actors.each_index {|i| avg += @actors[i].maxsp}
    when 'level' ; @actors.each_index {|i| avg += @actors[i].level}
    when 'exp'   ; @actors.each_index {|i| avg += @actors[i].exp}
    when 'str'   ; @actors.each_index {|i| avg += @actors[i].str}
    when 'dex'   ; @actors.each_index {|i| avg += @actors[i].dex}
    when 'agi'   ; @actors.each_index {|i| avg += @actors[i].agi}
    when 'int'   ; @actors.each_index {|i| avg += @actors[i].int}
    when 'atk'   ; @actors.each_index {|i| avg += @actors[i].atk}
    when 'pdef'  ; @actors.each_index {|i| avg += @actors[i].pdef}
    when 'mdef'  ; @actors.each_index {|i| avg += @actors[i].mdef}
    when 'eva'   ; @actors.each_index {|i| avg += @actors[i].eva}
    end
    return avg / @actors.size
  end
  #-----------------------------------------------------------------------------
  # * Gain All (Type, -Quantity)
  #-----------------------------------------------------------------------------
  def gain_all(type, quantity = 99)
    if type.is_a?(Fixnum) && type.between?(-1, 2)
      case type
      when -1
        $data_items.each_index    {|i| gain_item(i, quantity)}
        $data_weapons.each_index  {|i| gain_weapon(i, quantity)}
        $data_armors.each_index   {|i| gain_armor(i, quantity)}
      when 0 ; $data_items.each_index   {|i| gain_item(i, quantity)}
      when 1 ; $data_weapons.each_index {|i| gain_weapon(i, quantity)}
      when 2 ; $data_armors.each_index  {|i| gain_armor(i, quantity)}
      end
    end
  end
  #-----------------------------------------------------------------------------
  # * Lose All (Type, -Quantity)
  #-----------------------------------------------------------------------------
  def lose_all(type, quantity = 99)
    quantity = -quantity.abs if quantity > 0
    gain_all(type, quantity)
  end
end

Please note, at least one of the letters in the string must be a cap when calling the arg though, or it'll return 0.

$game_party.average('SP') #=> 1442
$game_party.average('Sp') #=> 1442
$game_party.average('sp') #=> 0
 
You'll also notice that he changed the variable name to @map_info.  That would be a proper name for the variable, as it is not indeed a string but an RPG::MapInfo object, for which @map_info[id].name is a String.  As the data only needs to be loaded once, loading it every time you call the name function is resource intensive.
 
Some advanced stuff for people who use a 8 direction movement script, or who want to make scripts based off 8 directional movement. Also, I added $game_map.no_tile?(x, y) which checks if tile on layer 1, 2, 3 are all tile id 0.

Also (I did this specifically for my jump script so you can't jump into the background), I aliased Game_Character passable? so that you can't move through a spot in which there is absolutely no tile in place. This is optional, feel free to remove it if you want. Besides, something about being able to normally walk on 'blank' tiles always bugged me, thats why I did it damnit!

Code:
#===============================================================================
# ** Game_Map
#-------------------------------------------------------------------------------
#  Added a method which will determine if jump is disabled on this map.
#===============================================================================
class Game_Map
  #-----------------------------------------------------------------------------
  # * Tile Blank?
  #-----------------------------------------------------------------------------
  def no_tile?(x, y)
    for i in 0..2
      return true if data[x,y,i].nil?
    end
    return data[x, y, 2].zero? && data[x, y, 1].zero? && data[x, y, 0].zero?
  end
end

#===============================================================================
# ** Game_Character
#-------------------------------------------------------------------------------
#   This class has been enhanced to check which of the 8 directions a character
# is moving. Also enhanced passable?() so that you can't pass a spot which all
# 3 layers are tile #0.
#===============================================================================
class Game_Character
  #-----------------------------------------------------------------------------
  # * Alias Listings
  #-----------------------------------------------------------------------------
  alias_method :no_tile_passable?,                    :passable?
  #-----------------------------------------------------------------------------
  # * Passable? (*Aliased*)
  #-----------------------------------------------------------------------------
  def passable?(x, y, d)
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    return $game_map.no_tile?(new_x, new_y) ? false : no_tile_passable?(x, y, d)
  end
  #-----------------------------------------------------------------------------
  # * Moving Down?
  #-----------------------------------------------------------------------------
  def moving_down?(diag = false)
    if diag ; return (self.real_y < self.y*128) && (self.real_x == self.x*128)
    end ; return (self.real_y < self.y * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Left?
  #-----------------------------------------------------------------------------
  def moving_left?(diag = false)
    if diag ; return (self.real_x > self.x*128) && (self.real_y == self.y*128)
    end ; return (self.real_x > self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Right?
  #-----------------------------------------------------------------------------
  def moving_right?(diag = false)
    if diag ; return (self.real_x < self.x*128) && (self.real_y == self.y*128)
    end ; return (self.real_x < self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Left?
  #-----------------------------------------------------------------------------
  def moving_up?(diag = false)
    if diag ; return (self.real_y > self.y*128) && (self.real_x == self.x*128)
    end ; return (self.real_y > self.y * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Lower Left?
  #-----------------------------------------------------------------------------
  def moving_lower_left?
    return (self.real_y < self.y * 128) && (self.real_x > self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Lower Right?
  #-----------------------------------------------------------------------------
  def moving_lower_right?
    return (self.real_y < self.y * 128) && (self.real_x < self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Lower Left?
  #-----------------------------------------------------------------------------
  def moving_upper_left?
    return (self.real_y > self.y * 128) && (self.real_x > self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Moving Lower Right?
  #-----------------------------------------------------------------------------
  def moving_upper_right?
    return (self.real_y > self.y * 128) && (self.real_x < self.x * 128)
  end
  #-----------------------------------------------------------------------------
  # * Move Direction?
  #-----------------------------------------------------------------------------
  def move_direction
    return 2 if moving_down?
    return 4 if moving_left?
    return 6 if moving_right?
    return 8 if moving_up?
    return 1 if moving_lower_left?
    return 3 if moving_lower_right?
    return 7 if moving_upper_left?
    return 9 if moving_upper_right?
    return 0
  end
  #-----------------------------------------------------------------------------
  # * Moving Diagonal?
  #-----------------------------------------------------------------------------
  def moving_diagonal?
    return true if moving_upper_left? or moving_upper_right?
    return true if moving_lower_left? or moving_lower_right?
    return false
  end
end

#===============================================================================
# ** Game_Player
#-------------------------------------------------------------------------------
#   This class has been enhanced to check if player is attempting to move a 
# diagonal specific or general diagonal direction.
#===============================================================================

class Game_Player < Game_Character
  #-----------------------------------------------------------------------------
  # * Attempt Up Left?
  #-----------------------------------------------------------------------------
  def attempt_upper_left?
    return (Input.press?(Input::UP) && Input.press?(Input::LEFT))
  end
  #-----------------------------------------------------------------------------
  # * Attempt Up Right?
  #-----------------------------------------------------------------------------
  def attempt_upper_right?
    return (Input.press?(Input::UP) && Input.press?(Input::RIGHT))
  end
  #-----------------------------------------------------------------------------
  # * Attempt Down Left?
  #-----------------------------------------------------------------------------
  def attempt_lower_left?
    return (Input.press?(Input::DOWN) && Input.press?(Input::LEFT))
  end
  #-----------------------------------------------------------------------------
  # * Attempt Down Right?
  #-----------------------------------------------------------------------------
  def attempt_lower_right?
    return (Input.press?(Input::DOWN) && Input.press?(Input::RIGHT))
  end
  #-----------------------------------------------------------------------------
  # * Attempt Diagonal?
  #-----------------------------------------------------------------------------
  def attempt_diagonal?
    return true if attempt_upper_left?
    return true if attempt_upper_right?
    return true if attempt_lower_left?
    return true if attempt_lower_right?
    return false
  end
end
 
Sorry about my absence guys. Life just has been busy. Anyways, I will be working on this for the next few days and getting it updated by friday or saturday.

I just noticed something...in the Screenshot module, it references a need for Screenshot.dll.  Since it doesn't seem to be named as a Windows registered library, I assume it's something I need to download, but there isn't a demo and I can't seem to find the file.

EDIT: Something I just thought of that would be interesting is a sort of checksum for save files and data files to assure they aren't hacked.  The files themselves would store a set of indeces (or a certain external checksum file would hold indeces for all the data files) that aren't in themselves checksums.  They would index a table of possible checksums, the values distributed randomly, like a random number table.  Each one would take certain specific bits from the file to compile a checksum instead of the entire file.  There are probably better ways to do it, as I've never put together any sort of data integrity algorithms before, but this is just my idea for the time being...stop me if somebody's already written something for this purpose...

EDIT2: And I figured out why my player sprite was not displaying correctly.  It had nothing to do with pixel movement.  It was because some modifications I've been making to Game_Battler have resulted in the player erroneously being .dead? and the recent Game_Character modifications in MACL used that to remove the player sprite.  This was all going wrong not because the player was actually dead, but because I used a '=' accidentally instead of a '==' 0_0
Yeah, I forgot to include the screenshot.dll. I'll add that in the next update. Nice idea for the checksum. I'll do some research and see if I can't throw something in the update. What exactly was the problem with the MACL and your script?

@Charlie Lee: Not a bad idea. I might modify that to make it more dynamic and customizable.
Code:
class Window_Command
  alias_method :macl_wnshortcuts_wnc_init, :initialize
  alias_method :macl_wnshortcuts_wnc_update, :update
  def initialize(width, commands)
    macl_wnshortcuts_wnc_init(width, commands)
    @shortcuts = {}
  end
  def add_shortcut(key, index)
    @shortcuts[key] = index
  end
  def update
    @shortcuts.each do |key, index|
      if Input.trigger?(key)
        @index = index
        break
      end
    end
    macl_wnshortcuts_wnc_update
  end
end

How's that work?

@Kain Nobel: I'll take a look at those methods and add them in (I may modify them slightly to make them more efficient and customizable, like I do everything lol).
 
The "problem" I had with MACL was that it now contains a script that attaches a battler to Game_Player, and it removes the sprite if battler.dead? The real problem was that when I rewrote the dead? method (to use my four hp values instead of the one), one of the expressions used a "var = 0" instead of a "var == 0".  Entirely my fault.
 
It's all good.  Interestingly enough, I attached a @battler to Game_Character in my own project too.  It's defined by Game_Player.setup_battler and Game_Event.setup_battler, while that method is not in Game_Character.  I'm sure you've done more on that than I have yet...
 
I didn't bother with a method to setup the battler. Care to share yours?

I did however change something that was slowing down everything drastically. I left a debug tool in there, that runs the refresh method every frame, vs. when the battler changes. It now only updates when the battler dies or changes. (Making a special battler= method, vs. attr_writer: battler).
 
Remember that weird error about the 'each' thing I kept getting? After simply deleting the last script, I found that was the culprit of the error. You should check that script over, its probably an easy fix I'm just too lazy to fix it. (It was the 'System.Window Sprites' or something of that nature)

Also, I tried replacing my personal Window move methods simply with the Moveable module, but it seems everytime a window reaches its destination, I get an error. Whats wrong with it?

Code:
Script 'Modules.Moveable' line 192: NoMethodError occured
undefined method 'sign' for nil:NilClass

Not sure what's going on there, but you should look into that too before you release the next version if you haven't fixed them already.

SephirothSpawn":uwtnch9d said:
I did however change something that was slowing down everything drastically. I left a debug tool in there, that runs the refresh method every frame, vs. when the battler changes. It now only updates when the battler dies or changes. (Making a special battler= method, vs. attr_writer: battler).

Which script is causing the lag? I wanna delete it from my project until the next update.
 

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