Moving Platforms Demo - UPDATED to Release Candidate - Need HELP Testing!

Started by Heretic86, March 26, 2016, 10:06:03 pm

Previous topic - Next topic

Heretic86

NOTE: This is NOT a script release because of its very buggy quality.  This post is intended for discussion of effective ways to achieve this goal.

I thought this was worth while to share.

MOVING PLATFORMS



Its VERY buggy since I've only spent about 2 days working on it so far.  None the less, functional concept!  Im sure there are people interested in seeing what is happening, so here is my Prototype!

DOWNLOAD: Prototype Demo (Obsoleted)

NOTE: This version is now OUT OF DATE.  Full version has been released here.  The download version on this page is a prototype and lacks the functionality and stability of the release version.

This is eventually planned as another add-on for Modular Passable.  I just wanted some feedback from other Scripters what you guys would do in order to resolve the numerous bugs that currently exist.  Yeah, mirrored post in my "Collection" thread. 

But just curious what you guys all think?

Edit:  I'll probably put up new versions as they become available...  I already put up one new version.  Stoopid tyops!
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.)

Heretic86

April 01, 2016, 08:16:16 pm #1 Last Edit: April 11, 2016, 05:59:40 am by Heretic86
Ok, got some serious progress.  Collision works PERFECT, even on Looping Maps!

There is still a ton of work to do however, as you can see in the NOTES:

Spoiler: ShowHide
To use this code, grab the demo in the first link, then just replace ALL the code in Platforms with this version.

OBSOLETE - SEE LINK BELOW


# Version 2

# Notes to self

#
# LOOP MAP TAKEOFF BUG FIXED  - FULLY FIXED
#
# DIAGONAL MOVEMENT BUG - FULLY FIXED
#  (Dont use Script Calls for Random 8D, replacement of def move_random works, or
#   by putting a 1 frame wait after script random 8d Movement)
#
# Why waste time processing Real Distance for Platform if I only use
# its Move Speed anyway? Clamping to Platform Real Values causes takeoff
# issues in movement - Pull the Code and clean up.
#
#
# Player Transfer Stuff
#
# Event Transfer Stuff
#
# Event and Player Transfers, add an argument to allow "dropping" an
#  character onto a Platform without Boarding?  Hmm, set a character
#  flag and add another optional argument to platform_boardable?(c, option = nil)
#
#
# Thnk about how the Caterpillar Anti Lag works and how it relates
# to Platform and Platform Master concept to prevent Animation Desyncrhonization
#
#
#
# Interpreter Stuff (Msg Boxes, etc) like starting? or lock?
# - Able to move while Dialog is on screen HACK?  Nope.  Bug, and part of
#   the default engine!  Player Move Random (repeat) and Touch Event
#   will trigger Touch Events!  Ha Ha!  How to fix that.  Leave as Option?
#
#
# Think about Page Changes for Platform Events - Unboard Riders? Reboard?
#
# Think about STAIRS, shouldnt be too hard, I can just alias my own stuff
#  and make a requirement to place Platform Script below Stairs.  Is there
#  another way to do that?
#
# Interpreter - Freeze Platform movement if Interpreter Running as Option?
#
# Condiser adding in Touch Triggers **  Ok, done, but they have to be THROUGH
#  on Impassable surfaces.
#
# Look at the Triggers, they seem to be Triggerable from too far away?
#
# Test to see if Random Movement - Move Route Repeat can trigger Touch Events
# and continue to move with default scripts
#
# SDK Stuff, movement is ok, but check other Interpreter and Lock stuff
#
# Caterpillar Stuff
#
# Test stepping on to other surfaces, Ice, Stairs - Ice most likely wont
#  work as a Platform unless stepping off, but stairs should work just fine.
#
# SCROLLING CLOUDS GLITCH on edges of Looping Maps
#
# DONT FORGET TO UPDATE MAP HASHES IN COLLISION OPTIMIZER ON TRANSFER
# DONT FORGET TO UPDATE MAP HASHES IN COLLISION OPTIMIZER ON TRANSFER
# DONT FORGET TO UPDATE MAP HASHES IN COLLISION OPTIMIZER ON TRANSFER
#
# ----
#
# Comment the Waiting and Non Waiting "Hack" to make Platforms be used
# for things Unexpected
#
# Look at Restrict Tile passage, did I ever put anything in for No Terrain Tags?
#
# Is the Collision Problem because the Hash is not Updated when Character
# position is Updated? - I think so, I think that if fixed?  DONE, but check
#
# Take a look heavily at Collision Optimizer, when Events are moved about
# the Hash Map may need to be updated because the Old Location isnt properly
# stored in the Hash Map of Events.  Normal Event Updating allows Hash Map
# to self correct, but when using Event Commands to move an Event from
# one spot to another, those Events may have an Out of Date Hash Map, at
# least for one frame



# Check for Modular Passable Script - REQUIRED - DO NOT EDIT
unless $Modular_Passable
  print "Fatal Error: Heretic's Moving Platforms\n",
        "requires Heretics Modular Passable Script!\n\n",
        "Modular Passable is Not Available or is below this script.\n",
        "Modular Passable MUST be above this script.\n\n",
        "The Game must now Exit"
  exit
end

# Check for Heretic's Collision Optimizer Script - REQUIRED - DO NOT EDIT
unless Game_Map::method_defined?('events_hash_xy')
  print "Fatal Error: Heretic's Moving Platforms\n",
        "requires Heretics Collision Optimizer Script!\n\n",
        "Collision Optimizer is Not Available or is below this script.\n",
        "Collision Optimizer MUST be above this script.\n\n",
        "The Game must now Exit"
  exit
end

# If Loop Maps is being used, but is an old bugged version
if Game_Map::method_defined?('map_loop_passable?') and
   (not Game_Map::const_defined?('Loop_Map_Version') or
    Game_Map::Loop_Map_Version < 1.01)
  print "Fatal Error: Heretic's Moving Platforms\n\n",
        "The version of Looping Maps needs to\n be Version 1.01 or above.\n\n",
        "This version of Looping Maps is out of date.\n\n",
        "The Game must now Exit"
  exit
end




#==============================================================================
# ** Game_System
#==============================================================================
class Game_System
  #--------------------------------------------------------------------------
  # * Public Instance Variables - Game_System
  #--------------------------------------------------------------------------
  attr_accessor     :platform_enabled           # Enable or Disable Platforms
  #--------------------------------------------------------------------------
  # * Object Initialization
  #  - Adds Option for stepping on and off Platforms
  #--------------------------------------------------------------------------
  alias platform_system_initialize initialize unless $@
  def initialize
    # Call Original or other Aliases
    platform_system_initialize
    # New Option for allowing Platforms
    @platform_enabled = true
  end
end

#==============================================================================
# ** Game_Map
#==============================================================================
class Game_Map
  #--------------------------------------------------------------------------
  # * Public Instance Variables - Game_Map
  #--------------------------------------------------------------------------
  attr_accessor   :platform_groups        # Groups of Platforms
  attr_reader     :platform_allow_update  # Updates Platforms out of order
  #--------------------------------------------------------------------------
  # * Object Initialization - Game Map
  #--------------------------------------------------------------------------
  alias platform_map_initialize initialize unless $@
  def initialize
    # Call Original or other Aliases
    platform_map_initialize
    # New Array to contain each Platform Group
    @platform_groups = {}
  end
  #--------------------------------------------------------------------------
  # * Setup - Game_Map
  #--------------------------------------------------------------------------
  alias platform_map_setup setup unless $@
  def setup(map_id)
    # Current Map
    current_map_id = @map_id
    # If Changing to a New Valid Map
    if map_id > 0 and map_id != @map_id
      # New Hash to contain each Platform Group
      @platform_groups = {}
      # Reset the Player Platform properties
      $game_player.on_platform = nil
    end
    # Call Original or other Aliases to Initialize and create Events
    platform_map_setup(map_id)
  end
  #--------------------------------------------------------------------------
  # * Update - Game_Map
  #--------------------------------------------------------------------------
  alias platform_map_main_update update unless $@
  def update
    # Call Original or other Aliases of Main Update Method
    platform_map_main_update
    # Update the Platforms Boarding and Unboarding
    platforms_update_boarding
    # Update the Platform Events out of order
    platforms_update_groups
  end
  #--------------------------------------------------------------------------
  # * Platforms Update Boarding - Game_Map
  #  - Checks and Clears any Boarding Flags
  #--------------------------------------------------------------------------
  def platforms_update_boarding
    # Do not Update Out of Order if System Optin is not Enabled
    return unless $game_system.platform_enabled
    # Iterate the Groups (.values is needed for Hashes since its not an array)
    for group in platform_groups.values
      # Temporary Boarding Flags
      group_boarding = false
      clear_boarding = false
      # Iterate each Platform
      for platform in group
        # Check each Platform for a Boarding Flag
        if platform.platform_boarding and not group_boarding
          # Select each Platform Rider and check for Movement and On Platform
          for rider in platform.platform_riders
            # If Rider is not Moving or Jumping
            if rider.jumping? or rider.x * 128 != rider.real_x or
               rider.y * 128 != rider.real_y
              # Platform is still being Boarded / Unboarded
              group_boarding = true
              # Unable to Clear Boarding because Boarding is occuring
              clear_boarding = false
              # End Rider and Platform Iteration
              break(2)
            end
          end
          # Set the Clear Boarding Flag if we got here
          clear_boarding = true
        end
      end
      # Check the Group Boarding and Clear Boarding Flags
      if clear_boarding and not group_boarding
        # Iterate the Platform Events again and Clear any Boarding Flags
        for platform in group
          # Clear Boarding Flags
          platform.platform_boarding = false
        end
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Platforms Update Groups - Game_Map
  #  - Standard Event Updates so Platforms are Updated out of order
  #  - When platform_enabled is not turned on, Platforms update in order
  #--------------------------------------------------------------------------
  def platforms_update_groups
    # Do not Update Out of Order if System Optin is not Enabled
    return unless $game_system.platform_enabled
    # Disable Updating Platform Events
    @platform_allow_update = true
    # Iterate the Groups (.values is needed for Hashes since its not an array)
    for group in platform_groups.values
      # Iterate each Platform
      for platform in group
        # Update each Platform as an Event
        platform.platform_alternate_update
      end
    end
    # Disable Updating Platform Events
    @platform_allow_update = false
  end
  #--------------------------------------------------------------------------
  # * Add Platform To Groups - Game_Map
  #  - Adds Platforms to each Group
  #--------------------------------------------------------------------------
  def add_platform_to_group(event)
    # Get the Platform Group ID
    id = event.platform
    # Check that Array exists
    @platform_groups[id] = [] unless @platform_groups[id].is_a?(Array)
    # Add this Event to this Platform Group if it is not already there
    @platform_groups[id].push(event) unless @platform_groups[id].include?(event)
  end
  #--------------------------------------------------------------------------
  # * Event Tile Not Passable? - Game_Map
  #  - Prevents Boarding and Unboarding of Platforms if it is not Waiting
  #  - Prevents Characters with a \no_platforms Comment from any Movement
  #  - Allows Platforms to move thru ALL Characters unless the Event
  #    is a Platform of a different Platform Group (\platform[1] \platform[5])
  #  - Although there is some Event Iteration, it is very fast due to the
  #    number of Events selected is usually only 1 or 2 at top.  This is also
  #    why Collision Optimizer is required.
  #  - See Modular Passable for Argument Details
  #--------------------------------------------------------------------------
  alias platform_event_tile_not_passable? event_tile_not_passable? unless $@
  def event_tile_not_passable?(x,y,d,bit,event,self_event = nil, result = nil)
    # If Self is a Platform and Event is not a Platform, or Matching Group
    if self_event.platform and
       (not event.platform or event.platform == self_event.platform)
      # Passable - Platforms can not move thru other Platform Groups ONLY
      return false
    end
    # If Platform
    if event.platform and self_event
      # Impassable - \no_platforms comment or @no_platforms property
      return true if self_event.no_platforms
      # Use these Checks if System Option is Enabled
      if $game_system.platform_enabled
        # Shorthand
        platform = $game_map.events[self_event.on_platform]
        # Check against the Platform Group
        if not platform or platform.platform != event.platform
          # Impassable if Platform can not be Boarded
          return true if not event.platform_boardable?(self_event)
        end
      end
    end
    # If Character is on a Platform and checking Self Location
    if self_event and self_event.on_platform and $game_system.platform_enabled
      # Platform Shorthand
      plat = $game_map.events[self_event.on_platform]
      # Check if Platform is Moving
      if plat.x * 128 != plat.real_x or plat.y * 128 != plat.real_y
        # Determine next Location of Movement
        new_x, new_y = self_event.make_new_xy_8d(x, y, d)
        # If New Location is not Current Location since checked Here and There
        if self_event.x != new_x or self_event.y != new_y
          # Get Events at the New Location
          events = get_events_at_xy(new_x, new_y)
          # Default
          found = false
          # Iterate through the Events
          for e in events
            # If Event is not this Platform and is a Boardable Platform
            if e.platform_boardable?(self_event)
              # Another Platform has been found
              found = true
              # Quit Iterating for Performance
              break
            end
          end
          # Impassable - Unable to transfer to another Platform
          return true if not found
        end
      end
    end
    # Call Original or other Aliases with new Results
    platform_event_tile_not_passable?(x, y, d, bit, event, self_event, result)
  end
end

#==============================================================================
# ** Game_Character
#==============================================================================
class Game_Character
  #--------------------------------------------------------------------------
  # * Public Instance Variables - Game_Character
  #--------------------------------------------------------------------------
  attr_accessor   :on_platform       # Event ID of Platform
  attr_accessor   :no_platforms      # Prevents NPC's riding Platforms
  attr_reader     :platform          # Event acts as a Platform (Group ID)
  #--------------------------------------------------------------------------
  # * Increase Steps - Game_Character
  #  - Used to check for Platforms and Platform Boarding
  #--------------------------------------------------------------------------
  alias platform_increase_steps increase_steps unless $@
  def increase_steps
    # Call Original or other Aliases
    platform_increase_steps
    # Check for Platforms to Board
    board_platforms
    # Set a Flag that Passage was possible, thus increasing steps
    @platform_increased_steps = true
  end
  #--------------------------------------------------------------------------
  # * Board Platforms - Game_Character
  #  - Used to check for Platforms and Platform Boarding
  #  - Sets Flags for Unboarding or Transfer
  #--------------------------------------------------------------------------
  def board_platforms
    # Check for Self Properties and System Enabled
    if not @platform and not @no_platforms and not @through and
       $game_system.platform_enabled and not player_platform_debug?
      # Temporary Flag
      platform_found = false
      # Get Location (with Round on Looping Maps if enabled)
      x, y = platform_xy
      # Create a List of Events at the Location this Character just moved to
      events = $game_map.get_events_at_xy(x, y)
      # Current Platform Shorthand (may be nil)
      platform = $game_map.events[@on_platform]
      # Iterate through the Events to see if there is a Platform
      for event in events
        # If Event is a Platform and Platform is Boardable?
        if event.platform_boardable?(self)
          # If Platform has been Boarded
          if event.platform_board_character(self)
            # Set the Temporary Flag
            platform_found = true
            # Assign Event ID of Platform to Character
            @on_platform = event.id
            # If currently on a Platform
            if platform
              # If New Platform is in the same Platform Group
              if platform.platform == event.platform
                # Remove Self from old Platforms Riders
                platform.platform_riders.delete(self)
              else
                # Store the Event ID of the Old Platform to remove later
                @old_platform_id = platform.id
                # Set Boarding Flags on both Platforms
                platform.platform_boarding = true
                event.platform_boarding = true
              end
            # Board the Platform
            else
              # Set Flag that Platform Boarding
              event.platform_boarding = true
              # Assign Event ID of Platform to Character
              @on_platform = event.id
            end
            # Quit iterating the List of Events for Performance
            break
          end
        end
      end
      # If on a Platform and suitable New Platforms were Boarded or Unboarded
      if @on_platform and not platform_found
        # Set the Boarding Flag on the current Platform
        platform.platform_boarding = true
        # Sets a Flag to remove character from Platforms Riders
        @unboard_platform = true
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Player Platform Debug? - Game_Player
  #  - When CTRL Key is Pressed, Player can not board Platforms
  #--------------------------------------------------------------------------
  def player_platform_debug?
    # Check Conditions for Player Debug Movement
    return ($DEBUG and Input.press?(Input::CTRL) and @id == 0)
  end
  #--------------------------------------------------------------------------
  # * Lock - Game_Character
  #  - Prevents Locking Platforms because it causes Animation Errors
  #--------------------------------------------------------------------------
  alias platform_lock lock unless $@
  def lock
    # Prevent Locking Platforms by pressing Enter
    return if @platform
    # Call Original or other Aliases
    platform_lock
  end
  #--------------------------------------------------------------------------
  # * Update - Game_Character
  #  - Removes Characters from Platforms when they step off or transfer
  #--------------------------------------------------------------------------
  alias platform_main_update update unless $@
  def update
    # Used for Debugging Player Movement
    platform_player_debug_update if @id == 0
    # Use Math to determine Moving due to Platforms changing the result
    last_moving = (@x * 128 != @real_x or @y * 128 != @real_y)
    # Call Main Update Method for Character
    platform_main_update
    # Clear the Flag that Passage was possible with Increase Steps
    @platform_increased_steps = nil
    # If no longer moving (using Platform Method of checking)
    if last_moving and not moving? and not jumping?
      # Clear Property
      @dir_last_moved = nil
      # If Transfer between Two Platform Groups
      if @old_platform_id
        # Remove Self from the Old Platforms Riders
        $game_map.events[@old_platform_id].platform_riders.delete(self)
      end
    end
    # If Flag has been set to Unboard from a Platform and no longer moving
    if @unboard_platform and @on_platform and last_moving and
       @x * 128 == @real_x and @y * 128 == @real_y
      # Remove Self from Platform Riders
      $game_map.events[@on_platform].platform_riders.delete(self)
      # Clear the On Platform Event ID and Unboard Flag
      @on_platform = nil
      @unboard_platform = nil
    end
  end
  #--------------------------------------------------------------------------
  # * Passable? - Game_Character
  #  - This preserves a variable needed for motion set in diagonal aliases
  #--------------------------------------------------------------------------
  alias platform_main_passable? passable? unless $@
  def passable?(x, y, d)
    # Call Original or other Aliases to determine result
    result = platform_main_passable?(x, y, d)
    # If Direction is not a Diagonal
    if not [1,3,7,9].include?(@dir_last_moved)
      # Store Movement Direction if able to move
      @dir_last_moved = (result) ? d : nil
    end
    # Return initial result
    return result
  end 
  #--------------------------------------------------------------------------
  # * Move Lower Left - Game_Character
  #--------------------------------------------------------------------------
  alias platform_move_lower_left move_lower_left unless $@
  def move_lower_left
    # Call Original or other Aliases
    platform_move_lower_left
    # Save Diagonal Move Direction (1 is Lower Left, like on a Keypad)
    @dir_last_moved = (@platform_increased_steps) ? 1 : nil
  end
  #--------------------------------------------------------------------------
  # * Move Lower Right - Game_Character
  #--------------------------------------------------------------------------
  alias platform_move_lower_right move_lower_right unless $@
  def move_lower_right
    # Call Original or other Aliases
    platform_move_lower_right
    # Save Diagonal Move Direction (3 is Lower Right, like on a Keypad)
    @dir_last_moved = (@platform_increased_steps) ? 3 : nil
  end
  #--------------------------------------------------------------------------
  # * Move Upper Left - Game_Character
  #--------------------------------------------------------------------------
  alias platform_move_upper_left move_upper_left unless $@
  def move_upper_left
    # Call Original or other Aliases
    platform_move_upper_left
    # Save Diagonal Move Direction (7 is Upper Left, like on a Keypad)
    @dir_last_moved = (@platform_increased_steps) ? 7 : nil
  end
  #--------------------------------------------------------------------------
  # * Move Upper Right - Game_Character
  #--------------------------------------------------------------------------
  alias platform_move_upper_right move_upper_right unless $@
  def move_upper_right
    # Call Original or other Aliases
    platform_move_upper_right
    # Save Diagonal Move Direction (9 is Upper Right, like on a Keypad)
    @dir_last_moved = (@platform_increased_steps) ? 9 : nil
  end
  #------------------------------------------------------------------------
  # * Platform Align Character - Game_Character
  #  - Fixes Riders of a Platform with the Platform Position
  #------------------------------------------------------------------------
  def platform_align_character(x_adj, y_adj, dist_rx, dist_ry)
    # Adjust the X and Y with the Distance the Platform moved in Logical Values
    @x += x_adj
    @y += y_adj
    # Adjust Real X and Y with the Distance the Platform moved in Real Values
    @real_x += dist_rx
    @real_y += dist_ry
    # If Game Player (Player has an ID of 0)
    if @id == 0
      # Scroll the Screen adjusting for Platform Corrections
      platform_scroll_map_update(@real_x - dist_rx, @real_y - dist_ry)
      # If X or Y changed
      if x_adj != 0 or y_adj != 0 and not
         $game_system.map_interpreter.running?
        # Check if Movement has caused any Event Touch Triggers
        check_event_trigger_here([1,2])
      end
    end
  end
  #------------------------------------------------------------------------
  # * Platform Dist - Game_Character
  #  - Distance in Logical Coordinates (no Loop Map Round)
  #------------------------------------------------------------------------
  def platform_distance(x, y)
    return [@x - x, @y - y]
  end
  #------------------------------------------------------------------------
  # * Platform Real Distance - Game_Character
  #  - Distance in Real Coordinates (no Loop Map Round)
  #------------------------------------------------------------------------
  def platform_real_distance(rx, ry)
    return [@real_x - rx, @real_y - ry]
  end
  #------------------------------------------------------------------------
  # * Platform XY - Game_Character
  #  - Returns X and Y values of Character allowing for alias adjustment
  #------------------------------------------------------------------------
  def platform_xy
    # Return the X and Y values of this Character as an array
    return [@x, @y]
  end
  #------------------------------------------------------------------------
  # * Platform X No Match? - Game_Character
  #              real_x : Real X coordinate of Character
  #     platform_real_x : Real X coordinate of Platform Event
  #------------------------------------------------------------------------
  def platform_x_no_match?(real_x, platform_real_x)
    # Return whether or not the Real X and Platform Real X values match
    return (real_x != platform_real_x)
  end
  #------------------------------------------------------------------------
  # * Platform Y No Match? - Game_Character
  #              real_y : Real Y coordinate of Character
  #     platform_real_y : Real Y coordinate of Platform Event
  #------------------------------------------------------------------------
  def platform_y_no_match?(real_y, platform_real_y)
    # Return whether or not the Real Y and Platform Real Y values match
    return (real_y != platform_real_y)
  end
  #------------------------------------------------------------------------
  # * Moving X? - Game_Character
  #------------------------------------------------------------------------ 
  def platform_moving_x?
    # Get the Platform Event
    platform = $game_map.events[@on_platform]
    # If Self is not the Platform Event and Plaform is moving on X
    if platform.x * 128 != platform.real_x
      # Movement is occuring on X if coordinates do not match the Platform
      return platform_x_no_match?(@real_x, platform.real_x)
    end
    # Movement X determined by comparison of logical and real coordinates
    return @real_x != @x * 128
  end
  #------------------------------------------------------------------------
  # * Moving Y? - Game_Character
  #------------------------------------------------------------------------ 
  def platform_moving_y?
    # Get the Platform Event
    platform = $game_map.events[@on_platform]
    # If Self is not the Platform Event and Plaform is moving on Y
    if platform.y * 128 != platform.real_y
      # Movement is occuring on Y if coordinates do not match the Platform
      return platform_y_no_match?(@real_y, platform.real_y)
    end
    # Movement Y determined by comparison of logical and real coordinates
    return @real_y != @y * 128
  end
  #--------------------------------------------------------------------------
  # * Moving? - Game_Character
  #  - Modifies return value of moving? to allow character movement while on
  #    a platform and checks for unboarding from a Platform
  #  - While on a Platform, a Character is not considered moving unless
  #    the real coordinates of the platform and character do not match
  #--------------------------------------------------------------------------
  alias platform_moving? moving? unless $@
  def moving?
    # If Character is on a Platform and Option is Enabled
    if @on_platform and $game_system.platform_enabled
      # Use these methods to check for Platform compared to Character
      return (platform_moving_x? or platform_moving_y?)
    end
    # Call Original or other Aliases
    return platform_moving?
  end
  #--------------------------------------------------------------------------
  # * Platform Clamp Real X - Game_Character
  #  - Returns values to use with movement in [@real_x + dist, clamp_x].min
  #--------------------------------------------------------------------------
  def platform_clamp_real_x(x)
    return (@platform) ? 2 ** @move_speed : x * 128
  end
  #--------------------------------------------------------------------------
  # * Platform Clamp Real Y - Game_Character
  #  - Returns values to use with movement in [@real_y + dist, clamp_y].min
  #--------------------------------------------------------------------------
  def platform_clamp_real_y(y)
    return (@platform) ? 2 ** @move_speed : y * 128
  end
  #--------------------------------------------------------------------------
  # * Platform Update Movement - Game_Character
  #  - Altered to allow indepenedent movement on X and Y for Platforms
  #--------------------------------------------------------------------------
  def platform_update_movement
    # Split Distance into X and Y Distance
    x_dist = y_dist = 2 ** @move_speed
    # Set X and Y distance to 0 if direction is not relevant
    case @dir_last_moved
    when 4, 6 # Left and Right
      y_dist = 0
    when 2, 8 # Up and Down
      x_dist = 0
    end
    # Platform shorthand
    platform = $game_map.events[@on_platform]
    # Determine Clamping Values for Real X and Real Y
    clamp_x = platform.platform_clamp_real_x(@x)
    clamp_y = platform.platform_clamp_real_y(@y)
    # If command was to move character down, down left, or down right
    if [2,1,3].include?(@dir_last_moved)
      # Move down
      @real_y = [@real_y + y_dist, @real_y - clamp_y].max
    # If command was to move character up, up left, or up right
    elsif [8,7,9].include?(@dir_last_moved)
      # Move up
      @real_y = [@real_y - y_dist, @real_y + clamp_y].min
    end
    # If command was to move character left, down left, or up left
    if [4,1,7].include?(@dir_last_moved)
      # Move left
      @real_x = [@real_x - x_dist, @real_x + clamp_x].min
    # If command was to move character right, down right, or up right
    elsif [6,3,9].include?(@dir_last_moved)
      # Move right
      @real_x = [@real_x + x_dist, @real_x - clamp_x].max
    end
    # If move animation is ON
    if @walk_anime
      # Increase animation count by 1.5
      @anime_count += 1.5
    # If move animation is OFF, and stop animation is ON
    elsif @step_anime
      # Increase animation count by 1
      @anime_count += 1
    end   
  end 
  #--------------------------------------------------------------------------
  # If Heretic's Loop Maps is installed
  #--------------------------------------------------------------------------
  if Game_Map.method_defined?(:map_loop_passable?)
    #----------------------------------------------------------------------
    # * Platform XY - Game_Character - Loop Map Redefinition
    #  - Returns X and Y values of Character allowing for alias adjustment
    #----------------------------------------------------------------------
    def platform_xy
      # Get the Values of X and Y adjusted for Looping Maps
      x = ($game_map.loop_horizontal?) ? @x % $game_map.width : @x
      y = ($game_map.loop_vertical?) ? @y % $game_map.height : @y
      # Return the X and Y values of this Character as an array
      return [x, y]
    end
    #------------------------------------------------------------------------
    # * Platform X No Match? - Game_Character - Loop Map Redefinition
    #              real_x : Real X coordinate of Character
    #     platform_real_x : Real X coordinate of Platform Event
    #------------------------------------------------------------------------
    def platform_x_no_match?(real_x, platform_real_x)
      # If values in Argument need to be adjusted for Looping Maps
      if $game_map.loop_horizontal?
        real_x %= $game_map.width * 128
        platform_real_x %= $game_map.width * 128
      end
      # Return whether or not the Real X and Platform Real X values match
      return (real_x != platform_real_x)
    end
    #------------------------------------------------------------------------
    # * Platform Y No Match? - Game_Character - Loop Map Redefinition
    #  - This fixes Loop Map Adjustments and returns true / false on match
    #              real_y : Real Y coordinate of Character
    #     platform_real_y : Real Y coordinate of Platform Event
    #------------------------------------------------------------------------
    def platform_y_no_match?(real_y, platform_real_y)
      # If values in Argument need to be adjusted for Looping Maps
      if $game_map.loop_vertical?
        real_y %= $game_map.height * 128
        platform_real_y %= $game_map.height * 128
      end
      # Return whether or not the Real Y and Platform Real Y values match
      return (real_y != platform_real_y)
    end
    #----------------------------------------------------------------------
    # * Platform Distance - Game_Character - Loop Map Redefinition
    #  - Distance in Logical Coordinates
    #----------------------------------------------------------------------
    def platform_distance(x, y)
      # Shorthand for Width and Height
      w = $game_map.width
      h = $game_map.height
      # Round Positions for Looping Maps
      x = ($game_map.loop_horizontal?) ? x % w : x
      y = ($game_map.loop_vertical?) ? y % h : y
      # Round Self Positions for Looping Maps
      sx = ($game_map.loop_horizontal?) ? @x % w : @x
      sy = ($game_map.loop_vertical?) ? @y % h : @y
      # Determine Initial Distance
      x_dist = sx - x
      y_dist = sy - y
      # If Looping and Distance is more than half Width of Map
      if $game_map.loop_horizontal? and x_dist.abs > w / 2
        x_dist += (x_dist < 0) ? w : w * -1
      end
      # If Looping and Distance is more than half Height of Map
      if $game_map.loop_vertical? and y_dist.abs > h / 2
        y_dist += (y_dist < 0) ? h : h * -1
      end
      # Return Distance XY as an Array - x, y = method(x, y)
      return [x_dist, y_dist]
    end
    #----------------------------------------------------------------------
    # * Platform Real Distance - Game_Character - Loop Map Redefinition
    #  - Distance in Real Coordinates
    #----------------------------------------------------------------------
    def platform_real_distance(rx, ry)
      # Shorthand for Width and Height in Real Values
      w = $game_map.width * 128
      h = $game_map.height * 128
      # Round Positions for Looping Maps
      rx = ($game_map.loop_horizontal?) ? rx % w : rx
      ry = ($game_map.loop_vertical?) ? ry % h : ry
      # Round Self Positions for Looping Maps
      srx = ($game_map.loop_horizontal?) ? @real_x % w : @real_x
      sry = ($game_map.loop_vertical?) ? @real_y % h : @real_y
      # Determine Initial Distance
      rx_dist = srx - rx
      ry_dist = sry - ry
      # If Looping and Distance is more than half Width of Map
      if $game_map.loop_horizontal? and rx_dist.abs > w / 2
        rx_dist += (rx_dist < 0) ? w : w * -1
      end
      # If Looping and Distance is more than half Height of Map / 2
      if $game_map.loop_vertical? and ry_dist.abs > h / 2
        ry_dist += (ry_dist < 0) ? h : h * -1
      end
      # Return Distance XY as an Array - x, y = method(x, y)
      return [rx_dist, ry_dist]
    end
    #----------------------------------------------------------------------
    # * Platform Align Character - Game_Character - Loop Map Alias
    #  - Alias corrects Player Position on Looping Maps
    #----------------------------------------------------------------------
    alias loop_platform_align_character platform_align_character unless $@
    def platform_align_character(dist_x, dist_y, dist_rx, dist_ry)
      # Call Original or other Aliases
      loop_platform_align_character(dist_x, dist_y, dist_rx, dist_ry)
      # If Not the Player
      if @id != 0
        # If Map Loops Horizontally
        if $game_map.loop_horizontal? and (@x < 0 or @x > $game_map.width)
          # Round for Horizontal Loop
          @x %= $game_map.width
          @real_x %= $game_map.width * 128
        end
        # If Map Loops Vertically
        if $game_map.loop_vertical? and (@y < 0 or @y > $game_map.height)
          # Round for Vertical Loop
          @y %= $game_map.height
          @real_y %= $game_map.height * 128
        end
      end
    end
  end # End Loop Map Redefinitions
  #--------------------------------------------------------------------------
  # * Update Move - Game_Character
  #  - Allows movement to be handled differently while on a Platform
  #--------------------------------------------------------------------------
  alias platform_update_move update_move unless $@
  def update_move
    # If on a Platform and not Unboarding
    if @on_platform and not @unboard_platform and @dir_last_moved
      # Movement Update for Characters on Platforms
      platform_update_movement
    else
      # Call Original or other Aliases
      platform_update_move
    end
  end
  #--------------------------------------------------------------------------
  # * Event Not Passable? - Game_Character
  #  - Allows Platforms to pass thru all Characters if the other
  #    character is not a Platform of a different Platform Group
  #--------------------------------------------------------------------------
  alias platform_event_not_passable? event_not_passable? unless $@
  def event_not_passable?(x, y, d, new_x, new_y, event, result = nil)
    # Check for two Platforms of the same Group
    if @platform and @tile_id > 0 and $game_system.platform_enabled and
       not (event.platform and @platform != event.platform)
      # Passable to Platforms of the same Platform Group
      return false
    end
    # Call Original or other Aliases
    platform_event_not_passable?(x, y, d, new_x, new_y, event, result)
  end
  #--------------------------------------------------------------------------
  # * Event Character Not Passable? - Game_Character
  #  - Allows Platforms to pass thru all other Characters
  #  - Comparison to other Platform groups is done in other Passable methods
  #--------------------------------------------------------------------------
  alias p_event_character_not_passable? event_character_not_passable? unless $@
  def event_character_not_passable?(x, y, d, new_x, new_y, event, result = nil)
    # Platforms are allowed to pass through ALL other Events and Characters
    return false if @platform and $game_system.platform_enabled
    # Call Original or other Aliases
    p_event_character_not_passable?(x, y, d, new_x, new_y, event, result)
  end
  #--------------------------------------------------------------------------
  # * Jump - Game_Character
  #     x_plus : x-coordinate plus value
  #     y_plus : y-coordinate plus value
  #--------------------------------------------------------------------------
  alias platform_jump jump unless $@
  def jump(x_plus, y_plus)
    # Store Old Coordinates
    last_x, last_y = @x, @y
    # Call Original or other Aliases
    platform_jump(x_plus, y_plus)
    # If New Coordinates are different
    if last_x != @x or last_y != @y
      # If plus value is not (0,0)
      if x_plus != 0 or y_plus != 0
        # If horizontal distnace is longer
        if x_plus.abs > y_plus.abs
          # Use the Direction that Passable was used to check
          @dir_last_moved = (x_plus < 0) ? 4 : 6
        # If vertical distance is longer, or equal
        else
          # Use the Direction that Passable was used to check
          @dir_last_moved = (y_plus < 0) ? 8 : 2
        end
      end   
      # Check if Jumping to a Platform
      board_platforms
    end
  end
end

#==============================================================================
# ** Game_Event
#==============================================================================
class Game_Event < Game_Character
  #--------------------------------------------------------------------------
  # * Public Instance Variables - Game_Event
  #--------------------------------------------------------------------------
  attr_accessor :platform_boarding      # If Platform is being Boarded
  attr_reader   :platform_sync          # Sync other Platform Groups (Array)
  #--------------------------------------------------------------------------
  # * Check Comment Page Config - Game_Event
  #--------------------------------------------------------------------------
  alias platform_check_page_comment_config check_page_comment_config unless $@
  def check_page_comment_config(comment, count)
    # Looks for "\platform[N]" Comments to create Platform Groups
    comment.gsub(/^\\platform\[([-0-9]+)\]\z/i) {
      # Only Tiles can be Platforms at this time
      if @tile_id > 0
        # Assign Platform Group ID to Event as a Property
        @platform = $1.to_i
        platform_riders = []
        # Add this Event to the Game Map Platform Groups
        $game_map.add_platform_to_group(self)
      else
        if $DEBUG
          print "Error for Event ",@id,", Platforms MUST have a Tile ID\n",
                "(You can set the Opacity to 0 to make it Invisible\n",
                "or use Event Pages)"
          @platform = nil
        end
      end
      # Allow other Alises that use Page Comments to be parsed
      return count;
      }
    # Looks for "\platform[N]" Comments to create Platform Groups
    comment.gsub(/^\\no_platforms\z/i) {
      # Set Flag to prohibit this Event riding on Platforms
      @no_platforms = true
      # Allow other Alises that use Page Comments to be parsed
      return count;
      }
    # Looks for "\platform_sync[2, 3]" in the Comment on List of Event Commands
    comment.gsub(/^\\platform_sync\[([0-9, ]+)\]\z/i){ @platform_sync = $1;
      @platform_sync = @platform_sync.split(",").map { |s| s.to_i };
      return count;
      }
    # Call Original or other Aliases since Comment contained no Platform Data
    return platform_check_page_comment_config(comment, count)
  end
  #--------------------------------------------------------------------------
  # * Reset Page Comment Config - Game_Event
  #  - Resets Platforms on Refresh or Page Change
  #--------------------------------------------------------------------------
  alias platform_reset_page_comment_config reset_page_comment_config unless $@
  def reset_page_comment_config
    # Reset Platform Properties
    @platform = nil
    @platform_riders = []
    @no_platforms = nil
    @platform_sync = nil
    @platform_starting = nil
    # Call Original or other Aliases
    platform_reset_page_comment_config
  end
  #--------------------------------------------------------------------------
  # * Platform Riders - Game_Event
  #  - Contains Characters (Player and Events) currently Riding Platform
  #--------------------------------------------------------------------------
  def platform_riders
    return @platform_riders ||= []
  end
  #--------------------------------------------------------------------------
  # * Update - Game_Event
  #  - Main Update Method for Game_Event
  #  - Allows Updates for Platforms to occur out of order
  #--------------------------------------------------------------------------
  alias platform_event_main_update update unless $@
  def update
    # If Platform and System Option is Enabled
    if @platform and $game_system.platform_enabled
      # Updates for Platforms performed out of order so must be Enabled
      return unless $game_map.platform_allow_update
    end
    # Call Original or other Aliases
    platform_event_main_update
  end
  #--------------------------------------------------------------------------
  # * Start Event - Game_Event
  #  - Pressing the Enter Key while on a Platform causes all Platforms to
  #    have the Starting flag set because they require Comments to be able
  #    to function as expected.  When Enter is pressed, Comments count in
  #    the List of Event Commands, thus, pressing Enter causes the Event
  #    to become desyncrhonized.  if @list.size > 1 registers Comments
  #--------------------------------------------------------------------------
  alias platform_event_start start unless $@
  def start
    # If trying to Start a Platform
    if @platform
      # Use a different flag to check @starting
      @platform_starting = true
      # Cant use the @starting flag if a Platform due to Animation
      return
    end
    # Call Original or other Aliases
    platform_event_start
  end
  #--------------------------------------------------------------------------
  # * Start Event - Game_Event
  #  - Typically just sets @starting to false by Interpreter
  #  - This definition clears an additional property by Alias
  #--------------------------------------------------------------------------
  alias platform_event_clear_starting clear_starting unless $@
  def clear_starting
    # Clear Platform Starting
    @platform_starting = false
    # Call Original or other Aliases
    platform_event_clear_starting
  end
  #--------------------------------------------------------------------------
  # * Starting - Game_Event
  #  - This replaces an attr_reader :starting to check for two values
  #    for Platforms due to Animation being halted while the Starting
  #    flag is set on Events
  #--------------------------------------------------------------------------
  def starting
    return (@starting or (@platform and @platform_starting) )
  end
  #--------------------------------------------------------------------------
  # * Move Type : Custom - Game_Event
  #  - Prevents Custom Movement for Platform Groups if being Boarded
  #--------------------------------------------------------------------------
  alias platform_move_type_custom move_type_custom unless $@
  def move_type_custom
    # If Player or Event is not completely on the Platform
    if @platform and platform_boarding?
      # Prevent Custom Movement Until until Platform has been fully Boarded
      return
    end
    # Call Original or other Aliases
    platform_move_type_custom
  end
  #--------------------------------------------------------------------------
  # * Platform Boardable? - Game_Event
  #  - Checks if this Event can be Boarded
  #  - This does not place restrictions on moving between Platforms of
  #    the same Platform Group
  #  - Checking @wait_count > 1 instead of 0 prevents intermittent behavior
  #    because Platfomrs are updated out of order
  #--------------------------------------------------------------------------
  def platform_boardable?(character)
    # False if Self is not a Platform
    return false unless @platform
    # Cannot Board unless System Enabled
    return false unless $game_system.platform_enabled
    # Cannot Board if Character has a No Platform Flag
    return false if character.no_platforms
    # Platforms can not board other Platforms
    return false if character.platform
    # Platforms can not be Through
    return false if @through
    # Get the Platform Event
    platform = $game_map.events[character.on_platform]
    # Look for a Group Match (@platform holds the Platform Group ID)
    if (platform and @platform == platform.platform) or @wait_count > 1
      # Boardable
      return true
    end
    # Not Boardable if not Waiting
    return false
  end
  #--------------------------------------------------------------------------
  # * Platform Boarding? - Game_Event
  #  - Checks if Player or other Events are boarding this Platform
  #--------------------------------------------------------------------------
  def platform_boarding?
    # Array of Groups to Check
    sync_groups = [@platform]
    # Check other Platform Events in same Group
    platforms = $game_map.platform_groups[@platform]
    # Iterate each Platform
    for platform in platforms
      # See if there are any other Groups to Sync with
      if platform.platform_sync.is_a?(Array)
        # Merge the Temporary Array with the one from the Platform Comment
        sync_groups = sync_groups + platform.platform_sync
      end
    end
    # Remove Duplicates for Performance
    sync_groups = sync_groups.uniq
    # Iterate the Groups
    for group_id in sync_groups
      # Get the Group from Game Map as Platforms
      platforms = $game_map.platform_groups[group_id]
      # If a Group is found
      if platforms
        # Iterate each Platform
        for platform in platforms
          # Group is being Boarded if ANY Platforms checked have Boarding Flags
          return true if platform.platform_boarding
        end
      end
    end
    # Default State - Not Being Boarded
    return false
  end
  #--------------------------------------------------------------------------
  # * Board Platform - Game_Event
  #  - Checks conditions and adds Character as a Platform Rider
  #--------------------------------------------------------------------------
  def platform_board_character(character)
    # Check for Properties
    if character.no_platforms or character.platform or character.through or
       not $game_system.platform_enabled
      # Unable to Board
      return false
    end
    # Check if Character is already in the Array
    if not platform_riders.include?(character)
      # Add this Character to the list of Riders
      platform_riders.push(character)
      # Boarding was successful
      return true
    end
  end
  #--------------------------------------------------------------------------
  # * Platform Alternate Update - Game_Event
  #  - Allows Out of Order Updating by Game_Map calls
  #  - This is NOT an Alias of the Main Update Method
  #--------------------------------------------------------------------------
  def platform_alternate_update
    # Save Coordinates in Temporary Variables (Last X lx, Last Y ly)
    lx, ly = @x, @y
    # Save Real Coordinates
    last_real_x, last_real_y = @real_x, @real_y
    # Update the Event using the Main Update Method Call
    update
    # Use Saved Positions to Update Platform Riders Positions
    platform_update_rider_positions(lx, ly, last_real_x, last_real_y)
  end
  #--------------------------------------------------------------------------
  # * Platform Update Rider Positions - Game_Event
  #  - Updates the Positions of all of the Platform Riders
  #--------------------------------------------------------------------------
  def platform_update_rider_positions(x, y, last_real_x, last_real_y)
    # Determine Distance of Movement on X and Y
    x_dist, y_dist = platform_distance(x, y)
    # Change Distance into -1, 0, or 1
    x_adj = (x_dist < 0) ? -1 : (x_dist > 0) ? 1 : 0
    y_adj = (y_dist < 0) ? -1 : (y_dist > 0) ? 1 : 0
    # Determine Real Distance of Movement with Last Real X and Last Real Y
    rx_dist, ry_dist = platform_real_distance(last_real_x, last_real_y)
    # Iterate through each Rider
    for rider in platform_riders
      # Align the Characters Position with the Platforms Movements
      rider.platform_align_character(x_adj, y_adj, rx_dist, ry_dist)
      # If X or Y values for this Character have been changed and not Player
      if (x_adj != 0 or y_adj != 0) and not rider.id == 0
        # Correct the Map Hash Keys for Events for Proper Collisions
        rider.store_map_hash_keys
      end
    end
  end
end

#==============================================================================
# ** Game_Player
#==============================================================================
class Game_Player
  #--------------------------------------------------------------------------
  # * Platform Scroll Map Update - Game_Player
  #  - Scroll is usually called when movement is updated, but movement is
  #    considered as not moving while on a platform.  This is called in
  #    a special case while riding a platform
  #      last_real_x : Player Real X value prior to platform movement
  #      last_real_y : Player Real Y value prior to platform movement
  #--------------------------------------------------------------------------
  def platform_scroll_map_update(last_real_x, last_real_y)
    # If character moves down and is positioned lower than the center
    # of the screen
    if @real_y > last_real_y and @real_y - $game_map.display_y > CENTER_Y
      # Scroll map down
      $game_map.scroll_down(@real_y - last_real_y)
    end
    # If character moves left and is positioned more let on-screen than
    # center
    if @real_x < last_real_x and @real_x - $game_map.display_x < CENTER_X
      # Scroll map left
      $game_map.scroll_left(last_real_x - @real_x)
    end
    # If character moves right and is positioned more right on-screen than
    # center
    if @real_x > last_real_x and @real_x - $game_map.display_x > CENTER_X
      # Scroll map right
      $game_map.scroll_right(@real_x - last_real_x)
    end
    # If character moves up and is positioned higher than the center
    # of the screen
    if @real_y < last_real_y and @real_y - $game_map.display_y < CENTER_Y
      # Scroll map up
      $game_map.scroll_up(last_real_y - @real_y)
    end
  end
  #--------------------------------------------------------------------------
  # * Platform Debug Update - Game_Player
  #  - When CTRL Key is Pressed, Player is Removed from Platforms
  #  - When CTRL Key is Released and Player is over a Platform, the Player
  #    is forced onto the Platform whether it is Boardable or not
  #--------------------------------------------------------------------------
  def platform_player_debug_update
    # If Player was just Debugging
    if @platform_last_debug and not Input.press?(Input::CTRL)
      # Get Events at Location that the Player was "Dropped"
      events = $game_map.get_events_at_xy(@x, @y)
      # Iterate thru the Events
      for event in events
        # If Event is a Platform
        if event.platform and not event.through
          # Bypass Boarding Checks and put the Player on this Platform
          event.platform_board_character(self)
          # Align Self with the Platform on Real X and Y
          @real_x, @real_y = event.real_x, event.real_y
          # Store the Event ID of the Platform just Boarded
          @on_platform = event.id
          # Exit the For Loop
          break
        end
      end
      # Clear the Debug Property
      @platform_last_debug = nil
    end
    # If holding down the CTRL Key and run from the Editor
    if player_platform_debug?
      # Check for Platforms
      if @on_platform
        # Get the Event
        platform = $game_map.events[@on_platform]
        # Remove Self from list of Riders
        platform.platform_riders.delete(self)
        # If Platform has no other Riders and is Boarding
        if platform.platform_boarding and platform.platform_riders.size == 0
          # Clear the Boarding Flag
          platform.platform_boarding = nil
        end
        # Clear the Property
        @on_platform = nil
      end
      # Check for Old Platforms
      if @old_platform_id
        # Get the Event
        platform = $game_map.events[@old_platform_id]
        # Remove Self from list of Riders
        platform.platform_riders.delete(self)
        # If Platform has no other Riders and is Boarding
        if platform.platform_boarding and platform.platform_riders.size == 0
          # Clear the Boarding Flag
          platform.platform_boarding = nil
        end
        # Clear the Property
        @old_platform_id = nil
      end
      # Set Flag that Platform Debug is occuring
      @platform_last_debug = true
    end
  end
  #--------------------------------------------------------------------------
  # If Heretic's Loop Maps is installed
  #--------------------------------------------------------------------------
  if Game_Map.method_defined?(:map_loop_passable?) 
    #------------------------------------------------------------------------
    # * Map Loop Position - Game_Player
    #  - Calls for Corrections when Player triggers a Map Loop
    #------------------------------------------------------------------------
    alias platform_map_loop_position map_loop_position unless $@
    def map_loop_position
      # If on a Platform
      if @on_platform
        # Get the Platform Event
        p = $game_map.events[@on_platform]
        # Determine Distance between Logical and Real (if Rounding is needed)
        x_dist = (@x * 128) - @real_x
        y_dist = (@y * 128) - @real_y
        # We have a Deviation if Distance is greater than 1 / 2 Map
        x_dev = (x_dist.abs > $game_map.width * 64) ? true : false
        y_dev = (y_dist.abs > $game_map.height * 64) ? true : false
        # If Platform is moving, Player is moving, or Jumping
        if @real_x != @x * 128 or @real_y != @y * 128 or
           p.real_x != p.x * 128 or p.real_y != p.y * 128 or
           jumping? or x_dev or y_dev
          # Set Looped Property for Scripts to check Value for ONE FRAME
          $game_map.looped = nil
          # If Horizontal Map Loop
          if $game_map.loop_horizontal?
            # If a Horizontal Loop is Occuring
            if @real_x < 0 or @real_x > $game_map.width * 128
              # Correct Positions if outside Map Boundaries
              correct_loop_left if @real_x < 0
              correct_loop_right if @real_x > $game_map.width * 128
            # Else if we have a Deviation in Logical and Real Coordinates
            elsif x_dev
              # Round the New Coordinates to correct Deviation
              @x %= $game_map.width
              @real_x %= $game_map.width * 128
              # Recenter Display Horizontally
              $game_map.display_x = @real_x - CENTER_X
            end
          end
          # If Horizontal Map Loop
          if $game_map.loop_vertical?
            # If a Vertical Loop is Occuring
            if @real_y < 0 or @real_y > $game_map.height * 128
              # Correct Positions if outside Map Boundaries
              correct_loop_up if @real_y < 0
              correct_loop_down if @real_y > $game_map.height * 128
            # Else if we have a Deviation in Logical and Real Coordinates
            elsif y_dev
              # Round the New Coordinates to correct Deviation
              @y %= $game_map.height
              @real_y %= $game_map.height * 128
              # Recenter Display Vertically
              $game_map.display_y = @real_y - CENTER_Y
            end
          end
          # Prevent Original from running
          return
        end
      end
      # Call Original or other Aliases
      platform_map_loop_position
    end
  end # End Loop Map Redefinitions
end


LEGAL PERMISSION TO DISTRIBUTE THIS VERSION OF THE CODE IN ANY FORM IS EXPLICITLY DENIED

Later versions of this code that I post will NOT be subject to the same legal restrictions.

In its current state, it will break your game, but can be used during development for your game.

--- END Legal Jargon ---


This code is probably now in a state it can be used for your own development, but you will need to update as newer versions are replaced and there is a TON of stuff I still have to do before releasing a full version.

---  Update Notes and Usage  ----

To create a Platform, put in a Comment in the first 10 lines that reads:
\platform[1]
- ALWAYS USE NUMBERS

You can replace 1 with different platform groups.  Platforms are intended to have several events right next to each other.  When these Events are next to each other and expected to move together, use the same NUMBER in the comment "\platform[3]".  This allows you to have a number of Platform Groups, each with their own sets of Events.

\platform_sync[2, 3, 11]

Platforms are also intended for you to be able to synchronize movement automatically with other groups when needed.  This is really only needed if you want a character to step from one Platform Group ( \platform[1] )  to another Platform Group ( \platform[2] ) and make sure it looks correct.

For example, if you intend to have Platform Group 1 have characters step from Platform Group 1 to Platform Group 2, then do the following

On the Events in Platform Group 1, put these comments:
\platform[1]
\platform_sync[2]

On the events in Platform Group 2, put these comments:
\platform[2]
\platform_sync[1]

Platform Sync is implemented and functioning properly at this time.

Platform Master is planned, but has not yet been implemented.  I'll try to work it in, but it may be too involved to get working correctly and preserve performance.



---  I WOULD LIKE SOME BUG HELP ---

One bug I would like a hand with, if anyone is interested has to do with FOGS at the edges of Looping Maps.  If you move the Player around a whole bunch on a Platform Group that is moving around, you'll occasionally see the FOG glitch and snap to a totally different position.  I took a look at it, but have not figured it out yet.  Its gonna be a hum dinger so any assistance would be appreciated.


---  OTHER NOTES  ---

Platforms (events with a \platform[n] comment) can move through ALL other Events and NPCs and even the Player EXCEPT for Platforms of OTHER Groups.  Thus, Group 1 can move through Group 1 and everything else, but the only restriction is a Group 1 Platform can NOT move through a Group that is not Group 1.

---

Im not sure if there are ANY Moving Platform scripts out there which are not related to Pixel Movement...  so yay for the community for this!  :D

Other than all that, what do you guys think so far?
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.)

schmoggi

Eat this, EB! This feels so naturally, something like this should have been in the maker from the start... like much more stuff.
I love what i see, Heretic. You did not only fix the endless loop Animation, but also the strange feeling of "slow movement" is completeley gone. Gorgeous!

greetz

Heretic86

Quote from: schmoggi on April 02, 2016, 07:31:18 am
Eat this, EB! This feels so naturally, something like this should have been in the maker from the start... like much more stuff.
I love what i see, Heretic. You did not only fix the endless loop Animation, but also the strange feeling of "slow movement" is completeley gone. Gorgeous!

greetz


Thanks!  Yeah, the weird movement was coming from Collision problems.  I wont bother to explain, but now that collision stuff works properly, doesnt the movement just feel "totally normal and expected" for RPG Maker XP games?

Spent most of the day busy with other stuff so havent made any progress to report.  I'll post new code once its ready tho.

I will need some testers...
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.)

Heretic86

April 11, 2016, 05:46:48 am #4 Last Edit: April 11, 2016, 09:14:52 am by Heretic86
Bump!

Ok, got a NEW VERSION!  Im updating the status to RELEASE CANDIDATE!

Download Here!

---

I'd really like some help with this!

Please TRY TO BREAK IT!

Take the script and play with it to your hearts content!  Do stuff like Save Games, change Event Pages, Switches, test compatibility with other scripts, push it to the limit!  I think I nailed all the bugs and glitches, but this is a very complex script so I need some help.  Do stuff like put a character on a Platform, then go back in the Editor and delete the Platform, things like that which you might do during normal course of editing that could case some issues.  Thats what I mean by TRY TO BREAK IT

Ive given nearly full Documentation, but here is a short recap

** REQUIRES MODULAR PASSABLE **
** REQUIRES COLLISION OPTIMIZER **

Scripts are included in the Download Link above.

Put some Comments on an Event:
\platform[1]
\tile_allow_move[1]  NOTE: This feature requires Restrict Tile Passages Script
\allow_npc                NOTE: This feature requires NPCs on Event Tiles

Do NOT put a Checkmark in THROUGH!  That is what the \tile_allow_move[2,3,4] Comment is intended for!

Put your Platform over an Impassable Tile, like Water (if Water is your first Autotile, or change the \tile_allow_move comment), and give the Platform Event a Move Route that has a WAIT command. 

$>Move Left
$>Wait 20 Frame(s)
$>Move Right
$>Wait 20 Frame(s)

You can put the Platforms of the same Group ID (  \platform[group_id]  ) next to each other to make BIG Platforms.  A requested feature for a Platform Master was also included.  Give one of your many Platforms a \platform_master[1] to control Group #1.  Comments are required on each Page, and need to be in the top 10 or so lines IN ANY ORDER.

PLEASE let me know if you either find any bugs or are unable to find any bugs!  BOTH are very important right now as Im not putting legal permissions on this script for a full release until I get a few eyes to take a look at it...

Thanks guys!  Enjoy!

---

Edit: Ok, found a bug, Forcing a Platform Master to be given a Move Route was busted.  Fixed.  Also added Jumping while on a Platform to affect any characters riding that Platform.  Woot for changes huh?  I uploaded a new version so if in doubt, grab it again.  I'll probably have to do this a few times...
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.)

orochii

I tried jumping while on the platform and it did some weird stuff xD.

Here is the code I added to the update, it's the same thing I use for my game. Just below the case Input.dir4 in Game_Player#update
# == Jump Button ==
      if Input.trigger?(Input::A)
        if $game_player.jumping? == false
          #jump_size = 0
          #jump_size += 1 if Input.dir8 > 0
          #jump_size += 1 if button_state(:RUN)
          #jump_size = 2 if [1,3,7,9].include?(Input.dir8)
          jump_size = Input.dir8 > 0 ? 2 : 0
          case Input.dir8
          when 0
            xp,yp = 0,0
          when 1
            xp,yp = 0-(jump_size/2),jump_size / 2
          when 2
            xp,yp = 0,jump_size
          when 3
            xp,yp = jump_size/2,jump_size/2
          when 4
            xp,yp = 0-jump_size,0
          when 6
            xp,yp = jump_size,0
          when 7
            xp,yp = 0-(jump_size/2),0-(jump_size/2)
          when 8
            xp,yp = 0,0-jump_size
          when 9
            xp,yp = jump_size/2,0-(jump_size/2)
          end
         
          #$game_player.jump(xp,yp)
          jump_route = RPG::MoveRoute.new
          jump_command = RPG::MoveCommand.new(code = 14, parameters = [xp,yp])
          jump_route.list.insert(0,jump_command)
          jump_route.repeat=false
          $game_player.force_move_route(jump_route)
        end
      end

It did some fun things like being stuck until the platform stopped moving and jumping too far to the left and going out of the screen as the platform moved.

Then I tried adding some more code to the jump in order to make it adjust itself to the available space in the map (because I use this in my game too).
  #--------------------------------------------------------------------------
  # * Jump
  #     x_plus : x-coordinate plus value
  #     y_plus : y-coordinate plus value
  #--------------------------------------------------------------------------
  def jump(x_plus, y_plus)
    # If plus value is not (0,0)
    if x_plus != 0 or y_plus != 0
      # If horizontal distnace is longer
      if x_plus.abs > y_plus.abs
        # Change direction to left or right
        x_plus < 0 ? turn_left : turn_right
      # If vertical distance is longer, or equal
      else
        # Change direction to up or down
        y_plus < 0 ? turn_up : turn_down
      end
    end
    # Calculate new coordinates
    new_x = @x + x_plus
    new_y = @y + y_plus
    # If plus value is (0,0) or jump destination is passable
    if (x_plus == 0 and y_plus == 0) or (passable?(new_x, new_y, 0))
      # Straighten position
      straighten
      # Update coordinates
      @x = new_x
      @y = new_y
      # Calculate distance
      distance = Math.sqrt(x_plus * x_plus + y_plus * y_plus).round
      # Set jump count
      @jump_peak = 12 + distance - @move_speed
      @jump_count = @jump_peak * 2
      # Clear stop count
      @stop_count = 0
      @move_start = true
    elsif !(passable?(new_x, new_y, 0))
      x_plus = x_plus > 0 ? [x_plus - 1 ,0].max : [x_plus + 1 ,0].min
      y_plus = y_plus > 0 ? [y_plus - 1 ,0].max : [y_plus + 1 ,0].min
      jump(x_plus, y_plus)
    end
  end

It still makes weird things when jumping on board the moving platform. So my advice right now is: Don't jump while a moving platform is moving.

I'm now trying to integrate it with my game. It doesn't crash xD. But it doesn't completely work. The moving platforms move, but the player doesn't seems to be boarding the platform. It just sits over it, the platform moves under his feet, and... yeah, that's it. The character doesn't seems to realize that there is something called friction that makes you move with objects xD!.

But I think it's solvable and it should have something to do with my own modifications. Also my game uses RGSS3 binaries and it has no problem with that :^D.

Heretic86

Ok.  So two things for you.  On Jumping, is the trouble occuring when the Platform is moving or holding still?

On the Platform sliding out from under, that could be a Script Order issue...  In order to get a character to move on a Platform, I had to unlock the characters from the normal XY Grid of RMXP, but relock them to the Grid of the Platform.  I'll bet if you can solve the character on a Platform issue first, you may have a better chance of solving the Jumping issue.

So despite the volume of code, there are two main properties which I suspect are affecting you.  Fix the issue with "boarding" the platform and the Jump issue will stand a chance of being corrected.  Both @on_platform and @dir_last_moved.  Both are needed for Platform Movement.  The @on_platform property (which is just the Event ID of the Platform Event) is normally set in Increase Steps.  The next property is @dir_last_moved.  I set this in checks made in Passable or right after Passable calls.  If a position is considered Passable, then typically Increase Steps is called.  In Increase Steps, I set a flag to remember temporarily if Increase Steps had been called.  I figured that in those cases, its a much simpler way of remembering if Passable had evaluated to True or False.  What sounds like isnt happening is there is @dir_last_moved isnt being saved due to custom movement calls, or Increase Steps isnt being called either.  I attempt to clear both those values immediately after updating so they dont hang around next frame update unless they are needed.

I wrote a method called "platform_save_dir_last_moved" so you could Alias it to save @dir_last_moved.  Take a peek at my Stairs version.  Yes, I Aliased my own methods for compatibility, and as an example.  Then call either Increase Steps, or call def board_platforms(x, y) directly after Passable has evaluated to true.  That should put your character on a Platform, where both @on_platform is saved, and puts the character on the Platforms "list of event riders", which also stores Character IDs.  I'll also hope that the way youre handling Jumping is in a specific order:  if jumping? update_jump; elsif moving? update_move.  That will allow you to put in code into your Update Jump, after updating your jump coordinates, then conditional branch platform_movement_conditions? and call platform_update_movement since movement for platforms will be skipped while jumping.

This is all in theory right now, and probably a ton of work for you, but that should help you to get these two scripts to be compatible.  If you need me to customize any of my code so you can make adjustments without affecting functionality, I'll do it because this is the very high level stuff I would like to make sure can happen.
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.)

Heretic86

Update:

Ive been working on building a proper Demo, which is usually when I find and fix most of my bugs.

I did manage to find a few things.

#1 - Changing Pages had a typo that caused a game crash.  Forgot to add an "s" to platform_group.

#2 - Using "Set Move Route..." on a Platform while it is Moving can cause issues for the Player.  Setting a Move Route on a non moving Platform is just fine and works exactly as expected.  However, because a solution would cause more trouble for users than it would fix, I did not correct this Bug.  I did mention it in some updated documentation.

Also, as Helios pointed out, he had some trouble getting another custom movement script to work with this one.  I expanded the documentation to explain how this system works and how to integrate another custom movement script with this one.

Full Release with revised Legal is getting closer, and yes, it will be free, even for Commercial projects.  Just gotta get rid of those game crashing bugs, but I suspect I have them corrected or documented.
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.)

orochii

Sorry, I read your post some years ago but got distracted by your explanations xD.

Yes, it occurs when the platform moves. I was able to jump out of the platform in your demo (since there are obstacles, I jumped over them, and everything felt fine). But then I tried jumping while boarding the platform, and then things happened.

By the way, I retested it on my game. Guess what? I forgot I was using a savegame, I had to set $game_system.platform_enabled to true! Now all is working just as in the demo. But thanks a lot for your explanation, this made me jump into the script and take a look at it.

I'll be waiting for that update, and working on other things for now. Maybe the things you've fixed solve my jumping problems.

Great script so far! :^D

EDIT: I made a video, wonder if it's visible? I wanted to make it hidden for some reason. It's just the things I mentioned happening. I don't know if it helps :^D. Also I made it with my game, I should've captured the demo! Hahahahah!
https://www.youtube.com/watch?v=JP8X22KtguI

Heretic86

Well, you should know I found a ton of Jump bugs tonight.  I think this very well could affect you.  Alas, the shortcomings of working with prototype scripts, right?  This should actually solve your issue of jumping in place while on a platform too.

I may need to see your move / jump script to get things working as expected, but close to fixing those jump bugs.  Just gotta work out some characters taking off all the way across the screen on the edges of looping maps.  Script has to work with or without the additional ones so let me solve that and I'll put up a new version as soon as I get this batch of bugs licked.

BTW: Video was visible, even if not searchable, which I didnt test.  It appears there might be a need to call event.store_map_hash_keys after moving based on some of the content that I saw.

---

Edit:  Ok, got a new version up.  Fixed a ton of stuff, but there is still one big bug that crashes games.  I feel pretty confident I have all the Jump stuff working now.  Other than that, I think once I can nip this last bug, I may be able to release.

Release Candidate #2
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.)

Heretic86

Nope.  Found more bugs.  Squashed em.  You all suck at finding bugs.  :P

Okay, I put a Final version that I believe is now BUG FREE in the Collection.  I havent updated the first post yet, still looking for beta testers or any positive / negative feedback, so if no one says anything, I'll probably update the first post to version 2.1 this weekend.  Not really changing anything, just giving some time for people to provide any feedback on it.

SUPPORT:

I'll provide support for version 1.0+ in this thread, but not for other scripts.

---

This will be posted on several websites, but I do plan on using CP primarily.  Im waiting for Pacman over at RMRK to reset my acct there so I can post the updated content.
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.)

Blizzard

Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

KK20


Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!

Heretic86

Lol, all good.  Well, script is out now, and it may not be needed right this very moment, but Im sure someone, somewhere will have a use for it.
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.)

orochii

I'm using your platforms script now, it works now with no problems as far as I've seen :^).

I have several questions though. Are characters unable of boarding/unboarding while the platform is moving? It's just something I observed, but I was not sure if that was the case.
Also jumping onto a platform now seems to be impossible, is it? If it is, then It's fine because that removes the bugs.

But so far it's a great script, and it's compatibility it's outstanding! I mean, I doomed my game as imcompatible with 99% of stuff, and for this to work I just had to change around 7 lines :^D.

My move_upper_left definition has a parameter because of a small change I did to passability, I actually need to check if that's working as before too. And the other thing is because I encapsulated the save/load functions into a SaveFile module. So it's just changing the class and adding class << self in order to make the aliasing work.

Heretic86

Characters can not board / unboard onto a moving platform by moving the character.  However, you can use set event location, and if the character can normally get on then, they can get on when transferred.  If you have a big block of platforms, thats not considered "boarding", thats just moving around, and that is unrestricted by either moving or jumping.

Boarding and Unboarding are different than "transfers".  Transfers are basically "set event location" or "set player location".  They work based on the Platforms Move Route.  Platforms are either "moving" with Move Left, Move Right, or should have a "Wait..." command going.  While the "Wait..." command is executing, then platforms are boardable / unboardable, but theres no restrictions around moving between platform events of the same group.  This means that the Move Frequency will need to be set to highest.  It could be your Move Frequency that is causing any sort of Boarding or Unboarding issues.  For example: Move Route ->  Move Left, Move Left, Wait 20 frames, Move Right, Move Right, Wait 20 frames.  Wash, rinse, repeat.  I did it like that to try to preserve compatability with other scripts that may alter the way Stop Counts and other ways to have done it could have been changed.

Jumping onto a platform should be perfect.  If you can step onto a platform, should be able to move as well.  If you cant step, then cant jump either.  Thats a restriction of boarding, and same thing should apply to both movement and jumping.

What happens when you move upper left?  Params were there so you could do exactly that.

I think using SaveFile as a module will work okay.  I put in the option to disable saving while on a platform cuz there were a few snags that may pop back up depending on peoples other scripts.  Basically, when you load a game, if any Edits to the game had taken place, the platform is moved back to its original location which could leave the player stranded over an impassable tile.  Since Editing usually only occurs before a game is released and really shouldnt after a game is released (if its bug free).  The script checks if the game had been edited (with "magic_number"), and if it had been edited, it moves the Player to the location of the platform they were on so they arent stranded, even if edited, in theory.  I had to fight with the caterpillar a bit to get it to load properly too.  Since those things could pop back up with other modifications of other scripts, I put in the option to disable saving if the player is having any interactions with a platform at all, and is extended if the Caterpillar is used. 

I know it works with 8 dir movement cuz I built it using a new game with the 8D movement thing I mentioned in previous posts.  But, since you do have some custom methods for your Jumping stuff, I think what is happening is those two methods may be conflicting.  I came across a number of things I did not think would "ever" be possible, but rethought the problem through and did find solutions.

Trust me, you CAN get this script to work in your game, and your Jump script with enough effort.  Its not a matter of code, its a matter of seeing the problem from a different perspective and writing code around that different perspective.  If I could write code to allow Event Jumping, you can write code to allow Jumping on a button press.  Difficult, but not impossible.  Hardest part is changing ones perspective.

If you really need me to, I can take a look at your Jump code and see if I can get it fixed.

---

NOTE: For the record, Full Version is in the Collection now.  Still working on a Standalone Demo.  There were a lot of significant changes between Release Candidates and Version 1.0.  Just wanna make sure youre using the latest version, although it may end up needing some code rewriting...
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.)