[XP] Heretic's Disable Battle Commands

Started by Heretic86, June 04, 2014, 08:19:03 pm

Previous topic - Next topic

Heretic86

Heretic's Disable Battle Commands
Authors: Heretic
Version: 1.0
Type: Battle Add-on
Key Term: Battle Add-on



Introduction

This script allows you to Disable or Enable the commands for "Attack", "Skill", "Defend", or "Item", and whatever other custom Commands may be a part of your Battle System.

It is very useful for creating Tutorials for players where you need to force a Player to choose a specific action.  To do this, you just disable the commands you do not want the Player to choose.


Features


  • Easy Script Calls to Enable or Disable any Commands

  • Should be compatible with other Languages

  • Commands are based on the Text of the Command itself for high compatability.




Screenshots

No Screenshots.  Basically it just makes commands that you choose to disable come up in "disabled_color" and plays your systems "Buzzer-SE" to let a Player know that they are not able to select that specific command.


Demo

No demo yet.  I'll throw it in as part of the "Collection" and edit this to link to it or another demo once a demo is created.


Script

Put above Main, but below your Battle System and Menu Systems.

Spoiler: ShowHide
#===============================================================================
#
#           HERETIC'S DISABLE BATTLE COMMANDS
#           Version 1.0
#           Monday, June 2nd, 2014
#
#===============================================================================
#
#  This script will allow you to easily Enable and Disable the Battle Commands
#  for your Actors.  The default Battle Menu Commands like "Attack", "Skill"
#  "Defend", and "Item".  This script was designed to check the text of
#  each Command so you can disable the French word for "Attack", or if you
#  changed stuff to allow for "Super Attack", you can enable or disable
#  those Commands as well.
#
#  All Battle Commands are Enabled by Default.
#
#  There are times that it is useful to Disable Commands.  Some Tutorials can
#  take advantage of disabling all the Battle Commands except the one you want
#  the Player to select.  Other times, it may be based on some condition in
#  your game.
#
#  This script will check the context of each word, so if your "Words" are
#  different, this script should still work, or can be easily modified to
#  be compatible with other Battle Systems.  This also allows foreign Laguages
#  to also be compatible.
#
#  To enable or disable a Command, just put in the Actors ID from the Database
#  and the "Word" you want to disable.
#
#  disable_command(1, "Attack")
#
#  NOTE: The "Word" you want to change MUST BE IN QUOTES.
#
#
#  The above command will make the Battle Command of "Attack" come up greyed
#  out as a visual indication to the Player that it has been disabled.  If
#  the Player tries to enter the command anyway, the system will play the
#  "Buzzer Sound" set in the Database.
#
#  To ENABLE a Command, simply use the Actors ID from the Database and the
#  the "Word" you want to enable.
#
#  enable_command(1, "Attack")
#
#  Once a Command has been Disabled, you MUST re-enable it for the Player
#  to ever use it again.  The Disabled Command will not reset after battle.
#
#  You can enable disable Multiple Commands also, just not in one script call.
#
#  disable_command(1, "Skill")
#  disable_command(1, "Defend")
#  disable_command(1, "Item")
#
#  The above script calls will prevent your Player from selecting any of
#  those Commands from the Command Window.  However, the Player can still
#  "Cancel" and skip to the next actor, or whatever your Battle System is
#  configured to do.
#
#  To prevent a Player from being able to "Cancel", use the following script.
#
#  disable_cancel(1)
#
#  That script call will prevent Aluxes from being able to "Cancel" to the
#  next Actor.  When combined with disable_command(actor_id, word), you force
#  the Player to have only one option to choose from.  Its VERY useful for
#  creating Tutorial Battles.
#
#  You can enable or disable Commands or Cancels for more than just one Actor
#  at a time.  For that, I put together a couple quick script calls to do it
#  all for you.
#
#  These script calls can be run either During Battle or Outside of Battle.
#
#  Note: They are Per Actor.  It doesnt matter what position they are in.
#
#
#  ---  LIST OF SCRIPT CALLS  ---
#
#  - Single Actor Commands -
#
#  enable_command(actor_id, "Word to Enable in Quotes")
#  disable_command(actor_id, "Word to Disable in Quotes")
#
#
#  - Single Actor Cancel (skip to next actor or defend) -
#
#  enable_cancel(actor_id)
#  disable_cancel(actor_id)
#
#
#  - Party Actor Commands and Cancels -
#
#  enable_command_party("Word to Enable")
#  disable_command_party("Word to Disable")
#  enable_cancel_party
#  disable_cancel_party
#
#
#  - All Actors, even ones NOT in your Party -

#  enable_command_all("Word to Enable")
#  disable_command_all("Word to Disable")
#  enable_cancel_all
#  disable_cancel_all
#
#
#  ---  NOTES  ---
#
#  Please be careful if you Add or Remove Actors as Commands, once Disabled
#  will STAY that way.
#
#  ---  COMPATABILITY  ---
#
#  This script should work with most Battle Systems, excluding Map Based Systems
#  like BlizzABS.  The Actor Command Window is normally a Window_Command which
#  inherits from Window_Selectable.  If the Battle System you are using has
#  altered @actor_command_window = Window_Command.new(params) to NOT be a
#  class of Window_Command, the fix should be super easy.  Just change the
#  name of the class in this script for Window_Command to whatever your
#  Battle System uses.
#
#==============================================================================

#==============================================================================
# ** Interpreter
#==============================================================================
class Interpreter
  #--------------------------------------------------------------------------
  # * Enable Cancel - Enables ability to Cancel while Command Window is open
  #     actor_id  : Actor ID in the Database, does not matter where in Party
  #--------------------------------------------------------------------------   
  def enable_cancel(actor_id)
    # If Actor ID isnt a Number
    if not actor_id.is_a?(Numeric)
      # Explain Error
      print "Warning: enable_cancel(actor_id) expects\n",
            "actor_id to be a Number!\n\n",
            actor_id, " is not a Number!" if $DEBUG
      # Note: I would have actually allowed for disabling by Names, but
      # I cant do it because Actors Names can be changed during gameplay
      # which can lead to unpredictable outcomes
           
      # Prevent Crash
      return
    # Actor isnt a Valid Actor
    elsif not $data_actors[actor_id]
      # Explain Error
      print "Warning: enable_cancel(actor_id)\n\n",
            "The Actor: ", actor_id, " isn't a Valid Actor!" if $DEBUG
      # Prevent Crash
      return
    end
    # Get the Actor based on Actor ID
    actor = $game_actors[actor_id]
    # If Cancel not already Disabled
    if actor.disabled_menu_words.include?("Cancel")
      # Disable Cancelling Inputs for that Actor
      actor.disabled_menu_words.delete("Cancel")
    end
  end 
  #--------------------------------------------------------------------------
  # * Disable Cancel - Disables ability to Cancel while Command Window is open
  #     actor_id  : Actor ID in the Database, does not matter where in Party
  #--------------------------------------------------------------------------   
  def disable_cancel(actor_id)
    # If Actor ID isnt a Number
    if not actor_id.is_a?(Numeric)
      # Explain Error
      print "Warning: disable_cancel(actor_id) expects\n",
            "actor_id to be a Number!\n\n",
            actor_id, " is not a Number!" if $DEBUG
      # Note: I would have actually allowed for disabling by Names, but
      # I cant do it because Actors Names can be changed during gameplay
      # which can lead to unpredictable outcomes
           
      # Prevent Crash
      return
    # Actor isnt a Valid Actor
    elsif not $data_actors[actor_id]
      # Explain Error
      print "Warning: disable_cancel(actor_id)\n\n",
            "The Actor: ", actor_id, " isn't a Valid Actor!" if $DEBUG
      # Prevent Crash
      return
    end
    # Get the Actor based on Actor ID
    actor = $game_actors[actor_id]
    # If Cancel not already Disabled
    if not actor.disabled_menu_words.include?("Cancel")
      # Disable Cancelling Inputs for that Actor
      actor.disabled_menu_words.push("Cancel")
    end
  end
  #--------------------------------------------------------------------------
  # * Enable Cancel Party - Enables Cancelling Command Windows for Party
  #
  #   - Note: Watch for changes to your Party!
  #--------------------------------------------------------------------------   
  def enable_cancel_party
    # For each Actor in your active Party
    for actor in $game_party.actors
      # Enable the ability to Cancel
      enable_cancel(actor.id)
    end
  end
  #--------------------------------------------------------------------------
  # * Disable Cancel Party - Disables Cancelling Command Windows for Party
  #
  #   - Note: Watch for changes to your Party!
  #--------------------------------------------------------------------------   
  def disable_cancel_party
    # For each Actor in your active Party
    for actor in $game_party.actors
      # Enable the ability to Cancel
      disable_cancel(actor.id)
    end
  end 
  #--------------------------------------------------------------------------
  # * Enable Cancel All - Enables Cancelling Command Windows for All Actors
  #
  #   - Note: Enables Cancel for Actors not in your Party also
  #--------------------------------------------------------------------------   
  def enable_cancel_all
    # For Everyone, All Actors, even ones not in Party
    for i in 0..$game_actors.size
      # Get the Actor
      actor = $game_actors[i]
      # Enable the ability to Cancel
      enable_cancel(actor.id) if not actor.nil?
    end
  end
  #--------------------------------------------------------------------------
  # * Disable Cancel All - Disables Cancelling Command Windows for All Actors
  #
  #   - Note: Disables Cancel for Actors not in your Party also
  #--------------------------------------------------------------------------   
  def disable_cancel_all
    # For Everyone, All Actors, even ones not in Party
    for i in 0..$game_actors.size
      # Get the Actor
      actor = $game_actors[i]
      # Enable the ability to Cancel
      disable_cancel(actor.id) if not actor.nil?
    end
  end
  #--------------------------------------------------------------------------
  # * Enable Command - Disables Command for Battle Commands (Item, Skill, etc)
  #     actor_id  : Actor ID in the Database, does not matter where in Party
  #     menu_word : The Text of the Menu Word to be disabled (Attack, Item, etc)
  #
  #   - Note: Default is all Commands are already Enabled
  #   - Useful for Tutorial Battles
  #-------------------------------------------------------------------------- 
  def enable_command(actor_id, menu_word)
    # If Actor ID isnt a Number
    if not actor_id.is_a?(Numeric)
      # Explain Error
      print "Warning: disable_menu(actor_id, menu_word) expects\n",
            "actor_id to be a Number!\n\n",
            actor_id, " is not a Number!" if $DEBUG
      # Note: I would have actually allowed for disabling by Names, but
      # I cant do it because Actors Names can be changed during gameplay
      # which can lead to unpredictable outcomes
           
      # Prevent Crash
      return
    # Actor isnt a Valid Actor
    elsif not $data_actors[actor_id]
      # Explain Error
      print "Warning: disable_menu(actor_id, menu_word)\n\n",
            "The Actor: ", actor_id, " isn't a Valid Actor!" if $DEBUG
      # Prevent Crash
      return
    # If the Menu Word is not a String like "Fight" or "Item"
    elsif not menu_word.is_a?(String)
      # Explain Error
      print "Warning: disable_menu(actor_id, menu_word)\n\n",
            "menu_word needs to be the Battle Command Word that\n",
            "you wish to Disable!\n\n",
            "Examples:\n",
            "# Disable Aluxes Fight Menu Item\n",
            "disable_menu(1, \"Fight\"\n",
            "# Disable Hilda Skill Menu Item\n",
            "disable_menu(8, \"Skill\"" if $DEBUG
      # Prevent Crash
      return
    elsif menu_word == ""
      # Explain Error
      print "Warning: disable_menu(actor_id, menu_word)\n\n",
            "menu_item can not be blank!\n",
            "disable_menu(", actor_id," \"\")" if $DEBUG
      # Prevent Crash
      return       
    end
    # Get the Actor based on Actor ID
    actor = $game_actors[actor_id]
    # If Item not already Disabled
    if actor.disabled_menu_words.include?(menu_word)
      # Disable the Menu Item for that Actor
      actor.disabled_menu_words.delete(menu_word)
    end
  end
  #--------------------------------------------------------------------------
  # * Disable Command - Disables Commands for Battle Commands (Item, Skill, etc)
  #     actor_id  : Actor ID in the Database, does not matter where in Party
  #     menu_word : The Text of the Menu Word to be disabled (Attack, Item, etc)
  #-------------------------------------------------------------------------- 
  def disable_command(actor_id, menu_word)
    # If Actor ID isnt a Number
    if not actor_id.is_a?(Numeric)
      # Explain Error
      print "Warning: disable_menu(actor_id, menu_word) expects\n",
            "actor_id to be a Number!\n\n",
            actor_id, " is not a Number!" if $DEBUG
      # Note: I would have actually allowed for disabling by Names, but
      # I cant do it because Actors Names can be changed during gameplay
      # which can lead to unpredictable outcomes
           
      # Prevent Crash
      return
    # Actor isnt a Valid Actor
    elsif not $data_actors[actor_id]
      # Explain Error
      print "Warning: disable_menu(actor_id, menu_word)\n\n",
            "The Actor: ", actor_id, " isn't a Valid Actor!" if $DEBUG
      # Prevent Crash
      return
    # If the Menu Word is not a String like "Fight" or "Item"
    elsif not menu_word.is_a?(String)
      # Explain Error
      print "Warning: disable_menu(actor_id, menu_word)\n\n",
            "menu_word needs to be the Battle Command Word that\n",
            "you wish to Disable!\n\n",
            "Examples:\n",
            "# Disable Aluxes Fight Menu Item\n",
            "disable_menu(1, \"Fight\"\n",
            "# Disable Hilda Skill Menu Item\n",
            "disable_menu(8, \"Skill\"" if $DEBUG
      # Prevent Crash
      return
    elsif menu_word == ""
      # Explain Error
      print "Warning: disable_menu(actor_id, menu_word)\n\n",
            "menu_item can not be blank!\n",
            "disable_menu(", actor_id," \"\")" if $DEBUG
      # Prevent Crash
      return       
    end
    # Get the Actor based on Actor ID
    actor = $game_actors[actor_id]
    # If Item not already Disabled
    if not actor.disabled_menu_words.include?(menu_word)
      # Disable the Menu Item for that Actor
      actor.disabled_menu_words.push(menu_word)
    end
  end
  #--------------------------------------------------------------------------
  # * Enable Command Party - Enables Battle Commands for everyone in the Party
  #    menu_word : The Text of the Menu Word to be disabled (Attack, Item, etc) 
  #
  #   - Note: Watch for changes to your Party!
  #--------------------------------------------------------------------------   
  def enable_command_party(menu_word)
    # For each Actor in your active Party
    for actor in $game_party.actors
      # Enable the Command from the Menu
      enable_command(actor.id, menu_word)
    end
  end
  #--------------------------------------------------------------------------
  # * Disable Command Party - Disables Battle Commands for everyone in Party
  #    menu_word : The Text of the Menu Word to be disabled (Attack, Item, etc) 
  #
  #   - Note: Watch for changes to your Party!
  #--------------------------------------------------------------------------   
  def disable_command_party(menu_word)
    # For each Actor in your active Party
    for actor in $game_party.actors
      # Disable the Command from the Menu
      disable_command(actor.id, menu_word)
    end
  end 
  #--------------------------------------------------------------------------
  # * Enable Command All - Enables Battle Commands for everyone in Party
  #    menu_word : The Text of the Menu Word to be disabled (Attack, Item, etc) 
  #
  #   - Note: Enables Commands for Actors not in your Party also
  #--------------------------------------------------------------------------   
  def enable_command_all(menu_word)
    # For Everyone, All Actors, even ones not in Party
    for i in 0..$game_actors.size
      # Get the Actor
      actor = $game_actors[i]
      # Enable the Command from the Menu
      enable_command(actor.id, menu_word) if not actor.nil?
    end
  end
  #--------------------------------------------------------------------------
  # * Disable Command All - Disables Battle Commands for everyone in Party
  #    menu_word : The Text of the Menu Word to be disabled (Attack, Item, etc) 
  #
  #   - Note: Disables Commands for Actors not in your Party also
  #--------------------------------------------------------------------------   
  def disable_command_all(menu_word)
    # For Everyone, All Actors, even ones not in Party
    for i in 0..$game_actors.size
      # Get the Actor
      actor = $game_actors[i]
      # Enable the ability to Cancel
      disable_command(actor.id, menu_word) if not actor.nil?
    end
  end
end

#==============================================================================
# ** Window_Command
#
#  NOTE:  You may need to change the name of the class here to make this
#         script compatible with certain Battle Systems.
#
#==============================================================================
class Window_Command < Window_Selectable
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :commands           # Contains Command Words for Battle Menu
  attr_accessor :actor_window       # Tells if Window is for Actor Commands
  #--------------------------------------------------------------------------
  # * Object Initialization
  #     width    : window width
  #     commands : command text string array
  #--------------------------------------------------------------------------
  alias disable_battle_menu_window_command_initialize initialize
  def initialize(width, commands)
    # Call Original or other Aliases
    disable_battle_menu_window_command_initialize(width, commands)
    # Add new Property
    @actor_window = false
  end
  #--------------------------------------------------------------------------
  # * Visible=
  #     value : true / false
  #
  #   - Sets the Visibility of this Window while doing other checks
  #--------------------------------------------------------------------------
  def visible=(value)
    # Ignore if this Command Window is not used for Actor Battle Commands
    if value == true and @actor_window == true and $scene.is_a?(Scene_Battle)
      # Check the Actor Command Window for Disabled Items
      $scene.check_actor_window_commands
    end
    # Set the Value of Parent regardless of Value, typically True or False
    super(value)
  end
end

#==============================================================================
# ** Scene_Battle
#
#    If the name of your Command Window is not @actor_command_window, then
#    you'll need to edit this part of the script to call to whatever your
#    Battle or Menu System uses.
#   
#    It may also be necessary to change the name of the method for checking
#    the Inputs from the Player to match the method used in your game.
#
#==============================================================================
class Scene_Battle
  #--------------------------------------------------------------------------
  # * Start Pre-Battle Phase
  #
  #   The Battle System uses several Command Windows.  This helps to identify
  #   which of those Command Windows is being used for getting the Actors
  #   Commands.
  #
  #   In the normal battle system and XRXS battle system, this is called before
  #   the Actors Battle Command Window appears.  This allows the script to
  #   know which window does what, as there are multiple Window_Selectable
  #   windows in the Battle Scene.  Yeah, it does get called multiple times
  #   but it isnt frequent enough to affect performance.
  #
  #--------------------------------------------------------------------------
  alias disable_battle_menu_start_phase1 start_phase1
  def start_phase1
    # Call Original or other Aliases
    disable_battle_menu_start_phase1
    # Designates the Actor Command Window Variable for Updates
    @actor_command_window.actor_window = true
  end
  #--------------------------------------------------------------------------
  # * Check Actor Window Commands
  #
  #   - Draws the Commands available to that Actor.  Enabled Items use
  #     the normal_color, typically white, and disabled Commands are
  #     drawn using disabled_color, typically grey or subdued.
  #
  #     This method is called when an identified Actor Command Window is
  #     set to become visible.  Thus, before it appears, it checks the
  #     text of each command to to enable and disable appropriately.
  #
  #--------------------------------------------------------------------------
  def check_actor_window_commands
   
    # Window Object for displaying Actor Battle Menu Items
    # NOTE: Change this name for Incompatability issues
    window = @actor_command_window
   
    # Get Actor for the Visible Menu
    actor = $game_party.actors[@actor_index]
    # Check if the Commands are Enabled or Disabled
    for index in 0...@actor_command_window.commands.size
      # The Command Text from the List of displayed Menu Items
      cmd = window.commands[index]
      # If that Command Text has been disabled for this Actor
      if actor.disabled_menu_words.include?(cmd)
        # Disable that Command with Disabled Text Color on the Menu
        window.disable_item(index)
      # Then this Command Text is Enabled for this Actor
      else
        # Draw that Command with Normal Text Color on the Menu
        window.draw_item(index, window.normal_color)
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update (actor command phase)
  #
  #   This phase handles the Input for the Actor Command Window, normally.
  #
  #   This is also where incompatability problems will occur.  If another
  #   battle system doesnt use this command to handle input, problems might
  #   be easily fixed by changing the name of this method to whatever method
  #   is used to handle inputs for Actor Commands.
  #
  #   Note:  Input.trigger? can not be checked multiple times, so checking
  #   if a command is disabled needs to happen before checking input.
  #
  #--------------------------------------------------------------------------
  alias disable_battle_menu_update_phase3 update_phase3
  def update_phase3
    # Get Actor for the Visible Menu
    actor = $game_party.actors[@actor_index]
    # Get the Command Word from the Window
    command = @actor_command_window.commands[@actor_command_window.index]
    # Check if that Actor has had that Menu Word disabled
    disabled = actor.disabled_menu_words.include?(command)
    # Check if that Actor is allowed to process Cancel Input Commands
    cancel = actor.disabled_menu_words.include?("Cancel")
    # If C button was pressed
    if disabled and Input.trigger?(Input::C)
      # Play buzzer SE
      $game_system.se_play($data_system.buzzer_se)
      # Prevent Input Processing
      return
    # If Cancelling the Actor Command Window is Disabled
    elsif cancel and @actor_command_window.active and Input.trigger?(Input::B)
      # Play buzzer SE
      $game_system.se_play($data_system.buzzer_se)
      # Prevent Input Processing
      return
    end
    # Call Original or other Aliases
    disable_battle_menu_update_phase3
  end
end

#==============================================================================
# ** Game_Actor
#==============================================================================
class Game_Actor < Game_Battler
  #--------------------------------------------------------------------------
  # * Object Initialization
  #     actor_id : actor ID
  #--------------------------------------------------------------------------
  alias disabled_battle_menu_item_initialize initialize
  def initialize(actor_id)
    # Call Original or other Aliases
    disabled_battle_menu_item_initialize(actor_id)
    # Disabled Words
    @disabled_menu_words = []
  end
  #--------------------------------------------------------------------------
  # * Disabled Menu Words
  #     List of Battle Menu Words (Attack, Skill, etc) that are Disabled
  #     for this Actor.  Does error checking also.
  #--------------------------------------------------------------------------
  def disabled_menu_words
    # Check if Property not an Array for preventing crash
    @disabled_menu_words = [] if @disabled_menu_words.nil?
    # Return the Array of words
    return @disabled_menu_words
  end
end

#==============================================================================
# ** Game_Actors
#==============================================================================
class Game_Actors
  #--------------------------------------------------------------------------
  # * Size - Returns Size of All Actors in Game
  #
  #   This is needed because $data is a table, and to make a table fast, it
  #   has less commands available than an array, so $data_actors.size is
  #   something that will crash your game by default.  So I just check where
  #   the modifiable data is stored in memory without affecting the templates
  #   stored in $data_ for the total number of Characters in a game.
  #--------------------------------------------------------------------------
  def size
    return @data.size
  end
end



Instructions

This script is pretty easy to use.  Each Disable script call has an Enable script counterpart.

disable_command(actor_id, "Attack")  # Disables "Attack" for that Actor
disable_cancel(actor_id)                   # Disables "Cancelling" or Previous Actor
disable_command_party("Attack")      # Disables "Attack" for entire Party
disable_command_all("Attack")          # Disables "Attack" for all Actors in game

To use the Enable Counterpart, just change disable_ to enable_.

enable_command(actor_id, "Item")



Compatibility

This script only aliases a few existing default methods, but adds several new methods for functionality.

It wont be compatible with BlizzABS because that Battle System takes place in the Map, not in a Battle Scene.  It may not be compatible with some Menu or Battle Systems, but fixing this should not be too difficult.  In the default Battle System, there is a line that says @actor_command_window = Window_Selectable.new".  This will tell you what class this script needs.  What will normally happen with an incompatible Battle or Menu System is that @actor_command_window may be a different class.  Change the name of the class in this script if the class name is not Window_Selectable.  If @actor_command_window is called something else, change those references accordingly in this script.

Battle Systems also need to handle inputs from Players for the "Attack", "Skill" window.  The default method is called "update_phase3".  If your Battle System is using another name for handling inputs from the Player for checking if "attack" or "skill" is selected, just change the name of this method to alias and reference that method instead.

I doubt it will be 100% compatible, but fixing these issues should not be too difficult.



Credits and Thanks


  • Chaos Project for hosting the site to post this script




Author's Notes

Compatability is one of my primary concerns with this script.  Despite it looking like a lot to change, there really isnt that much as there are only about 3 things that can go critically wrong, but they are fairly easy to fix.

If you have compatability issues with a certain Menu System or Battle System, please create a new thread for those issues.

For enhancement requests to this script, please post in this thread.
Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)