Chaos Project

RPG Maker => RPG Maker Scripts => Script Troubleshooting => Topic started by: Xuroth on March 09, 2011, 04:13:34 pm

Title: [XP] Edit RTP methods issue
Post by: Xuroth on March 09, 2011, 04:13:34 pm
I've been trying to work on my scripting skills and I've had a couple of issues with getting methods in new classes to be called. I dont understand what the difference between alias and the reserved word super is supposed to be. I've tried reading the RTP scripts to see, but when I try to emulate them and modify something, my methods never get called.

I played around with changing the color of the title HP in Window_BattleStatus so that when in battle, 'HP' is shown green. this was just a simple way to try to alias methods, though Im not sure if this is done correctly.

This DOES change the Name of 'HP', but I am curious if this would be no-no for compatibility? Essentially, I re-wrote def refresh so that it calls my method draw_colored_hp instead of draw_actor_hp.

Basically, in terms of compatibility and/or scripting ettiquette, is this acceptable?

Man, I suck at this!: ShowHide



HP_COLOR = Color.new(128, 255, 128, 255) # Green
# this constant is just here to make it configurable, even though
# it could be just placed below...
class Window_BattleStatus
# I doubt if I even need the alias, as the new refresh method
# directly calls the color edit method.

  alias draw_colored_hp draw_actor_hp
  def draw_colored_hp(actor, x, y, width = 144)
draw_actor_hp(actor, x, y, width = 144)
self.contents.font.color = HP_COLOR
self.contents.draw_text(x, y, 32, 32, $data_system.words.hp)
# This is to change the color of 'HP' or whatever the game
# calls it. As this is a test, I am just
# trying to see if this is acceptable practice.
  end


  def refresh
# This method directly calls the color edit method, so I don't
# think I need the alias above. However, if I do not change
# the refresh method to call my method, then mine never gets
# called, alias or not... I don't understand the right way to
# use alias maybe?

self.contents.clear
@item_max = $game_party.actors.size

for i in 0...$game_party.actors.size
  actor = $game_party.actors
  actor_x = i * 160 + 4
  draw_actor_name(actor, actor_x, 0)
  draw_colored_hp(actor, actor_x, 32, 120) #changed from draw_actor_hp
  draw_actor_sp(actor, actor_x, 64, 120)

  if @level_up_flags
     self.contents.font.color = normal_color
      self.contents.draw_text(actor_x, 96, 120, 32, "LEVEL UP!")
  else
    draw_actor_state(actor, actor_x, 96)
  end

end

  end

end

Title: Re: [XP] Edit RTP methods issue
Post by: G_G on March 09, 2011, 04:33:28 pm
Using the super method calls the method from the parent class.
class Parent
  def refresh
    #this is the parent method
    do stuff
  end
end

class Child < Parent
  def refresh
    super # calls the refresh method from the parent class so do stuff would get called
    do other stuff
  end
end


Using alias is to avoid overwriting existing methods within a class. Aliasing stores the old method. That way if you have a method overwriting another one then you can simply call the old method.
class Stuff
  def initialize
    set_important_variables_here
  end
end

class Stuff
  alias call_old_init_method initialize
  def initialize
    set_more_important_variables
    call_old_init_method # This calls the old initialize method
  end
end
Title: Re: [XP] Edit RTP methods issue
Post by: Xuroth on March 09, 2011, 06:18:06 pm
I tried to alias these methods to improve compatibility, as I am adding code to change the font color. However, when I test with this modified script, I get a NameError saying 'actor' is an undefined local variable or method. I hate to be asking the same n00bish question over and over again, but what would be the correct way to do this?

Still not getting this...: ShowHide



HP_COLOR = Color.new(128, 255, 128, 255) # Green
class Window_Base
  alias draw_colored_hp draw_actor_hp #not sure if I need to add the arguments
                                      #here or not.
                                     
  def draw_actor_hp(actor, x, y, width = 144)
   
    self.contents.font.color = HP_COLOR
    self.contents.draw_text(x, y, 32, 32, $data_system.words.hp)
    draw_colored_hp(actor, x, y, width = 144) #do I need this for calling the
                                              #rest of the old method?
  end

end
class Window_BattleStatus < Window_Base

  alias refresh_with_color refresh
  def refresh
    draw_colored_hp(actor, x, y, width = 144) #this line is the cause of the
                                              #error. If I remove the arguments
                                              #though, I get an error that
                                              #says "wrong number of arguments
                                              #(0 for 3)!"
    refresh_with_color
  end
end

Title: Re: [XP] Edit RTP methods issue
Post by: G_G on March 09, 2011, 06:23:33 pm
This is because there is no existing variable "actor" within that method. The way you are attempting to do it is most likely not going to work. So the best thing to do in some situations is to just rewrite/overwrite the method. In some cases its not bad. Also you wouldn't call draw_colored_hp, you would sitll call draw_actor_hp. draw_colored_hp isn't going to get your code called, its only going to call the old method. So aliasing the method in the battle status window is kinda pointless.

All you need is the rewrite for Window_Base's draw_actor_hp. Now when draw_actor_hp is called it will call your code. Also place the draw_colored_hp above all other code in the method. And replace the width = 144 with just width.
Title: Re: [XP] Edit RTP methods issue
Post by: Xuroth on March 09, 2011, 06:55:50 pm
Thanks g_g! Finally, after a week of trying to understand alias, I finally get it. The reason I was messing up was because of the placement of draw_colored_hp in the aliased method. That made me overthink everything else and get a huge mess of code which in the end only showed the normal hp color. Now I can take this and apply it to the script I've been trying to write!

Correct code:
Thanks game_guy!: ShowHide

HP_COLOR = Color.new(128, 255, 128, 255) # Green
class Window_Base
  alias draw_colored_hp draw_actor_hp                                 
  def draw_actor_hp(actor, x, y, width = 144)
     draw_colored_hp(actor, x, y, width)
    self.contents.font.color = HP_COLOR
    self.contents.draw_text(x, y, 32, 32, $data_system.words.hp)
  end

end



Also, now it makes sense why aliasing methods is good. Not only does it improve compatibility, it also shortens how much code you have to write...
Title: Re: [XP] Edit RTP methods issue
Post by: ForeverZer0 on March 10, 2011, 12:17:34 am
You will find that once you get the hang of aliasing, so many new things are now possible.
I remember being all excited about it, too.  :D
Title: Re: [XP] Edit RTP methods issue
Post by: Xuroth on March 10, 2011, 08:39:23 am
Well, I seem to be having the same sort of issue. This time I am aliasing 4 methods of Scene_Item. For some reason, it gives an error "undefined method 'refresh' for Nil:NilClass". There most certainly IS a refresh method, so I don't understand the problem!

Here is my script. Like other detail scripts, it waits until you are in Scene_Item and press Shift on a highlighted item. Then it is supposed to show the Window_Details. instead, it goes into error...

Spoiler: ShowHide

class Window_Details < Window_Base
  #initialize method does the window setup.
  def initialize
    #call from Window_Base to create a window
    super(0, 0, 640, 480)
    #set up the text area inside the window
    self.contents = Bitmap.new(width - 32, height - 32)
    #now setup font size, type, and color
    self.contents.font.name = 'Tahoma'
    self.contents.font.size = 20
    self.contents.font.color = normal_color #white
    #z-layer makes the detail window appear overtop all the item windows
    self.z += 10
    @details = [] #declares a variable to hold the details information later
    #call the refresh_reset method
    refresh_reset
  end
 
  #Refresh_Reset clears the window so text doesnt overlap
  #   if you browse 2 or more details
 
  def refresh_reset
    #clears the window
    self.contents.clear
  end
 
  #   Refresh updates the @details variable with new info
  def refresh
    #set a local variable to the global $selected_item value
    item = $selected_item.id
    #tests to see if item is an Item
    if $selected_item.is_a?(RPG::Item)
      #get the item's name
      item_name = $data_items[item].name
      #get the item's icon
      item_icon = $data_items[item].icon_name
      #and set a variable to hold the file name. named the same as other
      #detail scripts in case you want to use this one (for some reason)
      #and dont want to re-write all your lore (though your formatting
      #will likely need to be edited.)
      @detail_file = File.open("Data/Item_Detail.rxdata")
    #tests to see if the item is a Weapon
    elsif $selected_item.is_a?(RPG::Weapon)
      #get the name, icon, and file name as before
      item_name = $data_weapons[item].name
      item_icon = $data_weapons[item].icon_name
      @detail_file = File.open("Data/Weapon_Detail.rxdata")
    #tests to see if the item is an Armor
    elsif $selected_item.is_a?(RPG::Armor)
      #and again, fetch name and icon
      item_name = $data_armors[item].name
      item_icon = $data_armors[item].icon_name
      @detail_file = File.open("Data/Armor_Detail.rxdata")
    end
   
    #sets a variable to hold the icon
    bitmap = RPG::Cache.icon(item_icon) #should not need .png extension as
                                     #another scripter mentioned that RMXP
                                     #automatically loads the correct file
                                     #format. this will only conflict (in
                                     #theory) if there are multiple icons
                                     #with the same name, but different formats.
    #now draw the icon!
    self.contents.blt(5, 8, bitmap, Rect.new(0, 0, 24, 24), 255)
    self.contents.draw_text(32, 8, 256, 24, item_name)
   
    #now call the method that actually gets and displays the detailed info!
    fetch_details(item)
    show_details(5, 22)
  end
 
  #this method here grabs the details from the files. Similar to Jackatrade's
  #original script and DerVVulfman's Grouping and Details script, this uses
  # three different files for details. Each description can hold 10 lines of
  #text, though in the next version, I will try to update this so it can tell
  #automagically how many lines to use, and also make the window scrollable !!!
 
  #Note: due to limitations (my current scripting ability) I can not add sweet
  #features to make this desirable. Keep in mind that 1.0 of this is only to
  #be a simplistic and very basic system. I hope to add more later!
 
  def fetch_details(item)
    #Im not really familiar with arrays. so Im just setting one up that can
    #store the detail lines thouth I doubt its used efficiently. I'm sure that
    #other scripters can see how to do this better.
   
    #Here I cheated and looked at Jackatrade's original script to see how he
    #set this up.
   
    #array that holds details:
    description =
    [
    item * 10,
    item * 10 + 1,
    item * 10 + 2,
    item * 10 + 3,
    item * 10 + 4,
    item * 10 + 5,
    item * 10 + 6,
    item * 10 + 7,
    item * 10 + 8,
    item * 10 + 9,
    ]
    #stores all lines into variable
    @details = @detail_file.readlines
    #now set up !?Another?! variable used for processing the data.
    @desc = []
    #now set it to hold only 10 lines at a time!
    for i in 0..9
      @desc[i] = @details[description[i]]
    end
    #finished! now run the display details method!
    return
  end
 
  def show_details(x, y)
    #draw the Description title (next version this will be easier to change!)
    self.contents.draw_text(x, y - 20, 640, 32, "Description:")
    #draw all 10 lines normally
    for i in 0..9
      self.contents.draw_text(x, y, 640, 32, @desc[i])
      y += 20
    end
  #method end
  end
#class end
end

#==============================================================================#
class Scene_Item


alias detail_main main
  def main
    detail_main
    @detail_window = Window_Details.new
    @detail_window.visible = false
    @detail_window.active = false
    @detail_window.dispose
  end

  alias detail_update update
  def update
    detail_update
    $selected_item = @item_window.item
    if @item_window.active
      update_item
      return
    end
    if @detail_window.active
    update_details
      return
    end
  end

  def update_details
   if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      unless $game_party.item_can_use?(@item.id)
        @item_window.refresh
      end
      @item_window.active = true
      @detail_window.visible = false
      @detail_window.active = false
      @detail_window.refresh_reset
      return
    end
  end

 
  alias new_update_item update_item
  def update_item
    new_update_item
    if Input.trigger?(Input::A)
      # Below if-then statement checks for blank item, and cancels
      # input effect is true.
      if $selected_item == nil
        return
      end     
      $game_system.se_play($data_system.decision_se)
      @detail_window.refresh #for some reason, it crashes here
      @item_window.active = false     
      @detail_window.visible = true
      @detail_window.active = true
    end
  end
end


Any ideas on what I am doing wrong?
Title: Re: [XP] Edit RTP methods issue
Post by: G_G on March 10, 2011, 08:43:30 am
These lines here
@detail_window = Window_Details.new
    @detail_window.visible = false
    @detail_window.active = false

Will need to go above detail_main.

In some cases you'll need to call the alias first, other cases last, and some cases you'll need it in between code.
@detail_window = Window_Details.new
    @detail_window.visible = false
    @detail_window.active = false
    detail_main
    @detail_window.dispose

The old method "detail_main" Contains a loop statement. So its going to keep updating until the scene is changed. When it breaks out of the loop, that is when your detail window would have been made.
Title: Re: [XP] Edit RTP methods issue
Post by: Xuroth on March 10, 2011, 08:54:57 am
Thanks again g_g! Now it works enough that I can fine tune it, and slowly build on it. 

But how do you know when to place an alias after or between code?
Title: Re: [XP] Edit RTP methods issue
Post by: G_G on March 10, 2011, 08:57:10 am
If you're aliasing scenes and you're adding new windows, place it in the middle and the window call above it and the dispose below.
If you're doing edits to battle algorithms or special skills you'll probably want to put the alias at the bottom. Now if you're redrawing something like in your battle window then put it above. Its kinda a trial and error too ya know?
Title: Re: [XP] Edit RTP methods issue
Post by: Ryex on March 10, 2011, 08:59:22 am
think of an alias as exactly that and object exists independently of it's name just as a person dose. so using alias you can give an object a new name and then give that old name to a new object. which can in turn call the old object via the new name.

use alias when you need to add code to the begin or end of an existing function instead of overriding it.
Title: Re: [XP] Edit RTP methods issue
Post by: Xuroth on March 10, 2011, 12:25:17 pm
now I get an error saying it can't convert nil to String for this line:
self.contents.draw_text(x, y, 640, 32, @desc[i])

I've spent the last two hours trying to get this to work by tweaking different parts of the script, but to no avail. its driving me nuts...
Title: Re: [XP] Edit RTP methods issue
Post by: ForeverZer0 on March 10, 2011, 12:30:01 pm
@desc equals nil. You are either using an index that is out of range, or whatever sets the values is buggy. Start backtracing that variable, and place "p @desc" at certain intervals to see what that variable is equal to at different points, and see where it goes wrong. I would actually start with having it print "i" in the enumeration to see whats going on there.
Title: Re: [XP] Edit RTP methods issue
Post by: Xuroth on March 10, 2011, 01:39:51 pm
Thanks Zer0. so what is happening is the script is trying to find the data in the text file. if the file has blank lines being read, the system interprets those as nil. also, if the text file doesnt contain text for a topic, it will also yeild nil.

so now I am going to figure out a way to read an index of @desc and see if it is nil. if it is, I will turn it into an empty string like ' '

in the for loop that held the error I just had to:

#code for show_details(x, y)
for i in 0..9
  if @desc[i] == nil #check and see if iteration is nil
    @desc[i] = ' '    #if it is, change it to string
  else                   #but if not, carry on as normal!
    self.contents.draw_text(x, y, 640, 32, @desc[i])
  end
end
#rest of show_details(x, y)
Title: Re: [XP] Edit RTP methods issue
Post by: ForeverZer0 on March 10, 2011, 04:49:01 pm

@desc.each_index {|i| self.contents.draw_text(x, y, 640, 32, @desc[i] == nil ? ' ' : @desc[i])}


There's a slightly shorter way of doing it, though it will not actually change the value in @desc. It will simply use an empty string if the value is nil.