#=============================================================================
# ** TDS Battle Retry
#    Ver: 1.0
#------------------------------------------------------------------------------
#  * Description:
#  This script allows you to restart battles exactly as they were when you
#  started.
#------------------------------------------------------------------------------
#  * Features: 
#  Restart battle from a command.
#  Restart battle after defeat.
#------------------------------------------------------------------------------
#  * Instructions:
#
#  To disable or enable the battle retry feature, use these in a script call
#  from an event:
#
#    disable_battle_retry 
#    enable_battle_retry
#
#
#  To disable or enable the battle retry command in battle, use these in a
#  script call from an event:
#
#    disable_battle_retry_command
#    enabled_battle_retry_command
#------------------------------------------------------------------------------
#  * Notes:
#  None.
#------------------------------------------------------------------------------
# WARNING:
#
# Do not release, distribute or change my work without my expressed written 
# consent, doing so violates the terms of use of this work.
#
# I also reserve the right to deny permission to any individual or group from
# using any of my work.
#
# If you really want to share my work please just post a link to the original
# site.
#
# * Not Knowing English or understanding these terms will not excuse you in any
#   way from the consequenses.
#==============================================================================
# * Import to Global Hash *
#==============================================================================
($imported ||= {})[:TDS_Battle_Retry] = true

#==============================================================================
# ** TDS
#------------------------------------------------------------------------------
#  A module containing TDS data structures, mostly script settings.
#==============================================================================
module TDS
  #============================================================================
  # ** Battle_Retry_Settings
  #----------------------------------------------------------------------------
  #  This Module contains battle retry settings.
  #============================================================================  
  module Battle_Retry_Settings
    #--------------------------------------------------------------------------
    # * Constants (Features)
    #--------------------------------------------------------------------------  
    # Disable Retry Battle Command in battle if true (It will not be added)
    Disable_Command = false
    # Retry Command Name
    Retry_Command_Name = "Retry Battle"
  end
end


#==============================================================================
# ** BattleManager
#------------------------------------------------------------------------------
#  This module manages battle progress.
#==============================================================================
class << BattleManager
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------  
  alias tds_battle_retry_battle_manager_battle_start             battle_start
  alias tds_battle_retry_battle_manager_battle_end               battle_end
  #--------------------------------------------------------------------------
  # * Battle Start
  #--------------------------------------------------------------------------
  def battle_start(*args, &block)
    # Run Original Method
    tds_battle_retry_battle_manager_battle_start(*args, &block)
    # Create Retry Object
    create_retry_object if @retry_object.nil?
  end
  #--------------------------------------------------------------------------
  # * Defeat Processing
  #--------------------------------------------------------------------------
  def process_defeat
    $game_message.add(sprintf(Vocab::Defeat, $game_party.name))
    wait_for_message
    if @can_lose
      revive_battle_members
      replay_bgm_and_bgs
      SceneManager.return
      battle_end(2)      
    else
      # If Battle Retry is disabled
      if $game_system.battle_retry_disabled
        SceneManager.goto(Scene_Gameover)        
        battle_end(2)        
      else
        # Start Retry Prompt
        SceneManager.scene.start_retry_prompt(:gameover)
      end
    end
    return true      
  end    
  #--------------------------------------------------------------------------
  # * End Battle
  #     result : Result (0: Win 1: Escape 2: Lose)
  #--------------------------------------------------------------------------
  def battle_end(*args, &block)
    # Run Original Method
    tds_battle_retry_battle_manager_battle_end(*args, &block)
    # Clear Retry Object
    clear_retry_object
  end
  #--------------------------------------------------------------------------
  # * Retry Initialize Member Variables
  #--------------------------------------------------------------------------
  def retry_init
    @phase = :init              # Battle Progress Phase
    @actor_index = -1           # Actor for Which Command Is Being Entered
    @action_forced = nil        # Force Action
    @action_battlers = []       # Action Order List    
  end
  #--------------------------------------------------------------------------
  # * Clear Retry Object
  #--------------------------------------------------------------------------
  def clear_retry_object ; @retry_object end
  #--------------------------------------------------------------------------
  # * Restore to Retry
  #--------------------------------------------------------------------------
  def retore_to_retry
    # Return if Retry Object is nil
    return if @retry_object.nil?
    # Load Retry Object Contents
    contents = Marshal.load(@retry_object)     
    # Load Default Retry Objects & Custom Retry Object
    load_default_retry_objects(contents) ; load_custom_retry_objects(contents)
    # Retry Initialization
    retry_init
  end
  #--------------------------------------------------------------------------
  # * Create Retry Object
  #--------------------------------------------------------------------------
  def create_retry_object
    # Create Retry Contents Hash
    contents = {}
    # Add Default & Custom Retry Objects
    add_default_retry_objects(contents) ; add_custom_retry_objects(contents)
    # Create Retry Object
    @retry_object = Marshal.dump(contents)
  end
  #--------------------------------------------------------------------------
  # * Add Default Retry Objects
  #     contents : contents hash
  #--------------------------------------------------------------------------
  def add_default_retry_objects(contents)
    contents[:temp]           = $game_temp
    contents[:system]         = $game_system
    contents[:timer]          = $game_timer
    contents[:message]        = $game_message
    contents[:switches]       = $game_switches
    contents[:variables]      = $game_variables
    contents[:self_switches]  = $game_self_switches
    contents[:actors]         = $game_actors
    contents[:party]          = $game_party
    contents[:troop]          = $game_troop
    contents[:map]            = $game_map
    contents[:player]         = $game_player    
    contents[:frame_count]    = Graphics.frame_count
  end
  #--------------------------------------------------------------------------
  # * Add Custom Retry Objects
  #     contents : contents hash
  #--------------------------------------------------------------------------
  def add_custom_retry_objects(contents)
  end
  #--------------------------------------------------------------------------
  # * Load Custom Retry Objects
  #     contents : contents hash
  #--------------------------------------------------------------------------
  def load_default_retry_objects(contents)
    $game_temp            = contents[:temp]
    $game_system          = contents[:system]
    $game_timer           = contents[:timer]
    $game_message         = contents[:message]
    $game_switches        = contents[:switches]
    $game_variables       = contents[:variables]
    $game_self_switches   = contents[:self_switches]
    $game_actors          = contents[:actors]
    $game_party           = contents[:party]
    $game_troop           = contents[:troop]
    $game_map             = contents[:map]
    $game_player          = contents[:player]    
    Graphics.frame_count  = contents[:frame_count]
  end  
  #--------------------------------------------------------------------------
  # * Load Custom Retry Objects
  #     contents : contents hash
  #--------------------------------------------------------------------------
  def load_custom_retry_objects(contents)
  end  
end


#==============================================================================
# ** Game_System
#------------------------------------------------------------------------------
#  This class handles system data. It saves the disable state of saving and 
# menus. Instances of this class are referenced by $game_system.
#==============================================================================

class Game_System
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :battle_retry_disabled           # Retry Disabled flag    
  attr_accessor :battle_retry_command_disabled   # Retry Command Disabled flag
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------  
  alias tds_battle_retry_battle_game_system_initialize initialize
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize(*args, &block)
    # Run Original Method
    tds_battle_retry_battle_game_system_initialize(*args, &block)
    # Set Battle Retry Disabled Flags
    @battle_retry_disabled = false
    @battle_retry_command_disabled = TDS::Battle_Retry_Settings::Disable_Command
  end
end


#==============================================================================
# ** Game_Interpreter
#------------------------------------------------------------------------------
#  An interpreter for executing event commands. This class is used within the
# Game_Map, Game_Troop, and Game_Event classes.
#==============================================================================

class Game_Interpreter
  #--------------------------------------------------------------------------
  # * Disable or Enable Battle Retry
  #--------------------------------------------------------------------------
  def disable_battle_retry ; $game_system.battle_retry_disabled = true end
  def enable_battle_retry  ; $game_system.battle_retry_disabled = false end    
  #--------------------------------------------------------------------------
  # * Disable or Enable Battle Retry Command
  #--------------------------------------------------------------------------
  def disable_battle_retry_command ; $game_system.battle_retry_command_disabled = true end
  def enable_battle_retry_command  ; $game_system.battle_retry_command_disabled = false end
end


#==============================================================================
# ** Window_PartyCommand
#------------------------------------------------------------------------------
#  This window is used to select whether to fight or escape on the battle
# screen.
#==============================================================================

class Window_PartyCommand < Window_Command
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------  
  alias tds_battle_retry_battle_window_partycommand_make_command_list make_command_list
  #--------------------------------------------------------------------------
  # * Create Command List
  #--------------------------------------------------------------------------
  def make_command_list(*args, &block)
    # Run Original Method
    tds_battle_retry_battle_window_partycommand_make_command_list(*args, &block)
    # If Battle Retry Command is not disabled
    if !$game_system.battle_retry_command_disabled    
      # Add Battle Retry Command
      add_command(TDS::Battle_Retry_Settings::Retry_Command_Name, :battle_retry)
    end    
  end
end


#==============================================================================
# ** Window_Battle_Retry_Prompt
#------------------------------------------------------------------------------
#  This window handles battle retry prompt.
#==============================================================================

class Window_Battle_Retry_Prompt < Window_Command
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize ; super(466, 170) end
  #--------------------------------------------------------------------------
  # * Window Width and Height
  #--------------------------------------------------------------------------
  def window_width  ; 190 end
  #--------------------------------------------------------------------------
  # * Get Number of Lines to Show
  #--------------------------------------------------------------------------
  def visible_line_number ; 2 end   
  #--------------------------------------------------------------------------
  # * Item Rect
  #--------------------------------------------------------------------------
  def item_rect(index) ; rect = super ; rect.y += line_height ; rect end
  #--------------------------------------------------------------------------
  # * Max Columns
  #--------------------------------------------------------------------------
  def col_max ; 2 end
  #--------------------------------------------------------------------------
  # * Command Text Alignment
  #--------------------------------------------------------------------------
  def alignment ; 1 end
  #--------------------------------------------------------------------------
  # * Make Commands List
  #--------------------------------------------------------------------------
  def make_command_list ; add_command("Yes", :ok) ; add_command("No", :cancel) end
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    super
    contents.font.color = knockout_color
    draw_text(0, 0, contents_width, line_height, "Retry battle?", 1)
  end
end


#==============================================================================
# ** Scene_Battle
#------------------------------------------------------------------------------
#  This class performs battle screen processing.
#==============================================================================

class Scene_Battle < Scene_Base
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------  
  alias tds_battle_retry_scene_battle_create_party_command_window create_party_command_window
  #--------------------------------------------------------------------------
  # * Create Party Commands Window
  #--------------------------------------------------------------------------
  def create_party_command_window(*args, &block)
    # Run Original Method
    tds_battle_retry_scene_battle_create_party_command_window(*args, &block)
    # Set Party Command Window Handlers
    @party_command_window.set_handler(:battle_retry,  method(:start_retry_prompt))
  end  
  #--------------------------------------------------------------------------
  # * [Retry] Start Prompt
  #--------------------------------------------------------------------------
  def start_retry_prompt(type = :battle)
    # Retry Type
    @retry_type = type
    # Get Retry BGM
    @before_retry_bgm = RPG::BGM.last.dup
    # Fadeout BGM, BGS, and ME
    RPG::BGM.fade(400) ; RPG::BGS.fade(400) ; RPG::ME.fade(400)    
    # Creat Scene Cover Sprite
    @scene_cover = Sprite.new
    @scene_cover.bitmap = Graphics.snap_to_bitmap
    @scene_cover.bitmap.blur
    @scene_cover.opacity = 0
    @scene_cover.tone.set(-30, -30, -30, 128)
    @scene_cover.z = 9999
    # Update Graphics & Fadein Scene Cover    
    20.times { Graphics.update ; @scene_cover.opacity += 13}
    # Stop BGM, BGS, and ME
    RPG::BGM.stop ; RPG::BGS.stop ; RPG::ME.stop
    # Create Retry Prompt Window 
    @retry_prompt_window = Window_Battle_Retry_Prompt.new
    @retry_prompt_window.set_handler(:ok,  method(:on_retry_prompt_ok))
    @retry_prompt_window.set_handler(:cancel,  method(:on_retry_prompt_cancel))    
    @retry_prompt_window.x = (Graphics.width - @retry_prompt_window.width) / 2
    @retry_prompt_window.y = (Graphics.height - @retry_prompt_window.height) / 2    
    @retry_prompt_window.z = 10000
    @retry_prompt_window.openness = 0
    @retry_prompt_window.open
    @retry_prompt_window.activate
    # Update Loop
    loop { 
      # Update Graphics, Input, and Retry Prompt Window
      Graphics.update ; Input.update ; @retry_prompt_window.update
      # Break if Retry Prompt window
      break if @retry_prompt_window.nil? or @retry_prompt_window.disposed?
    }
  end
  #--------------------------------------------------------------------------
  # * [Retry] Prompt Cancel
  #--------------------------------------------------------------------------
  def on_retry_prompt_ok
    # Close Retry Prompt Window
    @retry_prompt_window.close
    # Update Retry Prompt Window Close
    while @retry_prompt_window.openness > 0 ; Graphics.update ; @retry_prompt_window.update end    
    # Process Retry
    process_retry
  end
  #--------------------------------------------------------------------------
  # * [Retry] Prompt OK
  #--------------------------------------------------------------------------
  def on_retry_prompt_cancel
    # Close Retry Prompt Window
    @retry_prompt_window.close
    # Update Retry Prompt Window Close
    while @retry_prompt_window.openness > 0 ; Graphics.update ; @retry_prompt_window.update end
    # Retry Type Case
    case @retry_type
    when :battle
      # Update Graphics & Fadeout Scene Cover    
      10.times { Graphics.update ; @retry_prompt_window.update ; @scene_cover.opacity -= 26}
      # Dispose of Scene Cover
      @scene_cover.dispose
      # Dispose of Retry Prompt window
      @retry_prompt_window.dispose ; @retry_prompt_window = nil      
      # Rplay Before Retry BGM
      @before_retry_bgm.replay     
      # Activate Party Command Window      
      @party_command_window.activate
    when :gameover 
      # Freeze Graphics
      Graphics.freeze
      # Dispose of Scene Cover
      @scene_cover.dispose
      # Dispose of Retry Prompt window
      @retry_prompt_window.dispose ; @retry_prompt_window = nil
      # Go to Game Over Scene
      SceneManager.goto(Scene_Gameover)
      # End Battle (Defeat)
      BattleManager.battle_end(2)  
    end
  end
  #--------------------------------------------------------------------------
  # * [Retry] Processing
  #--------------------------------------------------------------------------
  def process_retry  
    # Fadeout All
    fadeout_all(420)
    # Retry Terminate
    retry_terminate
    # Restore to Retry
    BattleManager.retore_to_retry
    # Retry Start, Post Start, and Battle Start
    retry_start ; retry_post_start ; retry_battle_start
  end
  #--------------------------------------------------------------------------
  # * [Retry] Terminate
  #--------------------------------------------------------------------------
  def retry_terminate
    # Dispose of Scene Cover
    @scene_cover.dispose if !@scene_cover.nil? or !@scene_cover.disposed?
    # Dispose of Retry Prompt window
    @retry_prompt_window.dispose if !@retry_prompt_window.disposed?
    # Set Retry Prompt Window to nil
    @retry_prompt_window = nil    
    terminate
  end
  #--------------------------------------------------------------------------
  # * [Retry] Start Processing
  #--------------------------------------------------------------------------
  def retry_start
    create_spriteset
    create_all_windows  
  end
  #--------------------------------------------------------------------------
  # * [Retry] Pos-Start Processing
  #--------------------------------------------------------------------------
  def retry_post_start
    Graphics.transition(20) ; Input.update    
    # Play Battle BGM
    BattleManager.play_battle_bgm        
  end
  #--------------------------------------------------------------------------
  # * [Retry] Battle Start
  #--------------------------------------------------------------------------
  def retry_battle_start
    process_event
    start_party_command_selection
    refresh_status
  end
end