Chaos Project

RPG Maker => RPG Maker Scripts => RMXP Script Database => Topic started by: Heretic86 on April 29, 2015, 07:57:33 pm

Title: [XP] Heretic's Modular Passable XP
Post by: Heretic86 on April 29, 2015, 07:57:33 pm
Modular Passable XP
Authors: Heretic
Version: 1.0
Type: Custom Movement System
Key Term: Custom Movement System



Introduction

Modular Passable is a Framework that allows many scripts to make modifications to both Game_Map passable and Game_Character passable.  It is mostly intended as a Scripter's Tool, and as a Core Script for other scripts that are dependant on it.

You won't notice any changes to your game if you use it without additional scripts.


Features




Screenshots

No screenshots


Demo

Spoiler: ShowHide
http://downloads.chaos-project.com/heretic86/MP/ModularPassable.exe

NOTE: This Demo contains a number of different scripts just to show you what this script was designed to do.

- NPCs on Event Tiles
- Restrict Tile Passages (Required for Vehicles)
- Restrict Bush Passages
- Downhill Ice Deluxe
- Diagonal Stairs Deluxe
- Loop Maps
- Collision Optimizer
- Mirror Movement
- Circular Sprite Motion
- Hotfoot Tiles
- Heretic's Vehicles

All of these additional scripts require Modular Passable in order to be compatible.  There are quite a few more fully compatible scripts that have nothing to do with Modular Passable, but were included for Gameplay Experience.



Script

Place below Scene_Debug.
Place below the SDK, if you use it.
Place below Heretic's Animation Speed, if you use it.
Place ABOVE ALL OTHER SCRIPTS.

Spoiler: ShowHide
#==============================================================================
#
#           HERETIC'S MODULAR PASSABLE [XP]
#           Version 1.0
#           Friday, October 31st, 2014
#
#==============================================================================
#
# -----  Installation  ------
#
# Place below the SDK if you use it, or below Scene Debug.  It should be above
# all other custom scripts.
#
#
# ---  Version History  ---
#
# Version 1.0 - Tuesday, October 21st, 2014
# - Initial Release
#
# -----  Overview  ------
#
# This is a Compatability Tool!  Use only when required!
#
# Some other scripts may be dependant on this one.  If this script is required
# by another Script, just place this below the SDK if it is installed, or
# below Scene_Debug, and above all other scipts.
#
# This script is NOT intended as an SDK. 
#
# It is only intended to allow specific scripts that are not compatible due
# to conflicting definitions of passable to be made compatible.  I expect
# that it will cause compatability issues, just like the SDK and MACL, hence
# why I suggest using it sparingly.  If you really like it, or it helps you
# solve compatability issues, be my guest and use it as a foundation.
#
# Dont just install this script by itself as it does nothing for you without
# dependant scripts.
#
#
# ------  Modularization  ------
#
# The intent of this script is to Modularize all of the internal calls made
# within Passable methods for Game_Map and Game_Character.
#
# Checks that are made and local variables created are now done by separate
# methods.  This allows Aliases of these methods to alter the functionality
# without the need to either rewrite the main Passable method itself, or to
# do additional iterations elsewhere, which is bad for performance.
#
# - This Script is NOT intended for Maximum Performance
# - This Script IS intended for Maximum Compatability
#
# The benefits will only be apparent when two or more scripts are used that are
# dependant on this framework.
#
#
# -----  Additional Arguments  -----
#
# I tried to pass along relevant arguments to each of the methods, even if
# those arguments are not initially needed.  Other scripts may have need of
# the arguments passed, even if the initial functionality does not use the
# arguments.  Local Variables have also been passed because they can be very
# expensive to recalculate, such as event hash iteration.
#
# In order to maximize compatability between other scripts without creating
# the need to have a specific order for those scripts, every method that is
# called by the main Passable methods allows previously determined results
# to be passed along to other Aliases, or to be completely overridden by
# returning the value as determined by those Aliases.
#
# If you have a script that needs to alter the results of make_new_xy or
# make_new_xy_8dir, please pass the result value in an Array of [x, y]
# to receive the values properly.  This script does not provide for
# actual eight directional movement, but can handle the checks needed
# in eight directional movement without replacing the passable methods.
#
#
#
# -----  Additional Functionality: Tile Events  ------
#
# Since this script isnt intended to make every script compatible with every
# other script, I took the liberty of making some enhancements.
#
# The first significant change that I made was to create a hash to hold only
# Events that have Tile Graphics.  Game_Map Passable originally checked all
# of the events on a map, then checked if each event had a Tile Graphic each
# and every time an Event tried to move.  The @event_tiles hash is updated
# in Refresh for Game Event, which is far less frequent than iterating every
# single Event multiple times for each frame of gameplay.
#
# It is much faster to have fewer events to iterate.  So Game_Map Passable now
# only iterates the Events in the smaller array.  Trust me, the performance
# gain made here is significant enough to offset the extra checks made by
# additional arguments passed as methods.
#
# -----  Additional Functionality: Event Refresh Options  -----
#
# Event Refresh has two new purposes.  The first is to update the @event_tiles
# hash.  The second allows iterating the first several Comments on an Event
# Page for other scripts that use Comments to configure Events.
#
# Event Refresh allows you to easily put in Comment Configurations for your
# script.  When an Event is Refreshed, the Comments are passed to a method
# that you can Alias easily and scan for your conditions. This helps to
# prevent conditions that Comments need to be on the first line of
# an Event Page, so additional scripts can add lots of functionality and
# retain compatability.
#
# -----  Comment Limit  -----
#
# The COMMENT_LIMIT is used so that only Comments made within the LIMIT
# number of lines are checked.  So if you have \option = "foo" on the 3rd line
# it will be checked, but putting \other_option = true on line 17, that wont
# be checked because it will exceed the LIMIT.  The COMMENT_LIMIT feature is
# purely for performance.
#
# The Default COMMENT_LIMIT is 10.  I strongly recommend that you keep this
# value for performance.  If you need to change this value, you can do so
# per Event by adding a \comment_limit[N] Comment on that Event page.  This
# will allow only that Page of that Event to check more than the Default.
# This allows performance gains made by keeping the constant at a pretty
# low number intact while still allowing you to do what you need to do
# without comprimising performance.  The code is also intended as an Example
# for Scripters to take a look at to see how to use Comments to add additional
# properties in their scripts more easily.
#
# \comment_limit[N] - Overrides the Constant value set in Configuration
#
# Note: Each line of a Comment or Script counts as a Line.
#
# Note: Only the first line of a Comment is passed to the checking method.
#       Additional lines can be checked with proper Scripting since the
#       counter is also passed as an argument.
#
#
#
# -----  Compatability  -----
#
# This script will NOT be compatible with any other script that replaces
# either Game_Map Passable or Game_Character Passable.  If a script replaces
# Game_Event Refresh, that can be fixed by putting the entire Game_Event class
# below the conflicting script, but leave Game_Map and Game_Character classes
# in this script above other user created scripts, except the SDK.
#
# If the nature of other scripts is extremely different, expect problems.  So
# other scripts like Pixel Movement Scripts most likely will be too foreign
# for this script to offer any compatability.  Bananas and Screwdrivers.
#
# This is intended for making the Default Movements more Modular only.
#
#
# -----  Framework Script  -----
#
# *** DO NOT USE SUPER FOR ALIASES IN IHERITING CLASSES ***
#
# The result of using Super will cause OTHER SCRIPTS BELOW YOURS TO BREAK.
#
# If you use this Script as a Framework for a Script you create, in order
# to maintain a high degree of compatability with other scripts, Class
# Structure needs to be maintained.  This is important when altering
# the outcome of any of the Game_Character definitions.  Inheriting
# Classes in Ruby works great, however, aliasing in Subclasses and the use
# of SUPER will break Inheritance Chains of additional scripts.  Your script
# will work just fine, but your Script will also BREAK any following Scripts
# because methods called in following scripts will not be called at all!
#
# Each Method defined here also contains a "- Class_Name" so that you can
# maintain proper Class Structure.  Alias these methods within their
# appropriate classes when applicable.
#
# When you use Game_Event < Game_Character, and create an Alias of a method
# defined in other scripts under Game_Character, any additional scripts that
# use Game_Event passage checks will NOT be called!
#
# To maintain your Class Structure for dependant Scripst, please ONLY make
# aliases of the Game_Character class and DO NOT create aliases or use
# the Super command in your scripts.  To allow you to make your necessary
# checks for proper conditions, the argument of self_event has been passed
# to relevant methods.  Use "not self_event.nil? and self != self_event", or
# "self == $game_player" for Player, or "self != self_event" for Events.
#
# Staying within Game_Character and using self checks for methods defined
# in the Modular Passable script will allow both your script and other
# dependant scripts to be 100% compatible and retain Script Order Free
# functionality.  Definitions for Game_Event that pertain to resetting
# any @instance_variables and define them can be aliased within the
# Event_Class.  Methods that are unique to your script can be used in
# whatever Class you want.  Methods that are defined in this script
# should maintain the Class Structure of this Script.
#
# If any methods in a script you create are not being called as expected, then
# start looking at any dependant scripts that I have not written for proper
# Class Sturctures.  Game_Character should stay in Game_Character and
# Game_Event should stay in Game_Event.  This could very well be the reason
# the methods defined in your script are not being called, and it would have
# nothing to do with your script.
#
# If you add additional arguments to any method, please pass two arguments
# in your *args calls, one for a :type, and additional *args for what ever
# values you need to check.  This will allow your script to maintain 100%
# compatability with other scripts that also need to use *args, then just
# write your checks like "if args[0] == :my_type and ...".  That will make
# sure your script only checks for your conditions, and other scrips will
# check for their conditions.  This is untested and isnt very efficient,
# but will maintain a higher degree of compatability.
#
# ---  Return vs Result  ---
#
# You can return true or false if you believe your conditions should
# override all other scripts.  For example, Super_Through or something like
# that.  Otherwise I would recommend using "result = true / false" as
# this script will return a true / false value before making the normal
# checks defined in this script.
#
#
# -----  Configuration: COMMENT_LIMIT  -----
#
#  COMMENT_LIMIT puts a cap on the number of Lines that will be read in
#  the List of Event Commands for Comment Configurations.  It prevents
#  every single line of an Event from being read, which will cause Lag
#  when you have lots of Events with lots of commands.  Each Line of
#  a Comment or Script will count as a Line.  Increasing this number
#  will have an impact on performance so don't go nuts and set this
#  number beyond anything reasonable.
#
#  You can override the COMMENT_LIMIT constant by adding a \comment_limit[N]
#  Comment to an Event within the first 10 lines.  This is useful if you
#  only have very few events that need to exceed this limit.  However, if
#  your Events are all full of Configuration Comments, then it is an
#  appropriate time to bump up the value of the constant.
#
#==============================================================================


COMMENT_LIMIT = 10   # Number of Event Commands to scan for Comment Options

#==============================================================================
# ** Game_Map
#==============================================================================
class Game_Map
  #--------------------------------------------------------------------------
  # * Object Initialization - Game_Map
  #--------------------------------------------------------------------------
  alias modular_passable_initialize initialize unless $@
  def initialize
    # Call Original or other Aliases
    modular_passable_initialize
    # New Property to hold Hash of all Events with Tile Graphics
    @event_tiles = {}
  end
  #--------------------------------------------------------------------------
  # * Event Tiles - Game_Map
  #   - A smaller hash than all events to iterate through for performance
  #   - Updates on Event Refresh for performance.  Any change in Pages with
  #     Switches or other Conditions requires Events to be Refreshed, which
  #     is where the hash is updated.
  #--------------------------------------------------------------------------
  def event_tiles
    # Returns existing hash or creates new for save games
    return @event_tiles ||= {}
  end
  #--------------------------------------------------------------------------
  # * Setup - Game_Map
  #  - Creates or Clears the Hash
  #     map_id : map ID
  #--------------------------------------------------------------------------
  alias modular_passable_setup setup unless $@
  def setup(map_id)
    # Clear Event Tiles (Each Event with a Tile will add itself on Refresh)
    @event_tiles = {}
    # Call Original or other Aliases
    modular_passable_setup(map_id)
  end
  #--------------------------------------------------------------------------
  # * Determine Valid Coordinates - Game_Map
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #     self_event : Character calling $game_map.passable 
  #     result     : true or false passed as an arg by Aliases
  #  - Added all available arguments for other Aliases to alter result
  #--------------------------------------------------------------------------
  def valid?(x, y, d = nil, self_event = nil, result = nil)
    # If an Alias has declared a Result, use the Alias result instead
    return result if not result.nil?
    # Standard Map Valid Determination
    return (x >= 0 and x < width and y >= 0 and y < height)   
  end
  #--------------------------------------------------------------------------
  # * Make Bit - Game_Map
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #     self_event : Character calling $game_map.passable 
  #     result     : true or false passed as an arg by Aliases
  #  - Converts Direction in Obstacle Bit (00001011)
  #--------------------------------------------------------------------------
  def make_bit(x, y, d, self_event = nil, result = nil)
    # If an Alias has declared a result, use the Alias result instead
    return result if not result.nil?
    # Change direction (0,2,4,6,8,10) to Obstacle Bit (0,1,2,4,8,0)
    bit = (1 << (d / 2 - 1)) & 0x0f
    # Return the Obstacle Bit
    return bit
  end
  #--------------------------------------------------------------------------
  # * Make Map Passable List - Game_Map
  #  - Returns an Array or Hash of Events for Iteration 
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #     bit        : Direction converted to Obstacle Bit 
  #     self_event : Character calling $game_map.passable
  #     results    : MUST be an Array or Hash of Events
  #  NOTE: results is Plural, not singular
  #  NOTE: MUST return an Array of Events
  #--------------------------------------------------------------------------
  def make_map_passable_list(x, y, d, bit, self_event = nil, results = nil)
    # If an Alias has declared an Hash of Events, use the Alias result instead
    return results if not results.nil?
    # Return the Hash of Map using event_tiles Method
    return event_tiles.values
  end
  #--------------------------------------------------------------------------
  # * Map Passable Conditions? - Game_Map
  #  - Return truth value if conditions met: true / false
  #  - Conditions for running Passability Checks on an Event
  #  - Typically an Event isnt checking itself, Through, and Coordinates match
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #     bit        : Direction converted to Obstacle Bit
  #     event      : Iterated Event made by make_map_passable_list
  #     self_event : Character calling $game_map.passable
  #     result     : true or false passed as an arg by Aliases
  #--------------------------------------------------------------------------
  def map_passable_conditions?(x,y,d,bit,event,self_event = nil, result = nil)
    # If an Alias has declared a result, use the Alias result instead
    return result if not result.nil?
    # Standard Conditions for checking Event Tiles
    if event.x == x and event.y == y and
       not event.through and event != self_event and
      # Check this Event Tile
      return true
    end
    # Default
    return false
  end
  #--------------------------------------------------------------------------
  # * Event Tile Not Passable? - Game_Map
  #   - If an Event has a Tile and isnt Through, passage determined by bits
  #   - Inverse Logic: -1 * -1 = 1
  #   - Returns TRUE if a Tile is Not Passable
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #                  10 is used for Jumping
  #     bit        : obstacle bit for specific direction passage
  #     event      : iteration of each event in all events to be checked
  #     self_event : Self (If event is determined passable)
  #     result     : true or false passed as an arg by Aliases 
  #--------------------------------------------------------------------------
  def event_tile_not_passable?(x,y,d,bit,event,self_event = nil, result = nil)
    # If an Alias has another result, use it
    return result if not result.nil?
    # If obstacle bit is set for that direction
    if @passages[event.tile_id] & bit != 0
      # Impassable - True is used to say this is NOT Passable
      return true
    # If obstacle bit is set in all directions
    elsif @passages[event.tile_id] & 0x0f == 0x0f
      # Impassable - True is used to say this is NOT Passable
      return true
    end   
  end 
  #--------------------------------------------------------------------------
  # * Event Tile Passable? - Game_Map
  #   - Non Through Events with Passable Non Priority Tiles are Passable
  #   - Returns TRUE if a Tile is Passable
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #                  10 is used for Jumping
  #     bit        : obstacle bit for specific direction passage
  #     event      : iteration of each event in all events to be checked
  #     self_event : Character calling $game_map.passable
  #     result     : true or false passed as an arg by Aliases   
  #--------------------------------------------------------------------------
  def event_tile_passable?(x, y, d, bit, event, self_event = nil, result = nil)
    # If an Alias has another result, use it
    return result if not result.nil?     
    # If Event has a Tile with no Priority
    if @priorities[event.tile_id] == 0
      # Passable
      return true
    end   
  end 
  #--------------------------------------------------------------------------
  # * Tile Not Passable? - Game_Map
  #   - Returns TRUE if a Map Tile is Not Passable due to bits
  #   - Inverse Logic: -1 * -1 = 1 
  #   - Returns true when Not Passable
  #   - Must return False or Nil to allow for Movement, other checks made
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #                  10 is used for Jumping
  #     bit        : obstacle bit for specific direction passage
  #     tile_id    : ID of each Tile that is being checked for Passage
  #     self_event : Character calling $game_map.passable
  #     result     : true or false passed as an arg by Aliases
  #--------------------------------------------------------------------------
  def tile_not_passable?(x, y, d, bit, tile_id, self_event = nil, result = nil)
    # If an Alias has another result, use it
    return result if not result.nil?
    # Tile ID acquistion failure
    if tile_id == nil
      # Impassable
      return true
    # If obstacle bit is set
    elsif @passages[tile_id] & bit != 0
      # Impassable - True is used to say Tile is NOT Passable
      return true
    # If obstacle bit is set in all directions
    elsif @passages[tile_id] & 0x0f == 0x0f
      # Impassable - True is used to say Tile is NOT Passable
      return true
    end
  end
  #--------------------------------------------------------------------------
  # * Tile Passable? - Game_Map
  #   - Returns TRUE if a Map Tile is Passable and skips next conditions
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #                  10 is used for Jumping
  #     bit        : obstacle bit for specific direction passage
  #     tile_id    : ID of each Tile that is being checked for Passage
  #     self_event : Character calling $game_map.passable
  #     result     : true or false passed as an arg by Aliases 
  #--------------------------------------------------------------------------
  def tile_passable?(x, y, d, bit, tile_id, self_event=nil, result=nil)
    # If an Alias has another result, use it
    return result if not result.nil?
    # If priorities other than not passable that are 0
    if @priorities[tile_id] == 0
      # Passable
      return true
    end
  end
  #--------------------------------------------------------------------------
  # * Passable? - Game_Map
  #
  #      ***  DO NOT OVERWRITE THIS METHOD  ***
  #            (aliases are fine however)
  #
  #  - Determines if New Location is passable based on Tiles and Event Tiles.
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #     self_event : Self (If event is determined passable)
  #  - This only checks for Tiles and Events with Tiles to determine if
  #    a location is passable.  Character Collisions are determined in
  #    another method, Game_Character Passable, not here.
  #  - The List of Events to check can be altered with Aliases instead
  #    of any need to replace this method, usually
  #--------------------------------------------------------------------------
  def passable?(x, y, d, self_event = nil)
    # If coordinates given are outside of the map
    unless valid?(x, y, d, self_event)
      # impassable
      return false
    end
    # Change direction (0,2,4,6,8,10) to obstacle bit (0,1,2,4,8,0) with Method
    bit = make_bit(x, y, d, self_event)
    # Create a List of Events to check on Map for Passable
    event_list = make_map_passable_list(x, y, d, bit, self_event)
    # Iterate each Event in the Event List
    for event in event_list
      # If Conditions indicate Event needs to be Checked (Location Match)
      if map_passable_conditions?(x, y, d, bit, event, self_event)
        # If Event Tile Not Passable returns True, then Event is Not Passable
        if event_tile_not_passable?(x, y, d, bit, event, self_event)
          # Impassable
          return false
        # If Event Tile Passable returns True, then Event is Passable
        elsif event_tile_passable?(x, y, d, bit, event, self_event)
          # Passable
          return true
        end
      end
    end
    # Loop searches in order from top of layer
    for i in [2, 1, 0]
      # Get tile ID
      tile_id = data[x, y, i]
      # If Tile Not Passable returns True, then Tile is Not Passable
      if tile_not_passable?(x, y, d, bit, tile_id, self_event)
        # Impassable
        return false
      # If Tile Passable returns True, then Tile is Passable
      elsif tile_passable?(x, y, d, bit, tile_id, self_event)
        # Passable
        return true
      end
    end
    # passable
    return true
  end
end

#==============================================================================
# ** Game_Character
#==============================================================================
class Game_Character
  #--------------------------------------------------------------------------
  # * Make New XY - Game_Character
  #  - Makes New Coordinates for X and Y (4 Directional Movement)
  #     x      : x-coordinate
  #     y      : y-coordinate
  #     d      : direction (0,2,4,6,8)
  #     result : Array passed as an arg by Aliases
  #
  #  NOTE: Must return an Array of New Map Coordinates [new_x, new_y]
  #    new_x, new_y = make_new_xy(x, y, d) 
  #  - This can be Aliased to alter New Coordinates based on other conditions
  #--------------------------------------------------------------------------
  def make_new_xy(x, y, d, result = nil)
    # If an Alias has another result, use it (Should return 2 values in Array)
    return result if not result.nil?     
    # Get new coordinates for four directional movement
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    # return array of New Coordinates
    return [new_x, new_y]
  end
  #--------------------------------------------------------------------------
  # * Make New XY 8D - Game_Character
  #  - Make New Coordinates for X and Y (8 Directional Movement)
  #     x     : x-coordinate
  #     y     : y-coordinate
  #     d     : direction (0,1,2,3,4,6,7,8,9 no 5)
  #     result : Array passed as an arg by Aliases   
  #  - This method is not called, but is available if needed
  #
  #  Note: Bit Flipping with 10 - d works, 10 - 9 (up right) = 1 (down left)
  #  Note: Must return an Array of New Map Coordinates [new_x, new_y]
  #    new_x, new_y = make_new_xy_8d(x, y, d)
  #--------------------------------------------------------------------------
  def make_new_xy_8d(x, y, d, result = nil)
    # If an Alias has another result, use it (Should return 2 values in Array)
    return result if not result.nil?
    # Get new coordinates for Eight Directional movement   
    new_x = x + ([9, 6, 3].include?(d) ? 1 : [7, 4, 1].include?(d) ? -1 : 0)
    new_y = y + ([1, 2, 3].include?(d) ? 1 : [7, 8, 9].include?(d) ? -1 : 0)
    return [new_x, new_y]
  end
  #--------------------------------------------------------------------------
  # * Event Not Passable? - Game_Character
  #  - Events can NOT move through another Event unless one is flagged Through
  #  - Player is allowed to move through Events, other checks performed later
  #  - Inverse Logic: -1 * -1 = 1
  #  - Returns true when Not Passable
  #  - Must return False or Nil to allow for Movement
  #     x      : x-coordinate
  #     y      : y-coordinate
  #     d      : direction (0,2,4,6,8)
  #             * 0 = Determines if all directions are impassable (for jumping)
  #     new_x  : Target X Coordinate
  #     new_y  : Target Y Coordinate
  #     event  : Event being checked against in iteration loop
  #     result : true or false passed as an arg by Aliases
  #--------------------------------------------------------------------------
  def event_not_passable?(x, y, d, new_x, new_y, event, result = nil)
    # If an Alias has another result, use it
    return result if not result.nil?
    # If Character doing the Passable check is an Event, not a Player
    if self != $game_player
      # Impassable - TRUE that Events are Not Passable through another Event
      return true
    end
  end
  #--------------------------------------------------------------------------
  # * Event Character Not Passable? - Game_Character
  #  - No Character (Events or Player) can move through any Event that has
  #    a Character Graphic, unless one of them is flagged Through
  #  - Inverse Logic: -1 * -1 = 1
  #  - Returns true when Not Passable
  #  - Must return False or Nil to allow for Movement
  #     x     : x-coordinate
  #     y     : y-coordinate
  #     d     : direction (0,2,4,6,8)
  #             * 0 = Determines if all directions are impassable (for jumping)
  #     new_x : Target X Coordinate
  #     new_y : Target Y Coordinate
  #     event : Event being checked against in iteration loop
  #     result : true or false passed as an arg by Aliases 
  #--------------------------------------------------------------------------
  def event_character_not_passable?(x, y, d, new_x, new_y, event, result = nil)
    # If an Alias has another result, use it
    return result if not result.nil?   
    # If this Event has a Character Graphic
    if event.character_name != ""
      # Impassable - TRUE that Event checked has a Character Graphic
      return true
    end
  end
  #--------------------------------------------------------------------------
  # * Other Passable? - Game_Character
  #  - This check is performed prior to Event Iteration for Performance
  #  - MUST return True to allow for Movement
  #     x     : x-coordinate
  #     y     : y-coordinate
  #     d     : direction (0,2,4,6,8)
  #             * 0 = Determines if all directions are impassable (for jumping)
  #     new_x : Target X Coordinate
  #     new_y : Target Y Coordinate
  #     result : true or false passed as an arg by Aliases   
  #-------------------------------------------------------------------------- 
  def other_passable?(x, y, d, new_x, new_y, result = nil)
    # If an Alias has another result, use it
    return result if not result.nil?     
    # Passable - Default
    return true
  end
  #--------------------------------------------------------------------------
  # * Make Passable List - Game_Character
  #  - Returns an Array or Hash of Events for Iteration 
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #     new_x : Target X Coordinate
  #     new_y : Target Y Coordinate 
  #     results    : MUST be an Array of Events if used
  #  NOTE: results is Plural, not singular
  #  NOTE: MUST return an Array of Events
  #--------------------------------------------------------------------------
  def make_passable_list(x, y, d, new_x, new_y, results = nil)
    # If an Alias has declared an Hash of Events, use the Alias result instead
    return results if not results.nil?
    # Return All Event Values in Game Map Hash
    return $game_map.events.values
  end
  #--------------------------------------------------------------------------
  # * Make Events List - Game_Character
  #  - Similar to Make Passable List
  #  - Intended for use in Non Passable determining methods in other Scripts
  #  - Intended to be aliased where X and Y values can be adjusted as needed
  #  - Excludes other Arguments needed by Make Passable List
  #  - Used by other Scripts with Triggers when X or Y have no arguments to fix
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     results    :
  #--------------------------------------------------------------------------
  def make_events_list(x, y, results = nil)
    # If an Alias has declared an Hash of Events, use the Alias result instead
    return results if not results.nil?   
    # Return All Event Values in Game Map Hash
    return $game_map.events.values   
  end
  #--------------------------------------------------------------------------
  # * Passable Conditions? - Game_Character
  #  - Return true / false if conditions met
  #  - Conditions for running Passability Checks on an Event
  #  - Typically an Event isnt checking itself, Through, and Coordinates match
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #     new_x      : Target X Coordinate
  #     new_y      : Target Y Coordinate 
  #     event      : Iterated Event made by make_passable_list 
  #     result     : values other than nil by Aliases override checks here
  #--------------------------------------------------------------------------
  def passable_conditions?(x, y, d, new_x, new_y, event, result = nil)
    # If an Alias has declared a result, use the Alias result instead
    return result if not result.nil?
    # Standard Conditions for checking Event Tiles
    if event.x == new_x and event.y == new_y and
       not event.through and event != self
      # Check this Event
      return true
    end
  end
  #--------------------------------------------------------------------------
  # * Match Coordinates? - Game_Character
  #  - Modular Passable mp_
  #  - Can be Aliased to alter Argument Values prior to comparison
  #  - Used by Heretic's Loop Maps to correct Values
  #--------------------------------------------------------------------------
  def mp_match_coordinates?(x, y, tx, ty)
    # If Argument Coordinates Match
    return true if x == tx and y == ty
  end
  #--------------------------------------------------------------------------
  # * Player Conditions? - Game_Character
  #  - Return true / false if conditions met
  #  - If New Location matches Player Position and Player not Through
  #     x          : x-coordinate
  #     y          : y-coordinate
  #     d          : direction (0,2,4,6,8,10)
  #                  *  0,10 = determine if all directions are impassable
  #     new_x : Target X Coordinate
  #     new_y : Target Y Coordinate 
  #     result     : values other than nil by Aliases override checks here
  #-------------------------------------------------------------------------- 
  def player_conditions?(x, y, d, new_x, new_y, result = nil)
    # If an Alias has declared a result, use the Alias result instead
    return result if not result.nil?
    # If Coordinates match Player Location and Player Through is Off
    if $game_player.x == new_x and $game_player.y == new_y and
       not $game_player.through
      # Conditions are met
      return true
    end
  end
  #--------------------------------------------------------------------------
  # * Event Player Not Passable? - Game_Character
  #  - Checks for Events with Character Graphics trying to move to the
  #    current Location of the Game Player
  #  - Inverse Logic: -1 * -1 = 1
  #  - Returns true when Not Passable
  #  - Must return False or Nil to allow for Movement 
  #     x     : x-coordinate
  #     y     : y-coordinate
  #     d     : direction (0,2,4,6,8)
  #             * 0 = Determines if all directions are impassable (for jumping)
  #     new_x : Target X Coordinate
  #     new_y : Target Y Coordinate
  #     result : true or false passed as an arg by Aliases   
  #-------------------------------------------------------------------------- 
  def event_player_not_passable?(x, y, d, new_x, new_y, result = nil)
    # If an Alias has another result, use it
    return result if not result.nil?
    # If this Event has a Character Graphic
    if @character_name != ""
      # Impassable - This Event with Graphic trying to move to Players Location
      return true
    end
  end 
  #--------------------------------------------------------------------------
  # * Passable? - Game_Character
  #
  #      ***  DO NOT OVERWRITE THIS METHOD  ***
  #            (aliases are fine however)
  #
  #  - Checks for Character Collisions to determine if Passable
  #     x : x-coordinate
  #     y : y-coordinate
  #     d : direction (0,2,4,6,8)
  #         * 0 = Determines if all directions are impassable (for jumping)
  #--------------------------------------------------------------------------
  def passable?(x, y, d)
    # Generate new X and Y coordinates
    new_x, new_y = make_new_xy(x, y, d)
    # If coordinates are outside of map
    unless $game_map.valid?(new_x, new_y, d, self)
      # Impassable
      return false
    end
    # If through is ON
    if @through
      # Passable
      return true
    end
    # If unable to leave first move tile in designated direction
    unless $game_map.passable?(x, y, d, self)
      # Impassable
      return false
    end
    # If unable to enter move tile in designated direction
    unless $game_map.passable?(new_x, new_y, 10 - d, self)
      # Impassable
      return false
    end
    # If unable to move for any other reason (alias this method)
    unless other_passable?(x, y, d, new_x, new_y)
      # Impassable
      return false
    end
    # Generate a List of Map Events to loop through
    event_list = make_passable_list(x, y, d, new_x, new_y)
    # Loop Events in List (typically ALL Game Map Event Values)
    for event in event_list
      # If conditions are met to check the event for passable
      if passable_conditions?(x, y, d, new_x, new_y, event)
        # If Event has Conditions that prohibit passage
        if event_not_passable?(x, y, d, new_x, new_y, event)
          # Impassable
          return false
        # If Character has Conditions that prohibit passage
        elsif event_character_not_passable?(x, y, d, new_x, new_y, event)
          # Impassable
          return false
        end
      end
    end
    # If Player is at or moving to Location this Event trying to move to
    if player_conditions?(x, y, d, new_x, new_y)
      # If Event not allowed to move to Players Location
      if event_player_not_passable?(x, y, d, new_x, new_y)
        # Impassable - Typically Event has a Character Graphic
        return false
      end
    end
    # Passable
    return true
  end
end

#==============================================================================
# ** Game_Player
#==============================================================================
class Game_Player < Game_Character
  #--------------------------------------------------------------------------
  # * Passable Determinants - Game_Player
  #     x : x-coordinate
  #     y : y-coordinate
  #     d : direction (0,2,4,6,8)
  #         * 0 = Determines if all directions are impassable (for jumping)
  #--------------------------------------------------------------------------
  def passable?(x, y, d)
    # Generate new X and Y coordinates
    new_x, new_y = make_new_xy(x, y, d)
    # If coordinates are outside of map
    unless $game_map.valid?(new_x, new_y)
      # Impassable
      return false
    end
    # If debug mode is ON and ctrl key was pressed
    if $DEBUG and Input.press?(Input::CTRL)
      # Passable
      return true
    end
    super
  end
end

#==============================================================================
# ** Game_Event
#==============================================================================
class Game_Event < Game_Character
  #--------------------------------------------------------------------------
  # * Check Comment Page Config - Game_Event
  #     comment : the Comment to be checked to adjust Page Properties
  #     count   : integer of which List of Event Commands is checked
  #
  #  - This is intended to be Aliased to prevent Iterations of each Comment
  #  - Each Comment can be scanned for specific strings of characters
  #  - Counter can be adjusted if you have a need to use more than one line
  #  - Comment Limit (Constant) is used to prevent scanning after Limit Reached
  #  - Count allows access to all Event Commands @page.list[count]
  # 
  #   Example 1: Set a TRUE Option if the string \option is the comment
  #     comment.gsub(/\\option/i){@option = true; return count}   
  #   Example 2: Set a Numeric Value to the Option \option[123]
  #     comment.gsub(/^\\option\[([0-9]+)/z\]/i) {@option = $1.to_i;
  #       return count}
  #
  #   Note: Proper Aliasing will still allow Non Comment Commands to be checked
  #         by checking the count argument passed.  Code 108 is the First Line
  #         of a Comment.  Code 408 is any Next Line of a Comment.  Next Lines
  #         do count against COMMENT_LIMIT.
  #
  #         if @page.list[count + 1].parameters.code == 408
  #           # Advance count for other Aliases
  #           count += 1
  #           # How to access a Comment on the Next Line
  #           your_command = @page.list[count].parameters[0]
  #           # Do your Script Checks here
  #         end
  #         # Return count of Original or other Aliases and pass Args
  #         return alias_of_check_page_comment_config(comment, count)
  #
  #   Note: When aliasing, please return the value of aliased methods for
  #         the local variable count to be altered as needed.
  #--------------------------------------------------------------------------
  def check_page_comment_config(comment, count)
    # Looks for "\comment_limit[N]" Comments to Override Comment Limit Constant
    comment.gsub(/^\\comment_limit\[([-0-9]+)\]\z/i){@comment_limit = $1.to_i;
      return count;}
    # Return adjusted or unadjusted counter
    return count
  end
  #--------------------------------------------------------------------------
  # * Reset Page Comment Config - Game_Event
  #  - Use this to Reset Varaibles that are set by Comment Configuration
  #  - If you have an Option that you want to be different on each Page, then
  #    clear those values here so they can be checked again instead of
  #    sticking around on different pages when you dont want them.
  #  - @option = nil or your Default Value
  #--------------------------------------------------------------------------
  def reset_page_comment_config
    # Reset Comment Limit Overrides
    @comment_limit = nil
    # Reset any Page Comment Configuration Variables here
    return true
  end
  #--------------------------------------------------------------------------
  # * Comment Limit? - Game_Event
  #  - Returns true / false if comment limit reached
  #  - Override Constant per Event Page with a \comment_limit[20] Comment
  #--------------------------------------------------------------------------
  def comment_limit?(count)
    return (count > @comment_limit) if not @comment_limit.nil?
    return (count > COMMENT_LIMIT)
  end
  #--------------------------------------------------------------------------
  # * Refresh - Game_Event
  #   - Checks for Tile IDs and updates smaller $game_map.event_tiles hash
  #   - Aliasable Methods used to Reset and Scan for Comment Configs
  #  Note: Config Comments are ONLY checked on a Page Change
  #--------------------------------------------------------------------------
  alias tile_event_and_comment_refresh refresh unless $@
  def refresh
    # Initial State of current @page before Refresh
    page = @page
    # Call Original or Other Aliases of Refresh
    tile_event_and_comment_refresh
    # If Valid Tile ID and Not Erased (Call after Refresh method)
    if @tile_id > 0 and not @erased
      # Store Event with Tile ID
      $game_map.event_tiles[@id] = self
    else
      # Remove Events without Tile ID from small Hash
      $game_map.event_tiles.delete(@id)
    end
    # If Event Not Erased
    unless @erased
      # If Page is not Nil (Page Conditions) and Page Change is occuring
      if not @page.nil? and @page != page
        # Reset to set again by Comment Conditions (@option = nil)
        reset_page_comment_config
        # For Performance on checking each Command in Page List when Refreshed
        count = 0
        # For each Event Command as 'command' in Page List of Event Commands
        @page.list.each {|command|
          # If Command Code is a Comment (Code 108, 408 is Next Line Code)
          if command.code == 108
            # Check Comment for Configuration Values and adjust Counter
            count = check_page_comment_config(command.parameters[0], count)
          end
          # Increment Counter
          count += 1
          # Stop Iterating after Limit reached
          break if comment_limit?(count)
        }  # End |command| loop (Event Command List)
      end
    end
  end
end

# Version of Modular Passable for dependant scripts to check.  DO NOT EDIT
$Modular_Passable = 1.0



Instructions

See the Script.


Compatibility

Zero known compatability issues at this time.

This script is not designed to work with Pixel Movement Scripts.

It is designed to handle Eight Directional Input.


Credits and Thanks




Author's Notes

Please post ONLY in relation to Modular Passable itself in this thread. 

Any of the other supported scripts will have their own thread.  Ask questions or report bugs in the appropriate threads.
Title: Re: [XP] Heretic's Modular Passable XP
Post by: Sylphe on May 01, 2015, 07:10:10 pm
This is a fantastic bundle of scripts *o* great job !

However I tried to use the MMW of your demo in my game but I experience a "bug" that appears at the very end of my first event, here is the error :
Spoiler: ShowHide
(http://i.imgur.com/3bovk9X.png?1)

At the end of my event I show a simple message (that is shown in game) then I activate the local switch A to stop the event and at this moment I get this error.

Even when I disable the "sticky" option the error shows.

I actually have  RTP scripts, Modular passable (last version) and collision optimizer and those scripts (you can also see the line of the error in the screenshot) :
Spoiler: ShowHide
(http://i.imgur.com/qeDXYdh.png?1)


and

Spoiler: ShowHide
(http://i.imgur.com/9waz6k9.png?1)


... I also scripted "set_max_dist(1)" at the top of the event but I keep the error :/
Any Idea what could cause it ? ^^ (the only thing that rewrite Game_Player < Game_Character in my scripts are yours lol)
Title: Re: [XP] Heretic's Modular Passable XP
Post by: Heretic86 on May 01, 2015, 07:38:18 pm
This is MMW related, not Modular Passable related.  But lets fix it anyway.

First thing I noticed is that you have Blizz ABS.  There is a version of MMW that is designed to be compatible with Blizz ABS and you could try using that version.  Im not very familiar with that version or the ABS, and Im also not sure if it has any of the features I put in.  But for using Blizz ABS, I'd recommend looking up MMW Ex, I think its called, instead of the version I put up.  They arent terribly different, but expect other bugs to pop up.

Try this, move attr_accessor :sticky from class Game_Player to class Game_Character.  I'd still expect other bugs tho...

Seems to me this is possibly related to an inheritance issue, probably coded wrong, by me, where an alias made of a super class, which would probably be bad juju on my part.  I might have to take a peek at your project...
Title: Re: [XP] Heretic's Modular Passable XP
Post by: Sylphe on May 01, 2015, 08:01:02 pm
Oooow ok I'm sorry ! I didn't see there was the same thing B-ABS compatible ._. thank you
At first I saw you're hotfoot script and I didn't understand what was hotfoot even when reading your post xD (surely because I'm french)
So I downloaded your "modular passable" demo so I thought it was ok to post my request here ^^
Well if I'm interested in MMW it is mainly for the "You can move while I'm talking" thing xD and my custom message system don't allow me to write a "(" in a message lol.
That's why MMW Ex fit me also ^^
(and you're right, putting the accessor in game_character fixed the bug, but another error appeared in my next event - Endless circle - I think I will use MMW Ex...)

Don't forget B-ABS in your compatibility section :p
Title: Re: [XP] Heretic's Modular Passable XP
Post by: KK20 on May 01, 2015, 08:10:36 pm
Quote from: Sylphe on May 01, 2015, 08:01:02 pm
At first I saw you're hotfoot script and I didn't understand what was hotfoot even when reading your post xD

To which I suggest you put animated GIFs as your screenshots for some of your scripts, Heretic. LICEcap is a good enough free software for this task.
Title: Re: [XP] Heretic's Modular Passable XP
Post by: Heretic86 on May 01, 2015, 08:50:34 pm
Quote from: KK20 on May 01, 2015, 08:10:36 pm
Quote from: Sylphe on May 01, 2015, 08:01:02 pm
At first I saw you're hotfoot script and I didn't understand what was hotfoot even when reading your post xD

To which I suggest you put animated GIFs as your screenshots for some of your scripts, Heretic. LICEcap is a good enough free software for this task.


Good call.  I'll post this in the Hotfoot Tiles thread...

(http://downloads.chaos-project.com/heretic86/images/hotfoot_anime.gif)