Hime-Works / Requests

Bug reports and requests that may require longer discussions and is not suitable to leave on the blog
http://himeworks.com/
GNU General Public License v2.0
7 stars 9 forks source link

WTF?!? Game_Battler.escape & clear_states #254

Closed Roguedeus closed 9 years ago

Roguedeus commented 9 years ago

I just noticed that escaping battle auto-clears ALL states via calling clear_states

  #--------------------------------------------------------------------------
  # * Escape
  #--------------------------------------------------------------------------
  def escape
    hide if $game_party.in_battle
    clear_actions
    clear_states
    Sound.play_escape
  end

This has to be a bug... Otherwise, WHY allow a state design to toggle this? rgss_escape_issue_1 Here, poison is OBVIOUSLY meant to persist after battle... But in order to remove it cheaply all you need to do is successfully escape from your next battle.

This applies to ALL states. including death. If a party member is dead, simply escape from your next battle, and SHAZAM!! They are alive again... BOGGLE

Roguedeus commented 9 years ago

I verified this is NOT happening in a clean project... ugh.

Roguedeus commented 9 years ago

Clearly, by default, using the escape command doesn't call the battlers escape method... So this bug shouldn't occur. Normally.

class Scene_Battle < Scene_Base
  #--------------------------------------------------------------------------
  # * [Escape] Command
  #--------------------------------------------------------------------------
  def command_escape
    turn_start unless BattleManager.process_escape
  end
end
module BattleManager
  #--------------------------------------------------------------------------
  # * Escape Processing
  #--------------------------------------------------------------------------
  def self.process_escape
    $game_message.add(sprintf(Vocab::EscapeStart, $game_party.name))
    success = @preemptive ? true : (rand < @escape_ratio)
    Sound.play_escape
    if success
      process_abort
    else
      @escape_ratio += 0.1
      $game_message.add('\.' + Vocab::EscapeFailure)
      $game_party.clear_actions
    end
    wait_for_message
    return success
  end
end

Question now is WTH is my build calling it now, when my other builds haven't?

edit: FACEPALM I had forgotten I applied RECOVER ALL to both Lose and Escape, on the test battle processing.

Anyway, I did verify the issue with the item/skill escape effect.

Roguedeus commented 9 years ago

Obviously I am not the only one that noticed this issue...

#==============================================================================
# 
# ? Yanfly Engine Ace - Party System v1.08
# -- Last Updated: 2012.01.23
# -- Level: Normal
# -- Requires: n/a
# 
#==============================================================================

#==============================================================================
# ? Updates
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# 2012.01.23 - Bug fixed: Party members are now rearranged when newly added.
# 2012.01.14 - New Feature: Maximum Battle Members Variable added.
# 2012.01.07 - Bug fixed: Error with removing members.
# 2012.01.05 - Bug fixed: Escape skill/item effects no longer counts as death.     <----------------#
# 2011.12.26 - Compatibility Update: New Game+
# 2011.12.17 - Updated Spriteset_Battle to have updated sprite counts.
# 2011.12.13 - Updated to provide better visual display when more than 5 pieces
#              of equipment are equipped on an actor at a time.
# 2011.12.05 - Added functionality to display faces in the Party Select Window.
#            - Fixed bug that doesn't refresh the caterpillar when new members
#              join the party.
# 2011.12.04 - Started Script and Finished.
# 
#==============================================================================
HimeWorks commented 9 years ago

I think that's a pretty weird place to place the escape-altering logic.

Roguedeus commented 9 years ago

Definitely weird.

#RogueDeus  15_0131

#RDeus - Escape Fix

#===============================================================================
# 
#===============================================================================
class Game_BattlerBase
  #-----------------------------------------------------------------------------
  # overwrite:
  #   'hide' (@hidden = true) removes actor from battle_members array.
  #   'appear' is called in 'on_battle_end' (@hidden = false)
  #-----------------------------------------------------------------------------
  def escape
    hide if $game_party.in_battle
    # clear_actions
    # clear_states
    Sound.play_escape
  end
end
Roguedeus commented 9 years ago

Are there any tricks for calling a derived classes method from its base class?

Such as calling a Game_Battler method from Game_BattlerBase ?

edit: Nope no tricks. Works great.

Roguedeus commented 9 years ago

I don't get why its so damn easy for me to get carried away by the smallest things, and suddenly my entire day is gone...

I just wrote a Death substitute state script called 'Almost Dead'... Here are the basics.

=begin
Creates COMA state that is a slightly more complex version of DEATH.
Instead of simple DEATH, when an actors HP reaches ZERO, they fall into
COMA, during which they can die, but its unlikely.

COMA is supposed to be easier to cure than DEATH. 
  - Such as with tonic's or simple spells.

DEATH is supposed to be semi-permanent or require more work to remove. 
  - Such as a trip to a Church or a Resurrection quest. 

Instant Death is possible if enabled. But its meant to be rare and easily 
avoided.
  - Such as taking mass damage, should only be possible if attempting to
    fight enemies FAR outside the players power range. Dieing from such 
    damage will cause DEATH rather than COMA.
  - Such as dieing from a critical hit. This is incentive to keep an actors
    CEV (an often overlooked stat) as high as possible.
=end

    #============================================
    # INSTANT DEATH?
    #============================================
    #Allows for a incapacitating blow that deals enough damage to cause DEATH
    #instead of COMA.
    MASSDAMAGE_DEATH = true #RDeus::AlmostDeath::MASSDAMAGE_DEATH
    #--------------------------------------------
    #Percentage of MHP that must be dealt on the incapacitating blow to qualify
    #as massive damage.
    MASSDAMAGE = 0.25 #Default 25% #RDeus::AlmostDeath::MASSDAMAGE
    #--------------------------------------------
    #Allows for a CRITICAL HIT incapacitating blow to cause DEATH instead of COMA.
    CRITICAL_DEATH = true

    #============================================
    # COMA STASIS?
    #============================================
    #To keep states/buffs/debuffs active on COMA actors, set this true.
    #Intended to prevent COMA from being a means of wiping negative states.
    COMA_STASIS = true    #RDeus::AlmostDeath::COMA_STASIS
    #--------------------------------------------
    #Continues to process actors states even while COMA when true.
    #   Note: This must be TRUE for DAMAGE_IN_COMA to risk Death. 
    UPDATE_STASIS = true  #RDeus::AlmostDeath::UPDATE_STASIS
    #--------------------------------------------
    #If during UPDATE_STASIS a state deals damage, there is a chance
    #the actor may die, if this is set true. Otherwise to suffer a DEATH 
    #state, it must be applied directly, such as with a instant death option.
    DAMAGE_IN_COMA = true #RDeus::AlmostDeath::DAMAGE_IN_COMA
    #--------------------------------------------
    #This is the base chance of death from DAMAGE_IN_COMA
    #Normally chance is the ratio of the damage to the actors MHP/MMP
    MINIMUM_CHANCE = 0.10  #RDeus::AlmostDeath::MINIMUM_CHANCE
HimeWorks commented 9 years ago

Are there any tricks for calling a derived classes method from its base class? Such as calling a Game_Battler method from Game_BattlerBase ? edit: Nope no tricks. Works great.

That's typically how inheritance works: objects will call their own methods.

Roguedeus commented 9 years ago

I meant reverse inheritance. I know the question doesn't read that way at first.

I am calling a Game_Battle method from Game_BattlerBase, in order to easily access @result. I seem to remember, back when I coded in C# that it wasn't easy to do. Ruby is super easy.

HimeWorks commented 9 years ago

Do you mean having a Game_BattlerBase instance trying to access methods from a child class? That should immediately raise design issues

  1. Why is the logic not defined in Game_BattlerBase if both the parent and the child need it?
  2. Is it correct to instantiate a Game_BattlerBase object when you need methods from a child class?

The usual way to do this would be to define a method in the parent class, possibly doing nothing, and then overwrite it in the child class.

This way, static code analysis would not complain about your class trying to access methods or variables that do not exist.

Roguedeus commented 9 years ago

Yeah, I just needed to access @result for that battler, and that is done in Game_Battler... So instead of creating a separate instance of Game_ActionResult I just made the methods in Game_Battler and called them in Game_BattlerBase.

I considered overriding refresh in Game_Battler but the more I thought about all the aliases of the Game_BattlerBase method and the issues we established are caused by that, needing to call super in order for the aliases to function correctly, I decided instead to just call the child's method in the parent class. There doesn't appear to be any issues.

HimeWorks commented 9 years ago

Any method defined in Game_BattlerBase will be inherited by any child classes so they would be evaluated in the context of the object (which does hold an @result object)

Now, if you actually had a Game_BattlerBase instance and it tried to call that method, it will crash. This is one situation staticly typed classes will notice and tell you something isn't right.

Roguedeus commented 9 years ago

Thanks for clearing that up. ;)