[XP] Heretic's Restrict Tile Passage

Started by Heretic86, April 29, 2015, 08:04:03 pm

Previous topic - Next topic

Heretic86

April 29, 2015, 08:04:03 pm Last Edit: April 29, 2015, 10:49:43 pm by Heretic86
Restrict Tile Passage XP
Authors: Heretic
Version: 1.0
Type: Custom Movement System
Key Term: Custom Movement System



Introduction

This script will allow you to nearly fully control where Characters, both NPC Events and the Player can and can not move without changing Tileset Passages!  This is the CORE Script of what allows Heretic's Vehicles to move on Impassable Water Tiles.  Another very useful feature is that you can constrain an NPC Event to only move on certain Tile IDs, so you have NPCs that stay on a Road Tile while still allowing the Player the ability to walk off of the same Road Tile.


Features


  • Allows almost Total Control over where an NPC can move

  • Uses Simplified Tile IDs

  • Can make NPCs move on Impassable Tiles

  • Can make NPCs move through ALL Events and restrict by Tiles

  • Very useful for restricting Random Movements

  • Events configured Per Page

  • I like Gummy Bears and Swedish Fish, yeah, thats a Feature!

  • Fully Compatible with other Modular Passable Scripts I wrote

  • ** REQUIRED by Heretic's Vehicles XP Script




Screenshots

Spoiler: ShowHide


There are three NPCs that are set to move Randomly, and will be forced to always stay on this Road Tile.  Some stuff is hard to see.  Butterflies to the left can only move on the Flower Tiles that is Impassable to the Player and other NPCs.  There are Fish in the water that also move at Random and will always stay in the water.  There is a lot going on in this screenshot.



Demo

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

NOTE: The Demo contains several Modular Passable scripts.


Script

Place below Modular Passable (Required)
Place below Collision Optimizer (Optional)
Place below Loop Maps (Optional)

Spoiler: ShowHide
#=============================================================================
#
#           HERETIC'S RESTRICT TILE PASSAGE [XP]
#           Version 1.0
#           Tuesday, October 21st, 2014
#
#=============================================================================
#
# ---  Requirements and Installation  ---
#
# *** REQUIRES HERETICS MODULAR PASSABLE SCRIPT ***
#
# Place this Script below Heretic's Modular Passable Script and above Main.
#
#
# ---  Features  ---
#
# - Allows almost Total Control over where an NPC can move
# - Uses Simplified Tile IDs
# - Can make NPCs move on Impassable Tiles
# - Can make NPCs move through ALL Events and restrict by Tiles
# - Very useful for restricting Random Movements
# - Events configured Per Page
# - I like Gummy Bears and Swedish Fish, yeah, thats a Feature!
# - Fully Compatible with other Modular Passable Scripts I wrote
#
#
# ---  Overview  ---
#
#  This script is intended to help you keep your Characters exactly where
#  you want them by controlling passage based on simplified Tile IDs.  NPC's
#  with Random Movement may move where you don't want them to.  This offers
#  a way to control where they move.  It also allows Characters to move
#  about Randomly on normally Impassable tiles, which is useful for
#  fish.  NPC's can be made to ignore Collisions with other Events and
#  Characters while still controlling their movement with Tiles.  It will
#  allow you to prevent a Butterfly from moving through a Mountain or Wall
#  while not interfering with Movement of other Characters.
#
# Place the following Comments withing the first 10 or so Lines on
# each Event Page you wish to control movement based on Bush.
#
# \tile_allow_move[9]     - Causes an Impassable Tile to be Passable to NPC
# \tile_no_move[4]        - Event will NOT move on these Tile IDs
# \tile_only_move[1,2]    - Event can ONLY move around on these Tile IDs
# \event_through          - Through Events but still restriced by Tile
# \no_event_tiles         - Events won't try to move through Events with Tiles
# \no_through_event_tiles - Overrides \event_through, check Event Tile Passages
#
#
# The Configuration Comments allow Multiple Tiles to be specified!  Just put
# a comma between each Tile ID!  This allows you to specify ONE or MANY Tiles
# to control movement.  
#
# \tile_allow_move[5, 19] can move on Tiles 5 and 19 even if Impassable!
# \tile_no_move[3] won't be able to move to Autotile 3.
# \tile_no_move[5,6, 7,13] won't move to Autotiles 5, 6, or 7 or Tile 13.
# \no_event_tiles won't move through ANY Event Tiles unless Through
#
# \event_through          - Allows an Event to move through other Events and
#                           the Player, but will still be restricted by any
#                           Tile Passages.  Very useful for Butterflies,
#                           Fish,  Mice, small Insects and Bugs, very small
#                           NPC's and other Wildlife where Collision is not
#                           expected, but Tiles should still constrain
#                           movement to Tile Passages.
# \no_through_event_tiles - Use this with \event_through to make an NPC
#                           check the passages of an Event Tile.  It still
#                           allows Through of other Characters, Player, and
#                           Non Tile Events.
#
# Event_Through and No Event Tiles have no parameters to configure.
#
# NOTE: All ID's must fit on ONE LINE of a Comment!  Do NOT put spaces
#       or any additional characters after your Comment configuration!
#
#
# ---  Simplified Tile IDs  ----
#
# The real Tile ID's are a pain to work with, so I simplified them for you!
#
# Eraser Tile is Tile 0, the one in the upper left hand corner of the palette.
#
# Autotiles are 1 thru 7 from Left to Right.
#
# Tiles that come from your Tileset start at 8 in the upper left hand corner
# of your Tileset below the Autotile row and increment up from there from
# the left to the right.
#
#    ** Simplified Tile ID Map **
#
#    0  1  2  3  4  5  6  7 - Autotiles and Eraser (0)
#    8  9 10 11 12 13 14 15 - Tileset Tiles
#   16 17 18 19 20 21 22 23
#   24 25 26 27 28 29 30 31
#   etc...
#
#
# If you need to find a Tile ID, don't bother counting, especially on larger
# tilesets.  I made this super easy for you!  Just put an Event on the Tile
# you want to find out the simplified Tile ID for and run a Script:
#
# @>Script: rtp_tile_info
#
# The Information that pops up should be highly useful.  It details all three
# of the Tile Layers and gives you information about each Tile on each Layer.
#
# NOTE: Simplified Tile IDs are NOT the Real Tile ID's!  Don't mix them up!
#
# If you just want the Simlified Tile ID from an Event, easy peesy!
#
# @>Script: p $game_map.events[13].simple_tile_id  (p is a shortcut for print)
#
# If you run out of space, you can do it like this too:
#
# @>Script: e = $game_map.events[443]
#           print e.simple_tile_id
#
#
# ---  Passage  ---
#
# Through will still allow unrestricted passage anywhere on the map.
#
# Collisions with other events are still checked unless \event_through Comment.
#
# Events will also move through any Events with Tile Graphics UNRESTRICTED if
# the target Event Tile matches any \tile Tiles!  If you want to prevent
# this behavior, add a \no_event_tiles Comment.  Alternatively, if you also
# have my NPCs on Event Tiles script, you can put a \deny_npc Comment on
# the Event with the Tile.  NPCs on Event Tiles controls the Events with
# any Tile Graphics.  This script adds controls from the NPC side of things.
# NPCs on Event Tiles will apply the Passages of the Tiles to the NPC, which
# this script does not do.  They are perfectly compatible and work well
# when used together.
#
# With a \tile_no_move[tile_id] Comment, an Event will have normal movement
# EXCEPT for the Tile IDs you specify.  This can be useful for NPC's that
# wander around if you want them to stay off of Grass.  You could also give
# wildlife a \tile_no_move[tile_id] to keep them off Paths.  The Passage
# settings for that Tile do NOT need to be altered in the Database.
#
# A \tile_allow_move[N,N] also makes IMPASSABLE TILES PASSABLE and only
# for that Event!  This is useful when you want to remove some restrictions
# from where that Event can go, but want most other limitations.  This is
# intended for normalizing random movement, like keeping fish in ponds.
#
# You can use Priority Tiles for both \tile_allow_move and \tile_no_move
#
# You can NOT use a Priority tile to constrain a \tile_only_move Event.
#
# With a \tile_only_move[tile_id] Comment, an Event will ONLY move on Tiles
# with the Tile ID's you specify.  Everywhere else is prohibited.  This means
# you should be very careful with Detail Tiles as they will block passage.
# Priority Tiles do not affect Passage.  You should ONLY put NON Priority
# Tiles in \tile_only_move as Priority Tiles are excluded due to the need
# to work appropriately with other Layers.
#
# Any \tile_only_move Tile ID's will AUTOMATICALLY become PASSABLE for that
# Event!  This means you can make normally IMPASSABLE TILES PASSABLE, but
# only for that Event!  You do NOT need to make any changes to the Passage
# settings of your Tiles in the Database!  Detail Tiles that cover any
# of an Event's \tile_only_tiles WILL cause Impassable, so watch those
# Detail Tiles (Tiles with a 0 Priority).
#
# This is an easy way to create moving Fish that stay in Deep Water!  A Deep
# Water Autotile will be Impassable but will be FULLY PASSABLE for the Fish!
# If you set the Movement Type to Random, the Fish will wander around only
# on that particular Deep Water Tile!  If you give the Fish TWO Tile IDs, they
# will now be able to wander on Shallow and Deep Water Tiles!
#
# For Fish, if you use Ponds, the Edges of the Pond will also be Passable
# to the Fish.  The solution to this is to give yourself TWO Blank Tiles
# in your Tileset.  Make one of the Tiles fully passable, and the other
# impassable.  Don't give either Tile a Priority.  For Pond edges, use
# the Impassable Tile and simply paint that tile around the edge
# of the Pond.  The Impassable Tile keeps the Player off of the edge, and
# the fish away from the edge because it is not an included in the Tile IDs
# you specify in \tile_only_move[tile_id, tile_id].  Best of both worlds.
#
# ---  Stairs & Ice ---
#
# If you have my Diagonal Stairs Deluxe script installed in your game, Events
# with a \event_through Comment will still be affected by Event Stairs. If
# you want to prevent Stair Behavior for an Event with Through set to OFF
# and an \event_through Comment, just add a \no_stairs Comment to prevent
# your Event from interacting with Event Stairs.  For Ice behavior, simply
# do NOT give your Event an \ice Comment.
#
# ---  Version History  ---
#
# Version 1.0 - Tuesday, October 21st, 2014 - Initial Release
#
# ---  System Options  ---
#
# There are no configurable system options for this script.  All settings are
# controlled in Comments Per Event and Per Page.
#
#
#=============================================================================

# Check for Modular Passable Script - REQUIRED - DO NOT EDIT
unless $Modular_Passable
 print "Fatal Error: Heretics Restrict Tile Movement script\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 will now Exit"
 exit
end

#============================================================================
# ** Game_Map
#============================================================================
class Game_Map
 #--------------------------------------------------------------------------
 # * RTP Tile Info - Game_Map
 #     x     : x-coordinate
 #     y     : y-coordinate
 #     event : Map Event
 #  - DEVELOPMENT TOOL
 #  - Call from an Event -> Script: rtp_tile_info
 #  - Called by Interpreter Script in a Map Event, not used otherwise
 #  - Displays Simple Tile ID, Terrain Tag, Bush, Counter and Hotfoot
 #    settings for All Layers, and Map Passages for All Tiles at once
 #  - Checks for possible Terrain Tag Conflicts and other useful Data
 #--------------------------------------------------------------------------  
 def rtp_tile_info(x, y, event)
   # Check for Debug
   return unless $DEBUG
   # Tile Information
   info = []
   # Loop searches in order from top of layer
   for i in [2, 1, 0]
     # Get tile ID
     tile_id = data[x, y, i]
     # Store Tile Information in Array and check for nil
     info[i] = (tile_id) ? tile_id : 0
   end
   # Message to be displayed
   tile_msg = "Tile Information for Event ", event.id,
              " at X: ", event.x, " Y: ", event.y, "\n"
   tile_msg = tile_msg, "Tileset ID:", tileset_id, "\n\n"
   # Terrain Tag Conflict Checker (Default)
   tt = false
   # Last Non Priority Layer (Placeholder)
   lnpl = 0
   # Generate Message to be Printed for User
   for i in [3, 2, 1]
     # Recorded Tile in Layer Data
     tile_id = info[i - 1]
     # Setup Text and Simplified Tile ID
     simple_id = simplify_tile_id(tile_id)
     auto_msg = (simple_id < 8) ? " (Autotile)" : ""
     np_found = nil
     # Add this Text to the Message
     tile_msg = tile_msg, "LAYER ", i, "\t\t     Tile Passages"
     # If Tile Exists
     if tile_id > 0
       # Grab existing Terrain Tags to check for Terrain Tag Conflict
       ttc = true if @terrain_tags[tile_id] > 0 and tt
       # Store if a Terrain Tag is already set
       tt = true if @terrain_tags[tile_id] > 0
       # Map Bit Passages for Tiles (Bitwise Operations)
       up = (@passages[tile_id]&((1<<(8/2-1))&0x0f)==0)?"^":"x"
       # Position the ^ Character in the Up text
       up = (simple_id<8 or simple_id.to_s.size>3) ? "\t " + up : "\t\t " + up
       left = (@passages[tile_id]&((1<<(4/2-1))&0x0f)==0)?"<":"x"
       right = (@passages[tile_id]&((1<<(6/2-1))&0x0f)==0)?">":"x"
       down = (@passages[tile_id]&((1<<(2/2-1))&0x0f)==0)?"v":"x"
       # Priority Tile with Impassable Directions
       if @priorities[tile_id] > 0 and
          ((@passages[tile_id]&((1<<(8/2-1))&0x0f)!=0) or # Impassable Up
           (@passages[tile_id]&((1<<(4/2-1))&0x0f)!=0) or # Impassable Left
           (@passages[tile_id]&((1<<(6/2-1))&0x0f)!=0) or # Impassable Right
           (@passages[tile_id]&((1<<(2/2-1))&0x0f)!=0))   # Impassable Down
         # Layer for Priority Tile with Impassable Directions
         i_pr = i
       elsif not i_pr
         i_pr = 0
       end
       # Add the following as Text to the Message
       tile_msg = tile_msg, "\n- Simple Tile ID: ", simple_id, auto_msg
       tile_msg = tile_msg,  up
       tile_msg = tile_msg, "\n- Priority: ", @priorities[tile_id]
       tile_msg = tile_msg, "\t            ", left, "       ", right
       tile_msg = tile_msg, "\n- Terrain Tag: ", @terrain_tags[tile_id]
       tile_msg = tile_msg, "\t\t ", down
       tile_msg = tile_msg, "\n- Bush: ", @passages[tile_id] & 0x40 == 0x40
       tile_msg = tile_msg, "\n- Counter: ", @passages[tile_id] & 0x80 == 0x80
       # Priority Tile has Impassable Flags
       if (i < 3 and i_pr > i)
         tile_msg = tile_msg, "\nNOTE: Priority Tile on Layer ", i_pr,
           " will Override Passages for this Tile",
           "\n(This is normal for Fences and Railings)"
         np_found = true
       # If not Top Layer and Non Priority Tile has sett Passable Flags
       elsif (i < 3) and lnpl > i
         tile_msg = tile_msg, "\nNOTE: Tile on Layer ", lnpl,
           " will Override Passages for this Tile"
         np_found = true
       end
       
       if event.tile_allow_move and event.tile_allow_move.include?(simple_id)
         tile_msg = tile_msg, "\n- \\tile_allow_move allows Event ", event.id,
                    " ALL movement on Simple Tile ID:", simple_id
       end
       if event.tile_no_move and event.tile_no_move.include?(simple_id)
         tile_msg = tile_msg, "\n- \\tile_no_move prevents Event ", event.id,
                    " from ANY movement on Simple Tile ID:", simple_id
       end
       if event.tile_only_move and event.tile_only_move.include?(simple_id)
         tile_msg = tile_msg, "\n- \\tile_only_move allows Event ", event.id,
                    " ALL movement on Simple Tile ID:", simple_id
         if @priorities[tile_id] > 0
           tile_msg = tile_msg, "\n\nPROBLEM: Simple Tile ID:", simple_id,
                    " has a Priority of ", @priorities[tile_id],
                    " which does NOT allow movement!",
                    "\nUse \\tile_only_move with Non Priority Tiles!"
         end
       end
       # Newlines between Tile Titles
       tile_msg = tile_msg, "\n\n" if i > 0
     else
       # Add the following as Text to the Message
       tile_msg = tile_msg, "\n- Erased (Tile ID 0 - No Data)\n\n"
     end
     # Store Layer a Non Priority Tile is found
     lnpl = i if @priorities[tile_id] == 0 and np_found.nil?
   end
   # Add Terrain Tag Conflict Message if Terrain Tag Conflict Detected
   if ttc
     tile_msg = tile_msg, "NOTICE: Terrain Tag Conflict Detected!\n",
       "- Only ONE Terrain Tag can be processed at a time!\n",
       "- Terrain Tags on Lower Layers are unable to be used.\n",
       "- You can cover Terrain Tags with Non Priority Tiles, just\n",
       "  not another Terrain Tag Tile, including Priority Tiles.\n",
       "  (Non Fatal Information)"
   else
     tile_msg = tile_msg, "No Terrain Tag Conflicts Detected"
   end
   # Check for Eraser Tile with an Incorrect Priority (should ALWAYS be 5)
   if @priorities[0] != 5
     tile_msg = tile_msg,"\n\nWARNING: Eraser Tile has Incorrect Priority!\n",
        "- your Eraser Tile (the Tile in the upper left corner of\n",
        "  Tileset Palette Window) should have a Priority of 5"
   end
   # Return the Generated Information Message
   print tile_msg    
 end
 #--------------------------------------------------------------------------
 # * Tileset ID - Game_Map
 #  - Returns Map Data of Tileset ID
 #--------------------------------------------------------------------------
 def tileset_id
   return @map.tileset_id
 end  
 #--------------------------------------------------------------------------
 # * Simplify Tile ID - Game_Map
 #      tile_id : Tile ID Data
 #  - Returns 0 as Eraser Tile
 #  - Returns 1 - 7 for Autotiles
 #  - Returns Tile IDs that start at 8 for Non Autotile Tileset Data
 #--------------------------------------------------------------------------
 def simplify_tile_id(tile_id)
   # Convert Autotiles to 1 - 7 and subtract 376 so Tile IDs start at 8
   return (tile_id < 384 ? tile_id / 48 : tile_id - 376)
 end  
 #--------------------------------------------------------------------------
 # * Event Tile Not Passable? - Game_Map
 #   - Passable for Events with a Tile RTP Through flag
 #   - Returns TRUE if a Tile is Not Passable.  
 #   - Inverse Logic: -1 * -1 = 1
 #     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
 #     e      : iteration of each event in all events to be checked
 #     se     : Self (If event is determined passable)
 #     result : true or false passed as an arg by Aliases  
 #--------------------------------------------------------------------------
 alias rtp_event_tile_not_passable? event_tile_not_passable? unless $@
 def event_tile_not_passable?(x, y, d, bit, e, se = nil, result = nil)
   # If Self Event is trying to move through this Event and RTP Through
   if result.nil? and not se.nil?
     # If Self Event (s) has an \event_through Comment and not Override
     if se.event_through and not se.no_through_event_tiles
       # Passable - Self Event has an Event Through Flag, check other Tiles
       return false
     # If Non Priority Tile and Event has a Allowance for this Tile ID      
     elsif e.tile_id > 0 and not se.no_event_tiles and
           (se.tile_allow_move or se.tile_only_move or se.tile_no_move)
       # Simplify the Tile ID of the Event
       simple_id = simplify_tile_id(e.tile_id)
       # Shorthand
       tile_allow_move = se.tile_allow_move
       tile_only_move = se.tile_only_move
       tile_no_move = se.tile_no_move
       # If Converted Tile (simple_id) is Restricted
       if (tile_only_move and @priorities[e.tile_id] == 0 and
           not tile_only_move.include?(simple_id) ) or
          (tile_no_move and tile_no_move.include?(simple_id)) and
          (not tile_allow_move or not tile_allow_move.include?(simple_id))
         # Impassable - Tile is Restricted
         result = true
       # If Converted Tile ID of Event is Allowed
       elsif (tile_allow_move and tile_allow_move.include?(simple_id) ) or
             (tile_only_move and priorities[e.tile_id] == 0 and
              tile_only_move.include?(simple_id) )
         # Passable - Tile from Event is flagged to Allow Movement
         result = false
       end
     end
   end
   # Call Original or other Aliases (e = event, se = self_event)
   rtp_event_tile_not_passable?(x, y, d, bit, e, se, result)
 end
 #--------------------------------------------------------------------------
 # * RTP 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
 #     e      : iteration of each event in all events to be checked
 #     se     : Self (If event is determined passable)
 #     result : true or false passed as an arg by Aliases    
 #--------------------------------------------------------------------------
 alias rtp_event_tile_passable? event_tile_passable? unless $@
 def event_tile_passable?(x, y, d, bit, e, se = nil, result = nil)
   # If Self Event (s) is allowed through All Events(e) and not Override
   if se and se.event_through and not se.no_through_event_tiles
     # Passable - Self Event has an Event Through Flag, check other Tiles
     return false      
   # If Non Priority Tile and Event has a Allowance for this Tile ID
   elsif result.nil? and not se.nil? and e.tile_id > 0 and
         not se.no_event_tiles and (se.tile_allow_move or se.tile_only_move)
     # Simplify the Tile ID of the Event
     simple_id = simplify_tile_id(e.tile_id)
     # Shorthand
     tile_allow_move = se.tile_allow_move
     tile_only_move = se.tile_only_move
     tile_no_move = se.tile_no_move  
     # If Converted Tile (c_tile) is Not Restricted
     if (tile_allow_move and tile_allow_move.include?(simple_id) ) or
        (tile_only_move and @priorities[e.tile_id] == 0 and
        tile_only_move.include?(simple_id) )
       # Passable - Tile is Passable for this NPC
       result = true
     end
   end    
   # Call Original or other Aliases (e = event, se = self_event)
   rtp_event_tile_passable?(x, y, d, bit, e, se, result)
 end    
 #--------------------------------------------------------------------------
 # * RTP Tile Not Passable? - Game_Map
 #   - Alias of method defined in Modular Passable
 #   - Returns TRUE if a Map Tile is Not Passable due to bits
 #   - Inverse Logic: -1 * -1 = 1
 #   - 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 : Self (If event is determined passable)
 #     result     : true or false passed as an arg by Aliases
 #--------------------------------------------------------------------------
 alias rtp_tile_not_passable? tile_not_passable? unless $@
 def tile_not_passable?(x, y, d, bit, tile_id, self_event = nil, result = nil)
   # If Non Priority Tile and Event has a Restrction for this Tile ID
   if result.nil? and not self_event.nil? and tile_id > 0 and
      (self_event.tile_only_move or self_event.tile_no_move or
       self_event.tile_allow_move)
     # Convert Tile ID to a Simplified Tile ID
     simple_id = simplify_tile_id(tile_id)
     # Shorthand
     tile_allow_move = self_event.tile_allow_move
     tile_only_move = self_event.tile_only_move
     tile_no_move = self_event.tile_no_move
     # If Converted Tile (simple_id) is Restricted
     if (tile_only_move and @priorities[tile_id] == 0 and
         not tile_only_move.include?(simple_id)) or
        (tile_no_move and tile_no_move.include?(simple_id)) and
        (not tile_allow_move or not tile_allow_move.include?(simple_id))
       # Impassable - Tile is Restricted
       result = true
     # If Converted Tile ID is Allowed
     elsif (tile_allow_move and tile_allow_move.include?(simple_id) ) or
           (tile_only_move and @priorities[tile_id] == 0 and
           tile_only_move.include?(simple_id) )
       # Passable - Tile is Passable for this NPC
       result = false
     end
   end
   # Call Original or other Aliases
   rtp_tile_not_passable?(x, y, d, bit, tile_id, self_event, result)
 end
 #--------------------------------------------------------------------------
 # * RTP Tile Passable? - Game_Map
 #   - Alias of method defined in Modular Passable
 #   - 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 : Self (If event is determined passable)
 #     result     : true or false passed as an arg by Aliases  
 #--------------------------------------------------------------------------
 alias rtp_tile_passable? tile_passable? unless $@
 def tile_passable?(x, y, d, bit, tile_id, self_event = nil, result = nil)
   # If an Alias has another result, use it
   if result.nil? and not self_event.nil? and tile_id > 0 and
      (self_event.tile_allow_move or self_event.tile_only_move)
     # Convert Tile ID to a Simplified Tile ID
     simple_id = simplify_tile_id(tile_id)
     # Shorthand
     tile_allow_move = self_event.tile_allow_move
     tile_only_move = self_event.tile_only_move
     # If Converted Tile (simple_id) is Allowed
     if (tile_allow_move and tile_allow_move.include?(simple_id) ) or
       (tile_only_move and @priorities[tile_id] == 0 and
        tile_only_move.include?(simple_id) )
       # Passable - Tile is Passable for this NPC
       result = true
     end
   end
   # Call Original or other Aliases
   rtp_tile_passable?(x, y, d, bit, tile_id, self_event, result)
 end  
end

#==============================================================================
# ** Interpreter
#==============================================================================
class Interpreter
 #--------------------------------------------------------------------------
 # * RTP Tile Info - Interpreter (RTP = Restrict Tile Passage)
 #  - Script Call intended to be Printed during Development
 #       x : X Location on Map - Uses Events X if not specified
 #       y : Y Location on Map - Uses Events X if not specified
 #--------------------------------------------------------------------------
 def rtp_tile_info(x = nil, y = nil)
   # If run from Editor
   return unless $DEBUG
   # Event executing this Script Call
   event = $game_map.events[@event_id]
   # If no Arguments
   if x == nil and y == nil
     # X and Y coordinates of Event
     x, y = event.x, event.y
   end
   # If Location is Valid for the Map
   if not $game_map.valid?(x, y)
     # Generate Message for User about Tile
     return "Tile Information at Map X:", x, " Map Y:", y,
            "\n\nNo Info Available\n",
            "- Location is not on the Current Map"
   end
   # Print Map Data formatted for Humans
   $game_map.rtp_tile_info(x, y, event)
   # Return Msg about Printing twice
   return "just run \"rtp_tile_info(x, y)\" or just ",
          "\"rtp_tile_info\" without PRINT or p\n",
          "(no quotes either)"
 end
end

#==============================================================================
# ** Game_Character
#==============================================================================
class Game_Character
 #--------------------------------------------------------------------------
 # * Public Instance Variables - Game_Character
 #--------------------------------------------------------------------------
 attr_accessor :tile_allow_move         # Array of Tile IDs or nil
 attr_accessor :tile_only_move          # Array of Tile IDs or nil
 attr_accessor :tile_no_move            # Array of Tile IDs or nil
 attr_accessor :no_event_tiles          # Prevents NPCs on Event Tiles  
 attr_accessor :event_through           # Move through All Events, check Tiles
 attr_accessor :no_through_event_tiles  # Override \event_through, Event Tiles  
 #--------------------------------------------------------------------------
 # * RTP Event Not Passable? - Game_Character
 #  - ALL Collisions with \event_through Characters excluded from Checks
 #  - Overrides results of other scripts regardless of their results
 #  - Returning causes Tiles ONLY to be checked for \event_through Events
 #  - Coordinate Match has already been determined
 #     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
 #--------------------------------------------------------------------------
 alias rtp_event_not_passable? event_not_passable? unless $@
 def event_not_passable?(x, y, d, new_x, new_y, event, result = nil)
   # If Event or Self has an Event Through Flag
   if @event_through or event.event_through
     # Passable - Event has a Flag that allows Passage thru ALL Events
     return false
   # If Character has a Flag that prohibits Passage through Events with Tiles  
   elsif not @event_through and @no_event_tiles and
          not event.event_through and event.tile_id > 0
     # Impassable - This Character has a Flag that prohibits Event Tiles
     return true
   # If Event has a Non Priority Tile that is Restricted or Allowed
   elsif result.nil? and not @no_event_tiles and event.tile_id > 0 and
         (@tile_allow_move or @tile_only_move or @tile_no_move)
     # Convert Tile ID to a Simplified Tile ID
     simple_id = $game_map.simplify_tile_id(event.tile_id)
     # If Converted Tile (simple_id) is Restricted
     if (@tile_only_move and $game_map.priorities[event.tile_id] == 0 and
         not @tile_only_move.include?(simple_id)) or
        (@tile_no_move and @tile_no_move.include?(simple_id)) and
        (not @tile_allow_move or not @tile_allow_move.include?(simple_id))
       # Impassable - Event Tile is Restricted
       result = true
     # If Converted Tile ID is Allowed
     elsif (@tile_allow_move and @tile_allow_move.include?(simple_id) ) or
           (@tile_only_move and $game_map.priorities[event.tile_id] == 0 and
            @tile_only_move.include?(simple_id) )
       # Passable - Event Tile is Passable for this NPC
       result = false
     end
   end
   # Call Original or other Aliases
   rtp_event_not_passable?(x, y, d, new_x, new_y, event, result)
 end
 #--------------------------------------------------------------------------
 # * RTP Event Character Not Passable? - Game_Character
 #  - ALL Collisions with \event_through Characters excluded from Checks
 #  - Overrides results of other scripts regardless of their results
 #  - Returning causes Tiles ONLY to be checked for \event_through Events
 #  - Coordinate Match has already been determined
 #  - 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  
 #--------------------------------------------------------------------------
 alias rtp_event_char_not_passable? event_character_not_passable? unless $@
 def event_character_not_passable?(x, y, d, new_x, new_y, event, result = nil)
   # If Event has a @event_through Flag
   if @event_through or event.event_through
     # Passable - Event has a Flag that allows Passage thru ALL Events
     return false
   end
   # Call Original odr other Aliases
   rtp_event_char_not_passable?(x, y, d, new_x, new_y, event, result)
 end
 #--------------------------------------------------------------------------
 # * RTP Event Player Not Passable? - Game_Character
 #  - ALL Collisions with \event_through Characters excluded
 #  - Overrides results of other scripts regardless of their results
 #  - Returning causes Tiles ONLY to be checked for \event_through Events
 #  - Coordinate Match has already been determined
 #     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  
 #--------------------------------------------------------------------------
 alias rtp_event_player_not_passable? event_player_not_passable? unless $@
 def event_player_not_passable?(x, y, d, new_x, new_y, result = nil)
   # If Event has a @event_through Flag
   if @event_through
     # Passable - Event has a Flag that allows Passage thru PLAYER
     return false
   end
   # Call Original or other Aliases
   rtp_event_player_not_passable?(x, y, d, new_x, new_y, result)
 end
 #--------------------------------------------------------------------------
 # * Other Passable? - Game_Character
 #  - ALL Collisions with \event_through Characters excluded from Checks
 #  - Overrides results of other scripts regardless of their results
 #  - Returning causes Tiles ONLY to be checked for \event_through Events
 #  - 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  
 #--------------------------------------------------------------------------
 alias rtp_other_passable? other_passable? unless $@
 def other_passable?(x, y, d, new_x, new_y, result = nil)
   # If Event has a @event_through Flag and not Player
   if @event_through and self != $game_player
     # Passable - Event has a Flag that allows Passage
     result = true
   end
   # Cal Original or other Aliases
   rtp_other_passable?(x, y, d, new_x, new_y, result)
 end
 #--------------------------------------------------------------------------
 # * Simple Tile Id - Game_Character
 #--------------------------------------------------------------------------
 def simple_tile_id
   # If Event has a Tile
   if @tile_id > 0
     # Simplify it with the method in Game_Map and return it
     return $game_map.simplify_tile_id(tile_id)
   end
   # Default
   return 0
 end
end

#==============================================================================
# ** Game_Temp
#==============================================================================
class Game_Temp
 #--------------------------------------------------------------------------
 # * Public Instance Variables
 #--------------------------------------------------------------------------
 attr_accessor  :rtp_priority_error   # If Warning was Displayed for RTP
end

#==============================================================================
# ** Game_Event
#==============================================================================
class Game_Event < Game_Character
 #--------------------------------------------------------------------------
 # * Determine if Over Trigger - Game_Event
 #    (whether or not same position is starting condition)
 #  - Determine if Player must be standing on or facing this Event to trigger
 #  - Self is replaced with $game_player as Self Event because it is the
 #    Player that needs to be over the event or not
 #--------------------------------------------------------------------------
 alias rtp_over_trigger? over_trigger? unless $@
 def over_trigger?
   # If not through situation with character as graphic
   if @character_name != "" and not @through and not @event_through and
      not $game_player.through and not $game_player.event_through
     # Starting determinant is to face this Event to Trigger
     return false
   end
   # If no Collision between Player and Event
   if @event_through or @through or @character_name == "" or
      $game_player.through or $game_player.event_through
     # If this position on the map is Passable ($game_player as self_event)
     if $game_map.passable?(@x, @y, 0, $game_player)
       # Starting determinant is same position
       return true        
     else
       # Starting determinant is to face this Event to Trigger
       return false
     end
   end
   # Call Original or other Aliases
   rtp_over_trigger?
 end
 #--------------------------------------------------------------------------
 # * Check Tile Only Move errors - Game_Event
 #  - Checks to see if any Tiles have a Priority and display an Error in Debug
 #--------------------------------------------------------------------------
 def check_tile_only_move_errors
   # If in Editor and a Message has not already been displayed
   if $DEBUG and not $game_temp.rtp_priority_error and
      @tile_only_move and @tile_only_move.size > 0
     # Check each Simple Tile ID for a Priority
     for simple_id in @tile_only_move
       # If valid Tile
       if simple_id > 0
         # Convert Simpe ID to RMXP Tile ID
         tile_id = (simple_id < 8) ? simple_id * 48 : simple_id + 376
         # If Tile ID has a Priority
         if $game_map.priorities[tile_id] > 0
           # Explain the Problem
           print "RTP Warning: Event ", @id, " at Map X:", @x, " Map Y:", @y,
                 "\n- Simple Tile ID:", simple_id, " has a Priority!\n\n",
                 "\\tile_only_move[simple_id] should only be used\n",
                 "with Non Priority Tiles!\n\n",
                 "\\tile_allow_move[simple_id] and ",
                 "\\tile_allow_move[simple_id] can\n",
                 "both be used with Priority Tiles."
           # Set the Flag to prevent other Errors and allow User to fix issue
           $game_temp.rtp_priority_error = true
           # Prevent Spamming User with Errors
           return
         end
       end
     end
   end
 end
 #--------------------------------------------------------------------------
 # * Reset Page Comment Config - Game_Event
 #  - Resets Instance Variables on Refresh
 #--------------------------------------------------------------------------
 alias rtp_reset_page_comment_config reset_page_comment_config unless $@
 def reset_page_comment_config
   # Reset to set again by Comment Conditions immediately following
   @tile_allow_move = nil
   @tile_only_move = nil
   @tile_no_move = nil
   @no_event_tiles = nil
   @event_through = nil
   @no_through_event_tiles = nil
   # Runs Original or Other Aliases of this method
   rtp_reset_page_comment_config
 end
 #--------------------------------------------------------------------------
 # * RTP 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
 #  - Checks for \tile_allow_move[N], \tile_only_move[N,N], \tile_no_move[N,N]
 #  - Checks for \no_event_tiles Comments to prevent Tile Event Passage
 #  - Checks for \event_through Comments to allow Passage thru Characters
 #  - Checks for \no_through_event_tiles to override \event_through Event Tile
 #  - Returns count when a Comment is found to prevent checks by other Aliases
 #  - Returning count makes checks for comments occur faster
 #
 #  Note: When aliasing, please return the value of count, especially
 #        if your script adjusted this value.
 #--------------------------------------------------------------------------
 alias rtp_check_page_comment_config check_page_comment_config unless $@
 def check_page_comment_config(comment, count)
   # Looks for "\tile_allow_move" in the Comments, Capture Group $1 to Array
   comment.gsub(/^\\tile_allow_move\[([0-9, ]+)\]\z/i){@tile_allow_move = $1;
     @tile_allow_move = @tile_allow_move.split(",").map { |s| s.to_i };
     return count;}    
   # Looks for "\tile_only_move" in the Comments, Capture Group $1 to Array
   comment.gsub(/^\\tile_only_move\[([0-9, ]+)\]\z/i){@tile_only_move = $1;
     @tile_only_move = @tile_only_move.split(",").map { |s| s.to_i };
     check_tile_only_move_errors; return count;}
   # Looks for "\tile_no_move" in the Comments, Capture Group $1 to Array
   comment.gsub(/^\\tile_no_move\[([0-9, ]+)\]\z/i){@tile_no_move = $1;
     @tile_no_move = @tile_no_move.split(",").map { |s| s.to_i };
     return count;}
   # Looks for "\no_through_event_tiles" in the Comments (Use on NPCs)
   comment.gsub(/^\\no_through_event_tiles\z/i){@no_through_event_tiles = true;
     return count;}      
   # Looks for "\no_event_tiles" in the Comments (Use on Character Events)
   comment.gsub(/^\\no_event_tiles\z/i){@no_event_tiles = true;
     return count;}      
   # Looks for "\event_through" in the Comments
   comment.gsub(/^\\event_through\z/i){@event_through = true; return count;}
   # Return counter for other Aliases when no Comments are found
   return rtp_check_page_comment_config(comment, count)
 end  
end

# Restrict Tile Passage Version
$Restrict_Tile_Passage = 1.0



Instructions

Restrict Tile Passage (or RTP) has Three KEY Features
- tile_only_move[tile_ids]
- tile_allow_move[tile_ids]
- tile_no_move[tile_ids]

These three Key Features allow you to control specifically where any Character, including the Player can move.  To allow the Player to move on Water, you can run a script: @tile_only_move = [2, 3, 4] where 2, 3 and 4 are Water Tiles.


Compatibility

No known issues


Credits and Thanks


  • Id like to thank whoever invented the Remote Control for my TV.

  • I'd also like to express some major disappointment in whever invented the Remote Control for my TV since they didn't also invent Remote Control Beer!




Author's Notes

This script is REQUIRED by Heretic's Vehicles XP, and requires Modular Passable in order to function as expected.  There is one feature in here that is duplicated in several Modular Passable scripts, and that is \event_through.  This is not a mistake.  But please let me know if you find any bugs.  I've bent over backwards to make sure this script and every other Modular Passable script is PERFECT upon release.  Although the script was complete in October, it has taken me this long to make sure it is perfectly compatible with every other Modular Passable script out there, including Loop Maps, which has been an absolute nightmare due to the need to modify almost every other script I ever wrote.
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.)