There is a bug in several of my scripts regarding aliasing and class inheritance, and this may be a very subtle issue and result in hours of debugging before you find it.
The problem occurred when a scripter was writing some scripts on top of existing custom scripts. In fact it occurred not once, but twice! While trying to alias the
remove_state method in
Game_Battler and adding a print statement to it, the print statement was never executed, but the state was still removed.
Thinking about it, there is nothing obvious about why this might be happening. It just seems like none of your changes are being applied during the game!
We start with some example snippets in real code.
remove_state method is defined as follows by default
class Game_Battler < Game_BattlerBase def remove_state(state_id) if state?(state_id) revive if state_id == death_state_id erase_state(state_id) refresh @result.removed_states.push(state_id).uniq! end end end
And in one of my own scripts, I aliased the method in
Game_Actor like this
class Game_Actor < Game_Battler alias :ft_passive_states_remove_state :remove_state def remove_state(state_id) return if features_value_set(:passive_state).include?(state_id) ft_passive_states_remove_state(state_id) end end
What I expect to happen
When I wrote the code, I believed that I am simply adding a conditional check for actor objects, and then it will call whatever previous logic was defined for
What actually happens
Actually that is exactly what happened.
So what’s the problem?
Consider what happens if I want to alias the
remove_state method again, adding a simple print statement:
class Game_Battler < Game_BattlerBase alias :th_print_test_remove_state :remove_state def remove_state(state_id) p "this works!" th_print_test_remove_state(state_id) end end
Place this script below the custom actor script. When a state is removed from an actor, the print statement doesn’t occur! In fact, it’s as if the alias didn’t even work.
alias is not
super. It doesn’t automatically call methods defined in superclasses. For some reason I had thought I could use
alias this way to avoid overwriting logic defined by other scripts in superclasses, but evidently it backfired and resulted in hard-to-find bugs.
This tutorial basically showed something that you should be careful when choosing to alias methods that are defined in methods defined in multiple classes within a hierarchy.
At the time of writing, I have not found any nice way to address the issue of adding logic to a child class while not overwriting additional logic in parent classes. If you know of any solutions I would encourage you to share it in the comments!
Spreading the word
If you liked the post and feel that others could benefit from it, consider tweeting it or sharing it on whichever social media channels that you use. You can also follow@HimeWorks to get the latest updates or suggest topics that you would like to read about.