Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - mad.array

1
RMXP Script Database / [XP] Blinking Characters
March 28, 2013, 06:30:32 am
Blinking Characters
Authors: mad.array
Version: 1.1
Type: Game_Character Add-On
Key Term: Environment Add-on



Introduction

A script that automatically checks all Game_Events/Game_Characters to see if they have a blinking sprite and makes said events blink. Options can be changed to change blink rate and to force eyes open/closed.


Features


  • Make people blink

  • Control how often they blink

  • Make certain events not blink at all or have their eyes closed or open for however long you like.




Screenshots
Since when do I do screenshots?


Demo

Scripty goodness below.


Script

Place above Main, but below default scripts. To make characters blink you will need a graphic named the same as the normal character, but with the Suffix _Blink. So for Aluxes/Arshes/Default guy you would need the following:

001-Fighter01.png # The regular graphic.
001-Fighter_Blink.png # The blinking graphic.
Spoiler: ShowHide

#==============================================================================
# ** Game_Character (part 4)
#------------------------------------------------------------------------------
#  This class deals with characters. It's used as a superclass for the
#  Game_Player and Game_Event classes.
#
#   This section covers the main body of the blinking.
#   The only things you should need to change are the blink states and the blink
#   frames. The frames decides a rough guide for how long the eyes should be open
#   for. The blink states decide how the eyes act.
#     -1 = No blinking graphic
#      0 = Forced no blinking
#      1 = Normal blink(Eyes open)
#      2 = Normal blink(Eyes closed)
#      3 = Forced eyes closed
#==============================================================================

class Game_Character
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
 
  attr_accessor :base_character_name      #Base character file
  attr_accessor :end_base                 #New base sprite at end of animation
  attr_accessor :eye_sprite               #Current Eye sprite
  attr_accessor :blink_state              #Blink boolean
  attr_accessor :blink_frames             #Blink frame interval (average)
  attr_accessor :blink_count              #Current blink count
  attr_accessor :close_count              #Close rnd
  attr_accessor :open_count               #Open rnd
 
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  alias extinit initialize
  def initialize
    extinit
    @base_character_name = @character_name
    @end_base = ""
    @base_eye_sprite = ""
    @base_eye_hue = 0
    @eye_sprite = @base_eye_sprite
    @blink_state = 1
    @blink_frames = 80
    @blink_count = 0
    @close_count = 0
    @open_count = 0
  end
 
 
=begin

=end
 
  alias blinkupdate update
  def update
    blinkupdate
    update_blink
  end
 
  def update_blink
    cnb = sprintf("Graphics/Characters/%s_Blink.png", @character_name)
    suff = FileTest.exist?(cnb)
    if suff == false && @blink_state < 2
      @blink_state = -1
      return
    end
    bs = sprintf("%s_Blink", @character_name)
    if @blink_state == 1
      @blink_count += 1
      if @blink_count >= @open_count
        @base_character_name = @character_name
        @blink_count = 0
        @blink_state = 2
        @character_name = bs
        @close_count = (6 * (rand + 0.5))
      end
    end
    if @blink_state == 2
      @blink_count += 1
      if @blink_count >= @close_count
        @blink_count = 0
        @blink_state = 1
        @character_name = @base_character_name
        @open_count = @blink_frames * (rand + 0.5)
      end
    end
    if @blink_state == 3
      bs = sprintf("%s_Blink", @base_character_name)
      @blink_count =0
      if @character_name != bs
        @character_name = bs
      end
    end
  end
 
  def blink_reset_base
    @base_character_name = @character_name
  end

  def blink_refresh(frames)
    @blink_count = 0
    @blink_frames = frames
  end
 
  def blink_set_state(state)
    @blink_state = state
    case state
      when -1, 0, 1
        @blink_count = 0
        @character_name = @base_character_name
      when 2, 3
        @blink_count = 0
        bs = sprintf("%s_Blink", @base_character_name)
        if FileTest.exist?(bs)
          p("Apparently found!")
          @character_name = bs
        end
      end
  end

 
end

class Interpreter
 
  alias command_322_blink command_322
  def command_322
    $game_player.blink_state = 1 if $game_player.blink_state == -1
    command_322_blink
  end
 
  def blink_refresh(eventid, frames)
    # Branch by parameter
    case eventid
    when -1  # player
      $game_player.blink_refresh(frames)
    when 0  # this event
      events = $game_map.events
      events[@event_id].blink_refresh(frames)
    else  # specific event
      events = $game_map.events
      events[eventid].blink_refresh(frames)
    end
  end
 
  def blink_set_state(eventid, state)
    # Branch by parameter
    case eventid
    when -1  # player
      $game_player.blink_set_state(state)
    when 0  # this event
      events = $game_map.events
      events[@event_id].blink_set_state(state)
    else  # specific event
      events = $game_map.events
      events[eventid].blink_set_state(state)
    end
  end
 
end




Instructions
Again I'm using my favourite Event Control system, the Move Route. The blinking will work by default but if you want to refine the system then call a script command. You now have two options:

'blink_refresh(frames)'

Use this to change how often the character/event blinks. There is a random factor involved so it won't be exact. By default, this is set to 80 frames (4 seconds), but feel free to change this to whatever you want.

'blink_set_state(state)'

There are technically five options for state, but you should only ever need to use two.

0 = Forced eyes open
3 = Forced eyes closed

So if you set up a Move Route for the player and had a script call with 'blink_set_state(3)' your player would be running around with their eyes wide shut until you changed it.


Compatibility

Aliases update in Game_Character, so will probably have conflicts with systems that alter the player graphic.


Credits and Thanks


  • Mine... all mine!




Author's Notes

For your convenience, here are some blinking sprites for the RTP charsets. Just place them in Graphics/Characters.
http://www.filedropper.com/blinking
2
RMXP Script Database / [XP] mad.array Mini add-ons
March 23, 2013, 07:25:15 pm
mad.array Mini Add-ons
Authors: mad.array
Version: 1.0
Type: Snippets
Key Term: Misc Add-on



Introduction

A collection of bite sized add-ons that I've tinkered with. Look at the features a few dozen pixels down to see the list. Also ignore the fact that taking the hyphen into account, the acronym for this script is MaMa.


Features


  • In Battle Event Deletion

  • Event Mover & Perma-Delete

  • Global Self Switch Controller & Switch Invert

  • Advanced Timer Controls




Screenshots

As usual, I have none.


Script

Insert somewhere above Main.
Spoiler: ShowHide

#==============================================================================
# In Battle Event Removal
#------------------------------------------------------------------------------
#  Allows events to be deleted during a battle, not a frame before the
#  transition, not a frame afterwards.
#
#  To use it, use a 'Call Script' command before a battle. Then type:
#
#      $game_temp.battle_ids = [x,y,z, etc]
#
#  Inside the array, place the ids of the events to be deleted. When the battle
#  begins, the events will be removed. This works in the same way as the
#  'Erase Event' command, so make sure you set a switch or use some other method
#  to permanently remove the events.
#==============================================================================


class Game_Temp
 
 attr_accessor :battle_ids
 
 alias init_battle_ids initialize
 def initialize
   init_battle_ids
   @battle_ids = []
 end
end

class Scene_Map
 
 alias call_battle_ids call_battle
 def call_battle
   call_battle_ids
   for i in 0...$game_temp.battle_ids.length
     $game_map.events[$game_temp.battle_ids[i]].erase
   end
   $game_temp.battle_ids = []
   $game_map.need_refresh = true
 end
 
end

#==============================================================================
# Event Mover & Perma-Delete
#------------------------------------------------------------------------------
#  Allows you to set a new position for an event without running auto run scripts.
#
#  You can do this from a 'Set move route' command, but it will only work
#  for the event that is being controlled by the move route command. Just use
#  The 'script' option in the move route planner and type one of these:
#
#   'set_to_current_pos' - Sets the Events new position to where it currently is
#   so that next time the map loads, that's where the event will be.
#
#   'set_to_this_pos(x,y)' - This will set the position of the event to the
#   x and y coordinates specified.
#
#   'delete_event' - Permanently 'deletes' the event. Actually it doesn't, it
#   just erases it every time the map is loaded.
#
#
#==============================================================================

class Game_Map

 alias event_move_setup setup
 def setup(map_id)
   event_move_setup(map_id)
   for i in @map.events.keys
     key = [map_id, i]
     if $game_self_position != nil
       if $game_self_position[key] != nil
         stored_x = $game_self_position[key][0]
         stored_y = $game_self_position[key][1]
         stored_dir = $game_self_position[key][2]
         stored_del = $game_self_position[key][3]
         if stored_del == true
           @events[i].erase
         else
           @events[i].moveto(stored_x,stored_y)
           @events[i].direction = stored_dir
         end
       end
     end
   end
 end
 
end


class Game_Event
 
 attr_accessor :direction
   
 def set_to_current_pos
   if self != $game_player
     key = [$game_map.map_id, @id]
     $game_self_position[key] = [@x, @y, @direction, false]
   end
 end
 
 def set_to_this_pos(newx,newy)
   if self != $game_player
     key = [$game_map.map_id, @id]
     $game_self_position[key] = [newx,newy,@direction, false]
   end
 end
 
 def delete_event
   if self != $game_player
     key = [$game_map.map_id, @id]
     $game_self_position[key] = [@x,@y,@direction,true]
     self.erase
   end
 end
 
end

#==============================================================================
# ** Game_SelfStoredPos
#------------------------------------------------------------------------------
#  This class handles events stored locations.
#==============================================================================

class Game_SelfStoredPos

 def initialize
   @data = {}
 end

 def [](key)
   return @data[key]
 end

 def []=(key, value)
   @data[key] = value
 end
end

class Scene_Title
 
 alias stored_main main
 def main
   stored_main
   $game_self_position = Game_SelfStoredPos.new
 end
end

#==============================================================================
# Global Self Switch Control
#------------------------------------------------------------------------------
#  This script lets you control Self Switches on the current map from ANY event!
#  Using 'Call Script', just type 'SetSelfSwitch(e,s,v)' where e is the Event ID,
#  s is the Switch ("A","B","C" or "D") and v is true or false (no speech marks!)
#
#  Also, by typing 'InvertSelfSwitch(e,s)' you can turn a self switch off if it
#  is on and on if it is off.
#
#  Plus, as an added bonus, you can do this to normal switches by typing
#  'InvertSwitch(s)'
#==============================================================================
class Interpreter

 def SetSelfSwitch(e,s,v)
   key = [$game_map.map_id,e,s]
   $game_self_switches[key]= v
   $game_map.events[e].refresh
 end
 
 def InvertSelfSwitch(e,s)
   key = [$game_map.map_id,e,s]
   if $game_self_switches[key] == false
     $game_self_switches[key]=true
   else
     $game_self_switches[key]=false
   end
   $game_map.events[e].refresh
 end
 
 def InvertSwitch(s)
   if $game_switches[s] == false
     $game_switches[s]=true
   else
     $game_switches[s]=false
   end
 end
 
end

#==============================================================================
# Advanced Timer Controls
#------------------------------------------------------------------------------
#  Adds a few functions to the timer.
#
#  Use the 'call script' command and type one of the following:
#
#   timer_add(x)   -  Where x is the number of seconds you want to add to the
#                     timer.
#   timer_minus(x) -  Where x is the number of seconds you want to take away
#                     from the timer
#   pause_timer    -  If you want to pause the timer (Can be set before you
#                     start a timer so that it doesn't start until you tell
#                     it to.
#   unpause_timer  -  Unpauses a paused timer(Can again be set when a timer
#                     isn't running.
#==============================================================================


class Interpreter
 
 def timer_add(seconds)
   return if !$game_system.timer_working
   $game_system.timer += (seconds * Graphics.frame_rate)
 end
 
 def timer_minus(seconds)
   return if !$game_system.timer_working
   $game_system.timer -= (seconds * Graphics.frame_rate)
   $game_system.timer = 0 if $game_system.timer < 0
 end

 def pause_timer
   $game_system.timer_paused = true
 end

 def unpause_timer
   $game_system.timer_paused = false
 end

end


class Game_System
 
 attr_accessor :timer_paused
 
 alias matimerinit initialize
 def initialize
   matimerinit
   @timer_paused = false
 end

 alias timerupdate update
 def update
   timerupdate if @timer_paused == false
 end

end
 
end



Instructions

Insert above Main. Follow the half-hearted copy-paste job that is my set of instructions.

In Battle Event Deletion

Erases specified events DURING a battle. Not a frame before, not a frame afterwards. Use a 'Call Script' command before a battle. Then type:

   $game_temp.battle_ids = [x,y,z, etc]

Inside the array, place the ids of the events to be deleted. When the battle
begins, the events will be removed. This works in the same way as the
'Erase Event' command, so make sure you set a switch or use some other method
to permanently remove the events.

Event Mover & Perma-Delete

Permanently moves or 'deletes' events. Whenever the map is reloaded, it will remember the new location and whether the event is permanently deleted. Choose a 'Set move route' command and select the event you want to move or delete, then use the 'script' option in the move route planner and type one of these:

 'set_to_current_pos' - Sets the Events new position to where it currently is
 so that next time the map loads, that's where the event will be.

 'set_to_this_pos(x,y)' - This will set the position of the event to the
 x and y coordinates specified.

 'delete_event' - Permanently 'deletes' the event. Actually it doesn't, it
 just removes it every time the map is loaded.

Global Self Switch Controller & Switch Invert

This lets you control Self Switches on the current map from ANY event!
Using 'Call Script', just type 'SetSelfSwitch(e,s,v)' where e is the Event ID,
s is the Self Switch to alter ("A","B","C" or "D") and v is the boolean (true or false)

Also, by typing 'InvertSelfSwitch(e,s)' you can turn a self switch off if it
is on and on if it is off.

Plus, as an added bonus, you can do this to normal switches by typing
'InvertSwitch(s)'

Advanced Timer Controls

Adds a few functions to the timer. With it you can pause/unpause a timer, or add/take away time. Use the 'call script' command and type one of the following:

 timer_add(x)   -  Where x is the number of seconds you want to add to the timer.

 timer_minus(x) -  Where x is the number of seconds you want to take away from the timer

 pause_timer    -  If you want to pause the timer (Can be set before you start a timer so that it doesn't start until you tell it to.

 unpause_timer  -  Unpauses a paused timer(Can again be set when a timer isn't running.


Compatibility
None as far as I'm aware. Let me know if you encounter any.


Credits and Thanks

Mikey, for bombarding me with script requests and keeping me thinking.
Hayley, for putting up with the pre-release insomnia and post-release grouches.


Author's Notes

Credit is appreciated, but not needed.
3
RMXP Script Database / [XP] Monster Event Deletion
March 13, 2013, 09:00:37 am
Monster Event Deletion
Authors: mad.array
Version: 1.0
Type: Snippet
Key Term: Misc Add-on



Introduction

Just a little fix up for a common problem in RMXP. When you erase an event just after a battle, it always appears for a frame before being deleted. WELL NO MORE! With this script you can erase specific events during the battle scene and they will be gone as soon as the battle is over. Please note that you should still set a switch or something else to make sure they don't come back when you re-enter the map though!


Features


  • Monsters be-gone!

  • People be-gone!

  • Any event be-gone!

  • Simple Call Script command




Screenshots

How do you show an erased event?


Script

Insert somewhere above Main.
Spoiler: ShowHide

class Game_Temp
 
 attr_accessor :battle_ids
 
 alias init_battle_ids initialize
 def initialize
   init_battle_ids
   @battle_ids = []
 end
end

class Scene_Map
 
 alias call_battle_ids call_battle
 def call_battle
   call_battle_ids
   for i in 0...$game_temp.battle_ids.length
     $game_map.events[$game_temp.battle_ids[i]].erase
   end
   $game_temp.battle_ids = []
   $game_map.need_refresh = true
 end
 
end



Instructions

To use, simply set up a Call Script before your battle. Inside the script put:

$game_temp.battle_ids =[1,2,3]

Replacing the 1,2 & 3 with the event ids that need deleting. Again, make sure you still set up another, more permanent, method to make sure the event doesn't reappear.



Compatibility

I don't think there will be any compatability issues. Aliases call_battle from Scene_Map and Initialize from Game_Temp.


Credits and Thanks

I did it all by my self. Yaaaaay!


Author's Notes

Credit if you so wish, but it's 24 lines of code... several of which are blank. So feel free to just use it. Just don't claim it as your own!
4
TOA Caterpillar, Move Routes & Pathfinding
Authors: mad.array, using Advanced Pathfinding by ForeverZer0
Version: 0.5a
Type: Movement Addon
Key Term: Movement Addon



Introduction

Well, I've gone and mucked about with a perfectly good script. Again. Two perfectly good scripts all be told. This script allows you to use the in built move route commands with the tons_of_addons caterpillar feature. It also allows caterpillar actors to behave like events whilst they are away from the player. It is in a very rough stage at the moment so some testing and feedback will be required.

It uses my modified Advanced Pathfinding & Carrots script, which has been modified some more. I'm surprised no-one has asked about the carrot thing, but it's gone 1 in the morning so I'm surprised by a lot of things.


Features


  • All the features of the previous AP script

  • Control members of your caterpillar group!

  • Have them say things like a regular event would.

  • Return them to you like a dog with a stick!




Screenshots

Not really a screenshot script.



Script

Goes below toa scripts (required). Not compatible with other Pathfinding scripts.

Spoiler: ShowHide

#=begin
#+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
# Advanced Pathfinding + Carrots with Caterpillar Support
# Author: ForeverZer0, mad.array
# Version: 1.0b
# Date: 10.12.2011
#+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
#
# Introduction:
#   This is an advanced an highly inteligent pathfinding system. It allows for
#   the user to either through script or script call quickly and easily have
#   events or the game player automatically walk a path to a given set of
#   coordinates. The system is smart enough to quickly find paths through
#   relatively complex areas, and asjust on the fly for any obstacle that moves
#   to block its path. I used the A* algorithm, basic search algorithm used
#   often for robotics. More on this algorithm can be read about here:
#
#               http://en.wikipedia.org/wiki/A*_search_algorithm
#
#
#   In addition, the modifications to the script allow for events to navigate to
#   other events via their event name. If more than one event with a name exists
#   it will pick one at random. You can also define multiple event names to pick
#   from in an array.
#
#   In a further addition, caterpillar actors (henceforthe referred to as
#   members) can also be moved by 'syncing' them to an event on the map. When
#   this is done, they will move instead of that event. They will also perform
#   the actions of that event when the trigger conditions are met.
#
# Features:
#   - Fast and intelligent pathfinding
#   - Easy to use script calls
#   - Optional "range" parameter can have character find alternate locations
#     if the preferred one is blocked and they are within the given range.
#   - Optional callbacks can be given to have something execute if when the
#     character reaches its goal, or when it fails to do so.
#
# Instructions:
#   - Place script below default scripts and tons_of_addons, and above "Main".
#   - Use the following script call:
#
#     pathfind(X, Y, CHARACTER, RANGE, SUCCESS_PROC, FAIL_PROC)
#    
#     The X and Y are the only required arguments. The others can be omitted.
#    
#     X - The x-coordinate to pathfind to. If X is a string or array then
#         strings must be contained within "quotation marks" and the array
#         within [square brackets].
#     Y - The y-coordinate to pathfind to. If using a string or array, DO NOT
#         leave Y blank. It will cause the script to crash.
#
#     CHARACTER - Either an instance of the character ($game_player,
#                 $game_map.events[ID], etc) or the ID of a character. The ID
#                 will be the event ID. Use -1 for the game player.
#
#     SUCCESS_PROC - A Proc object that will be executed when the player
#                    reaches the defined coordinates.
#     FAILURE_PROC - A Proc object that will be executed when the player
#                    cannot reach the defined coordinates.
#
#   - As default, the pathfinder will make 35 attempts to recalculate a route
#     that gets blocked. This value can be changed in game with the script
#     call:
#           $game_map.collision_retry = NUMBER
#
#     You can change the default value if desired by looking down to the first
#     class below in the main script.
#   - For longer pathfind routes, it is sometimes necessary to reset the
#     search limiter. This may cause increased lag when an object blocks the
#     character from being able to move, but will increase the range that the
#     system can work with. Use the following script call:
#
#         $game_map.search_limiter = NUMBER  (Default 1000)
#
#   - If you are experiencing any compatibility problems, go to the Game_Map
#     class below and set @recalculate_paths to false. This will take away some
#     of the efficiency of recalculating collisions, but will improve may fix
#     your problem.
#   - When you want a member to move, you have to sync them to an event. This
#     can be done by using the following script call:
#
#         $game_player.members[i].synced = i
#
#     Where i is the number of the event your member will use for move commands
#     and interaction.
#
#   - When returning a member to the train, have an event commands like this;
#    
#       Script: z = $game_player.calc_return_path(i)
#               pathfind(z[0],z[1],2,0)
#               Wait for moves completion
#       Script: $game_player.members[i].synced = nil
#
#     Where i is the index of the member(0 to 2)
#      
#
# Compatibility:
#   Highly compatible. May experience issues with Custom Movement scripts,
#   but even then, it is unlikely. Also modifies Interpreter command 209... as
#   in not aliased, I had to copy and paste and change modified. Sorry!
#
# Credits/Thanks:
#   - ForeverZer0, for the AP script
#   - Blizzard, for the caterpillar scipt and general awesomeness.
#   - Special thanks to Jragyn for help making the big maze for the demo and
#     help testing.
#   - Credit goes to the Peter Hart, Nils Nilsson and Bertram Raphael for the
#     original search algorithm that was implemented
#
#+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

class Game_System
 
 alias init_toa_later initialize
 def initialize
   init_toa_later
   @CATERPILLAR                = true
end

 attr_accessor :CATERPILLAR
end

#===============================================================================
# ** Game_Map
#===============================================================================

class Game_Map
 
 attr_accessor :collision_retry
 attr_accessor :recalculate_paths
 attr_accessor :search_limiter
 
 alias zer0_pathfinding_init initialize
 def initialize
   # Initialize instance variables used for pathfinding.
   @collision_retry = 35
   @recalculate_paths = true
   @search_limiter = 1000
   # Original method
   zer0_pathfinding_init
 end
end

#===============================================================================
# ** Interpreter
#===============================================================================

class Interpreter
 
 def pathfind(x, y, *args)
   @x = x
   @y = y
   args[0] = @event_id if args[0] == nil
   args[1] = 0 if args[1] == nil
   if @x.is_a?(Array)
     decidepath(@x, @y, @args)
   end
   findpathevent(@x,@y, args)
   Pathfind.new(Node.new(@x, @y), *args)
 end

 def decidepath(x, y, args)
   r = rand(100) + 1
   for i in 0...x.size
     targ1 = 1 + (100/x.size) * i
     targ2 = (100/x.size) * (i +1)
     if r >= targ1 && r <=targ2
       @x=x[i]
     end
   end
 end

 def findpathevent(x, y, args)
   xs = []
   ys = []
   proxx = []
   proxy = []
   distance = []
   chosen = nil
   if x.is_a?(String)
     for event in $game_map.events.values
       if event.name == x
         xs.push(event.x)
         ys.push(event.y)
       end
     end
     if args[0].is_a?(Integer)
     if args[0] >  0
       runnerx = $game_map.events[args[0]].x
       runnery = $game_map.events[args[0]].y
     else
       runnerx = $game_player.x
       runnery = $game_player.y
     end
   end
   if args[0].is_a?(Game_Character)
     char = args[0]
     runnerx = char.x
     runnery = char.y
   end
     if xs.size > 1
       for i in 0...xs.size
         proxx[i] = runnerx - xs[i]
         proxy[i] = runnery - ys[i]
         proxx[i] *= -1 if proxx[i] <0
         proxy[i] *= -1 if proxy[i] <0
         if proxx[i] > proxy[i]
           distance[i] = proxx[i] - proxy[i]
         elsif proxx[i] < proxy[i]
           distance[i] = proxy[i] - proxx[i]
         elsif proxx[i]==0
           distance[i] = proxy[i]
         elsif proxy[i]==0 || proxy[i] == proxx[i]
           distance[i] = proxx[i]
         end
       end
       j = 0
       while chosen == nil
         chosen = distance.index(j)
         j+=1
       end
         @x = xs[chosen]
         @y = ys[chosen]
     else
       @x = xs[0]
       @y = ys[0]
     end
   end
 end
end


class Game_Event
 
 attr_accessor :direction_fix
 attr_accessor :step_anime
 attr_accessor :walk_anime
 attr_accessor :always_on_top
 
def name
  return @event.name
end
end

#==============================================================================
# ** Pathfind
#==============================================================================

class Pathfind

 attr_reader   :route                  
 attr_accessor :range  
 attr_reader   :goal
 attr_reader   :found
 attr_reader   :character                                
 attr_accessor :success_proc          
 attr_accessor :failure_proc        
 attr_accessor :target    
 attr_accessor :collisions      
 
 def initialize(node, char = -1, range = 0, *callbacks)
   # Set the character. Can either us an ID or an instance of a Game_Character.
   # A value of -1, which is default, is the Game_Player.
   if char.is_a?(Integer)
     @character = (char == -1) ? $game_player : $game_map.events[char]
     $game_player.members.each {|member|
       if member.synced==char
         member.frozen = false
         @character = member
       end}
   elsif char.is_a?(Game_Character)
     @character = char
   end
   # Set forcing flag. Will be disabled for recalculating on the fly.
   @forcing = true
   # Call a public method, since this method may need to be used again,
   # and "initialize" is private.
   setup(node, range, *callbacks)
 end
 
 
 def setup(node, range = 0, *callbacks)
   # Initialize the node we are trying to get to.
   @target = Node.new(node.x, node.y)
   @goal = @target.clone
   # Set beginning nodes and required variables.
   @start_node = Node.new(@character.x, @character.y)
   @nearest = Node.new(0, 0, 0, -1)
   @range, @found, @collisions = range, false, 0
   # Set callbacks for success and failure if included, else nil.
   @success_proc = callbacks[0]
   @failure_proc= callbacks[1]
   # Initialize sets to track open and closed nodes
   @open_set, @close_set = [@start_node], {}  
   # Find the optimal path
   calculate_path  
 end

 def calculate_path
   # Only do calculation if goal is actually passable, unless we only
   # need to get close or within range
   if @character.passable?(@goal.x, @goal.y, 0) || @range > 0 || @character.is_a?(Game_Member)
     # Initialize counter
     counter, wait = 0, 0
     until @open_set.empty?
       counter += 1
       # Give up if pathfinding is taking more than 500 iterations
       if counter >= $game_map.search_limiter
         @found = false
         break
       end
       # Get the node with lowest cost and add it to the closed list
       @current_node = get_current
       @close_set[[@current_node.x, @current_node.y]] = @current_node
       if @current_node == @goal ||
          (@range > 0 && @goal.in_range?(@current_node, @range) &&
          !@character.passable?(@goal.x, @goal.y,0))
         # We reached goal, exit the loop!
         @target = @goal
         @goal, @found = @current_node, true
         break
       else # if not goal
         # Keep track of the node with the lowest cost so far
         if @current_node.heuristic < @nearest.heuristic ||
           @nearest.heuristic < 1
           @nearest = @current_node
         end
         # Get adjacent nodes and check if they can be added to the open list
         neighbor_nodes(@current_node).each {|neighbor|
           # Skip Node if it already exists in one of the lists.
           next if can_skip?(neighbor)
           # Add node to open list following the binary heap conventions
           @open_set.push(neighbor)
           arrange(@open_set.size - 1)
         }
       end
     end
   end
   # If no path was found, see if we can get close to goal
   unless @found
     if @range > 0 && @nearest.heuristic > 0  
       # Create an alternate path.
       setup(@nearest, @range, @success_proc, @failure_proc)
     elsif @failure_proc != nil && (($game_map.collision_retry == 0) ||
       (@collisions > $game_map.collision_retry))
       # If out of retries, call the Proc for failure if defined
       @failure_proc.call
     end
   end
   # Create the move route using the generated path
   create_move_route
 end

 def create_move_route
   # There's no path to generate if no path was found
   return if !@found
   # Create a new move route that isn't repeatable
   @route = RPG::MoveRoute.new
   @route.repeat = false
   # Generate path by starting from goal and following parents
   node = @goal
   while node.parent
     # Get direction from parent to node as RPG::MoveCommand
     code = case direction(node.parent.x, node.parent.y, node.x, node.y)
     when 2 then 4 # Up
     when 4 then 3 # Left
     when 6 then 2 # Right
     when 8 then 1 # Down
     else; 0
     end
     # Add movement code to the start of the array
     @route.list.unshift(RPG::MoveCommand.new(code)) if code != 0
     node = node.parent
   end
   # If the path should be assigned to the character
   if (@forcing && !@route.list.empty?)
     @collisions = 0
     @character.paths.push(self)
     @character.force_move_route(@route) if @character.paths.size == 1
   end
   # Reset forcing flag if needed
   @forcing = true
   # Return the constructed RPG::MoveRoute
   return @route
 end
 
 def arrange(index)
   # Rearrange nodes in the open_set
   while index > 0
     # Break loop unless current item's cost is less than parent's
     break if @open_set[index].score > @open_set[index / 2].score
     # Bring lowest value to the top.
     temp = @open_set[index / 2]
     @open_set[index / 2] = @open_set[index]
     @open_set[index] = temp
     index /= 2
   end
 end
 
 def get_current
   return if @open_set.empty?
   return @open_set[0] if @open_set.size == 1
   # Set current node to local variable and replace it with the last
   current = @open_set[0]
   @open_set[0] = @open_set.pop
   # Loop and rearrange array according to the A* algorithm until done.
   y = 0  
   loop {
     x = y
     # If two children exist
     if 2 * x + 1 < @open_set.size
       if @open_set[2 * x].score <= @open_set[x].score
         y = 2 * x
         if @open_set[2 * x + 1].score <= @open_set[y].score
           y = 2 * x + 1
         end
       end
     # If only one child exists
     elsif 2 * x < @open_set.size &&
       @open_set[2 * x].score <= @open_set[x].score
       y = 2 * x
     end
     # Swap a child if it is less than the parent.
     break if x == y
     temp = @open_set[x]
     @open_set[x] = @open_set[y]
     @open_set[y] = temp
   }
   # Return the original first node (which was removed)
   return current
 end

 def direction(x1, y1, x2, y2)
   # Return the numerical direction between coordinates.
   return 6 if x1 > x2 # Right
   return 4 if x1 < x2 # Left
   return 2 if y1 > y2 # Bottom
   return 8 if y1 < y2 # Top
   return 0            
 end
 
 def neighbor_nodes(node)
   # Create array to hold the nodes, then check each direction.
   nodes = []
   nodes.push(get_neighbor(node.x + 1, node.y, node)) # Right
   nodes.push(get_neighbor(node.x - 1, node.y, node)) # Left
   nodes.push(get_neighbor(node.x, node.y + 1, node)) # Down
   nodes.push(get_neighbor(node.x, node.y - 1, node)) # Up
   # Remove any nil elements, then return results.
   return nodes.compact
 end
 
 def get_neighbor(x, y, parent)
   # Calculate direction, return new node if passable.
   direction = direction(x, y, parent.x, parent.y)
   if @character.passable?(parent.x, parent.y, direction)
     # The heuristic is simply the distance
     heuristics = ((x - @goal.x).abs + (y - @goal.y).abs)
     return Node.new(x, y, parent, parent.cost + 1, heuristics)
   end
 end
 
 def can_skip?(node)
   # Branch by if node is in either the open or closed set.
   if @open_set.include?(node)
     index = @open_set.index(node)
     return true if @open_set[index].score <= node.score
     # Swap them and update list order
     @open_set[index] = node
     arrange(index)
     return true
   elsif @close_set[[node.x, node.y]] != nil
     # If the existing passed node has a lower score than this one.
     return true if @close_set[[node.x, node.y]].score <= node.score
     # Update the existing node
     @close_set[[node.x, node.y]] = node
   end
   # Return false if no criteria was met.
   return false
 end
end

#==============================================================================
# ** Game_Character
#==============================================================================

class Game_Character
 
 attr_accessor :paths
 attr_accessor :move_route_forcing
 attr_accessor :move_route

 alias zer0_pathfinding_init initialize
 def initialize
   # Add public instance variable for paths
   @paths = []
   # Original method
   zer0_pathfinding_init
 end
 
 def next_route
   # Stop any custom move route that may be occuring.
   if @move_route != nil
     # Set index and disable forcing of current route
     @move_route_index = @move_route.list.size
     @move_route_forcing = false
     # Reset to what it was originally
     @move_route = @original_move_route
     @move_route_index = @original_move_route_index
     @original_move_route = nil
   end
   # Remove first path from the paths array.
   @paths.shift
   # If there is another path to follow...
   if @paths[0] != nil
     # Setup path again to reflect any changes since original creation
     @forcing = false
     @paths[0].setup(@paths[0].target, @paths[0].range,
       @paths[0].success_proc, @paths[0].failure_proc)
     force_move_route(@paths[0].route) if @paths[0].found
   end
 end
 
 alias zer0_recalculate_paths_move move_type_custom
 def move_type_custom
   if $game_map.recalculate_paths
     # Interrupt if not stopping
     return if jumping? || moving?
     # Loop until finally arriving at move command list
     while @move_route_index < @move_route.list.size
       # Get the move command at index
       command = @move_route.list[@move_route_index]
       # If command code is 0 (end of list)
       if command.code == 0
         # If [repeat action] option is ON
         if @move_route.repeat
           # Reset move route index to the top of the list
           @move_route_index = 0
         end
         # If [repeat action] option is OFF
         unless @move_route.repeat
           # If move route is forced and not repeating
           if @move_route_forcing and not @move_route.repeat
             # The move route is no longer forced (moving ended)
             @move_route_forcing = false
             # Restore original move route
             @move_route = @original_move_route
             @move_route_index = @original_move_route_index
             @original_move_route = nil
             # If there was a path to follow and we reached goal
             if @paths[0] != nil
               if self.x == @paths[0].goal.x &&
                 y == @paths[0].goal.y && @paths[0].success_proc
                 # Call success Proc if goal is reached and it is defined.
                 @paths[0].success_proc.call
               end
               next_route
             end
           end
           # Clear stop count
           @stop_count = 0
         end
         return
       end # if command.code == 0
       # For move commands (from move down to jump)
       if command.code <= 14
         # Branch by command code
         case command.code
         when 1 then move_down                 # Move down
         when 2 then move_left                 # Move left
         when 3 then move_right                # Move right
         when 4 then move_up                   # Move up
         when 5 then move_lower_left           # Move lower left
         when 6 then move_lower_right          # Move lower right
         when 7 then move_upper_left           # Move upper left
         when 8 then move_upper_right          # Move upper right
         when 9 then move_random               # Move random
         when 10 then move_toward_player       # Move toward player
         when 11 then move_away_from_player    # Move away from player
         when 12 then move_forward             # Step forward
         when 13 then move_backward            # Step backward
         when 14 then jump(command.parameters[0], command.parameters[1]) # Jump
         end
         # If movement failure occurs when "Ignore If Can't Move" is unchecked.
         if !@move_route.skippable && !moving? && !jumping?
           # If path is current and collision limit is not reached
           if @paths[0] != nil &&
             @paths[0].collisions < $game_map.collision_retry
             # Setup path again to update starting location.
             # original goal node is used because pathfinding changes
             # the goal node to current node
             goal, range = @paths[0].target, @paths[0].range
             reach = @paths[0].success_proc
             fail = @paths[0].failure_proc
             counter = @paths[0].collisions + 1
             # Find another path to goal
             @paths[0] = Pathfind.new(goal, self, range, reach, fail)
             @paths[0].collisions = counter
             force_move_route(@paths[0].route) if @paths[0].found
             # Wait a bit before starting to follow the new path
             @wait_count = 6
             return
           elsif paths[0] != nil
             # Call failure Proc if defined and set move index.
             @move_route_index = @move_route.list.size
             @paths[0].failure_proc.call if @paths[0].failure_proc != nil
             next_route
           end
           # End method
           return
         end
         # Advance index
         @move_route_index += 1
         return
       end # if command.code <= 14
       # If waiting
       if command.code == 15
         # Set wait count (from provided parameter)
         @wait_count = command.parameters[0] * 2 - 1
         @move_route_index += 1
         return
       end # if command.code == 15
       # If direction change (turning) command
       if command.code >= 16 and command.code <= 26
         # Branch by command code
         case command.code
         when 16 then turn_down                      # Turn down
         when 17 then turn_left                      # Turn left
         when 18 then turn_right                     # Turn right
         when 19 then turn_up                        # Turn up
         when 20 then turn_right_90                  # Turn 90° right
         when 21 then turn_left_90                   # Turn 90° left
         when 22 then turn_180                       # Turn 180°
         when 23 then turn_right_or_left_90          # Turn 90° right or left
         when 24 then turn_random                    # Turn at Random
         when 25 then turn_toward_player             # Turn toward player
         when 26 then turn_away_from_player          # Turn away from player
         end
         @move_route_index += 1
         return
       end
       # If other command (commands that don't 'return')
       if command.code >= 27
         # Branch by command code
         case command.code
         when 27                                              # Switch ON
           $game_switches[command.parameters[0]] = true
           $game_map.need_refresh = true
         when 28                                              # Switch OFF
           $game_switches[command.parameters[0]] = false
           $game_map.need_refresh = true
         when 29 then @move_speed = command.parameters[0]     # Change speed
         when 30 then @move_frequency = command.parameters[0] # Change freq
         when 31 then @walk_anime = true                      # Move ON
         when 32 then @walk_anime = false                     # Move OFF
         when 33 then @step_anime = true                      # Stop ON
         when 34 then @step_anime = false                     # Stop OFF
         when 35 then @direction_fix = true                   # Direction ON
         when 36 then @direction_fix = false                  # Direction OFF
         when 37 then @through = true                         # Through ON
         when 38 then @through = false                        # Through OFF
         when 39 then @always_on_top = true                   # On top ON
         when 40 then @always_on_top = false                  # On top OFF
         when 41                                              # Change Graphic
           # Can't change into a tile
           @tile_id = 0
           @character_name = command.parameters[0]
           @character_hue = command.parameters[1]
           # Update direction
           if @original_direction != command.parameters[2]
             @direction = command.parameters[2]
             @original_direction = @direction
             @prelock_direction = 0
           end
           # Update frame
           if @original_pattern != command.parameters[3]
             @pattern = command.parameters[3]
             @original_pattern = @pattern
           end
         when 42 then @opacity = command.parameters[0]        # Change Opacity
         when 43 then @blend_type = command.parameters[0]     # Change Blending
         when 44 then $game_system.se_play(command.parameters[0]) # Play SE
         when 45 then result = eval(command.parameters[0])    # Script
         end
         # Increment move index.
         @move_route_index += 1
       end
     end
   else
     # Original method
     zer0_recalculate_paths_move
   end
 end
end

#==============================================================================
# ** Node
#==============================================================================

class Node

 attr_accessor :x                      
 attr_accessor :y                      
 attr_accessor :parent                  
 attr_accessor :cost                
 attr_accessor :heuristic                  

 def initialize(x, y, parent = nil, cost = 0, heuristic = 0)
   # Set public instance variables.
   @x, @y, @parent, @cost, @heuristic = x, y, parent, cost, heuristic
 end

 def score
   # Return the current "score" of this node
   return @cost + @heuristic
 end
 
 def in_range?(node, range)
   # Return true/false if Nodes are within RANGE of each other.
   return (@x - node.x).abs + (@y - node.y).abs <= range
 end

 def ==(node)
   # Returns true/false of whether self and other are equal.
   return ((node.is_a?(Node)) && (node.x == @x) && (node.y == @y))
 end
end

#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# Caterpillar by Blizzard
# Version: 2.2b
# Type: Game Experience Improvement
# Date: 7.3.2007
# Date v1.01b: 7.3.2007
# Date v2.0: 7.8.2007
# Date v2.0b: 8.8.2007
# Date v2.1b: 17.2.2008
# Date v2.11b: 22.2.2008
# Date v2.2b: 1.11.2008
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#
# new in v1.01b:
#   - now events can't go through your party members anymore
#
# new in v2.0:
#   - completely overworked and improved
#
# new in v2.0b:
#   - improved coding and made it work more convenient
#   - fixed a few glitches
#   - added DEAD_DISPLAY option
#   - removed stop animation override upon the player character
#
# new in v2.1b:
#   - fixed bug where an empty party would cause a crash
#
# new in v2.11b:
#   - fixed a minor compatibility glitch with Blizz-ABS
#
# new in v2.2b:
#   - improved coding and made it work more convenient
#   - fixed the bug where deactivating the caterpillar wouldn't work properly
#
#
# Compatibility:
#
#   93% compatible with SDK v1.x. 60% compatible with SDK v2.x. You might
#   experience problems with pixel movement scripts or map graphic manipulating
#   scripts. Blizz-ABS disables this add-on automatically and uses the
#   Blizz-ABS Caterpillar system.
#
#
# Features:
#
#   - your party members follow you on the map
#   - less code than other caterpillar scripts
#   - use $game_player.update_buffer('reset') if you need all party members to
#     gather around the player
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=

#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

# max number of party members
MAX_PARTY = 4
# actor IDs where the actor is animated even when not walking
ANIMATED_IDS = []
# 0 - shows all characters; 1 - shows "ghosts"; 2 - removes from caterpillar
DEAD_DISPLAY = 0

#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

#==============================================================================
# Game_Character
#==============================================================================
   
class Game_Character
 
 alias passable_caterpillar_later? passable?
 def passable?(x, y, d)
   result = passable_caterpillar_later?(x, y, d)
   new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
   new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
   unless @through
     $game_player.members.each {|member|
         if member.character_name != '' && member.x == new_x && member.y == new_y && member.through==false
           return false
         end}
   end
   return result if $BlizzABS && BlizzABS::VERSION >= 1.01
   return result if self.is_a?(Game_Player) || self.is_a?(Game_Member)
   new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
   new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
   unless @through
     $game_player.members.each {|member|
         if member.character_name != '' && member.x == new_x && member.y == new_y
           return false
         end}
   end
   return result
 end
 
end

#==============================================================================
# Game_Player
#==============================================================================
   
class Game_Player
 
 attr_reader :members
 attr_reader :move_speed
 attr_accessor :active_member
 attr_accessor :return_buffer
 
 alias init_caterpillar_later initialize
 def initialize
   init_caterpillar_later
   @active_member = true
   @members = []
   @return_buffer = []
   @lastdirection = 0
   @directionpause = 4
   @directionframe = 0
   (1...MAX_PARTY).each {|i| @members.push(Game_Member.new(i))} unless $BlizzABS
 end
 
 alias upd_caterpillar_later update
 def update
   upd_caterpillar_later
   refresh if DEAD_DISPLAY > 0
   @members.each {|member| member.update}
   if $game_system.CATERPILLAR && ANIMATED_IDS.include?(actor.id)
     @step_anime = true
   end
 end
 
 alias straighten_caterpillar_later straighten
 def straighten
   straighten_caterpillar_later
   @members.each {|member| member.straighten}
 end
 
 alias refresh_caterpillar refresh
 def refresh
   unless $game_system.CATERPILLAR
     refresh_caterpillar
     return
   en d
   act, $game_party.actors[0] = $game_party.actors[0], actor
   $game_party.actors.pop if $game_party.actors[0] == nil
   refresh_caterpillar
   return if actor == nil
   $game_party.actors[0] = act
   if actor.dead? && DEAD_DISPLAY == 1
     @opacity = Graphics.frame_count % 4 / 2 * 255
     @blend_type = 1
   end
 end
 
 def actor
   if DEAD_DISPLAY > 0
     $game_party.actors.each {|actor| return actor unless actor.dead?}
   end
   return $game_party.actors[0]
 end
 
 def update_buffer(next_move)
   if next_move == nil
     @members.each {|member| member.buffer = []}
   else
     @members.each {|member| member.update_buffer(
         next_move == 'reset' ? nil : next_move)}
   end
 end
 
 def update_return_buffer(move)
   return_buffer.push(move)
   if return_buffer.size > 3
     return_buffer.delete_at(0)
   end
 end
 
 alias move_down_caterpillar_later move_down
 def move_down(turn_enabled = true)
   update_buffer(2) if passable?(@x, @y, 2)
   update_return_buffer(2) if passable?(@x, @y, 2)
   move_down_caterpillar_later
 end
 
 alias move_left_caterpillar_later move_left
 def move_left(turn_enabled = true)
   update_buffer(4) if passable?(@x, @y, 4)
   update_return_buffer(4) if passable?(@x, @y, 4)
   move_left_caterpillar_later
 end
 
 alias move_right_caterpillar_later move_right
 def move_right(turn_enabled = true)
   update_buffer(6) if passable?(@x, @y, 6)
   update_return_buffer(6) if passable?(@x, @y, 6)
   move_right_caterpillar_later
 end
 
 alias move_up_caterpillar_later move_up
 def move_up(turn_enabled = true)
   update_buffer(8) if passable?(@x, @y, 8)
   update_return_buffer(8) if passable?(@x, @y, 8)
   move_up_caterpillar_later
 end
 
 alias move_lower_left_caterpillar_later move_lower_left
 def move_lower_left
   if passable?(@x, @y, 2) && passable?(@x, @y + 1, 4) ||
      passable?(@x, @y, 4) && passable?(@x - 1, @y, 2)
     update_buffer(1)
   end
   move_lower_left_caterpillar_later
 end
 
 alias move_lower_right_caterpillar_later move_lower_right
 def move_lower_right
   if passable?(@x, @y, 2) && passable?(@x, @y + 1, 6) ||
      passable?(@x, @y, 6) && passable?(@x + 1, @y, 2)
     update_buffer(3)
   end
   move_lower_right_caterpillar_later
 end
 
 alias move_upper_left_caterpillar_later move_upper_left
 def move_upper_left
   if passable?(@x, @y, 8) && passable?(@x, @y - 1, 4) ||
      passable?(@x, @y, 4) && passable?(@x - 1, @y, 8)
     update_buffer(7)
   end
   move_upper_left_caterpillar_later
 end
 
 alias move_upper_right_caterpillar_later move_upper_right
 def move_upper_right
   if passable?(@x, @y, 8) && passable?(@x, @y - 1, 6) ||
      passable?(@x, @y, 6) && passable?(@x + 1, @y, 8)
     update_buffer(9)
   end
   move_upper_right_caterpillar_later
 end
 
 alias jump_caterpillar_later jump
 def jump(x_plus, y_plus)
   if (x_plus != 0 || y_plus != 0) && passable?(@x + x_plus, @y + y_plus, 0)
     update_buffer([x_plus, y_plus])
   end
   jump_caterpillar_later(x_plus, y_plus)
 end
 
 alias moveto_caterpillar moveto
 def moveto(x, y)
   update_buffer(nil)
   moveto_caterpillar(x, y)
   @members.each {|member|
   unless member.frozen==true
       member.moveto(x, y)
       case @direction
         when 2 then member.turn_down
         when 4 then member.turn_left
         when 6 then member.turn_right
         when 8 then member.turn_up
       end
   end}
 end
 
 def syncevent(member,eventid)
   mevent = $game_player.members[member]
   event = $game_map.events[eventid]
   mevent.synced=eventid
 end
 
 alias check_member_event_there check_event_trigger_there
 def check_event_trigger_there(triggers)
   result = false
   # If event is running
   if $game_system.map_interpreter.running?
     return result
   end
   result = check_member_event_there(triggers)
   new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
   new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
   for member in $game_player.members
     # If event coordinates and triggers are consistent
     if member.synced != nil
       event = $game_map.events[member.synced]
       if member.x == new_x && member.y == new_y && triggers.include?(event.trigger)
         # If starting determinant is front event (other than jumping)
         #if not member.jumping? and not member.over_trigger?
           member.lock
           event.start
           result = true
         #end
       end
     end
   end
 return result
end

 def calc_return_path(index)
   nodex=$game_player.x
   nodey=$game_player.y
   b = $game_player.members[index]
   rb = return_buffer.reverse
   if index > 0
   for i in 0...index
     move = rb[i]
     nodex +=1 if move == 4
     nodex -=1 if move == 6
     nodey -=1 if move == 2
     nodey +=1 if move == 8
   end
 else
     move = rb[0]
     nodex +=1 if move == 4
     nodex -=1 if move == 6
     nodey -=1 if move == 2
     nodey +=1 if move == 8
   end
   b.buffer = []
   if index > 0
     for i in 0...index
       b.buffer.push(rb[i])
     end
   else
     b.buffer.push(rb[0])
   end
   return [nodex, nodey]
 end
 
end
 
#==============================================================================
# Game_Member
#==============================================================================

class Game_Member < Game_Character
 
 attr_accessor :buffer
 attr_accessor :frozen
 attr_accessor :synced
 attr_accessor :direction_fix
 attr_accessor :step_anime2
 attr_accessor :walk_anime
 attr_accessor :always_on_top
 
 def initialize(index)
   super()
   @frozen = false
   @synced = nil
   @direction_fix = false
   @step_anime2 = false
   @walk_anime = true
   @always_on_top = false
   @index, @force_movement, @buffer, @through = index, 0, [], true
 end
 
 def refresh
   unless $game_system.CATERPILLAR && actor != nil
     @character_name, @character_hue = '', 0
     return
   end
   @character_name = actor.character_name
   @character_hue = actor.character_hue
   if actor.dead? && DEAD_DISPLAY == 1
     @opacity, @blend_type = Graphics.frame_count % 4 / 2 * 255, 1
   else
     @opacity, @blend_type = 255, 0
   end
 end
 
 def actor
   case DEAD_DISPLAY
   when 0 then return $game_party.actors[@index]
   when 1
     alive = 0
     $game_party.actors.each {|actor| alive += 1 unless actor.dead?}
     if @index >= alive
       ind, flag = @index - alive, true
     else
       ind, flag = @index, false
     end
     $game_party.actors.each_index {|i|
         ind -= 1 if (flag == $game_party.actors[i].dead?)
         return $game_party.actors[i] if ind < 0}
   when 2
     ind = @index
     $game_party.actors.each_index {|i|
         ind -= 1 unless $game_party.actors[i].dead?
         return $game_party.actors[i] if ind < 0}
   end
   return nil
 end
 
 def update
   refresh
   @transparent = $game_player.transparent
   @move_speed = $game_player.move_speed
   @through = !@frozen
   unless moving? || @buffer.size <= @index && @force_movement <= 0 || @frozen == true
     if @buffer.size > 0
       move = @buffer.shift
       if move.is_a?(Array)
         jump(move[0], move[1])
       else
         case move
         when 1 then move_lower_left
         when 2 then move_down(true)
         when 3 then move_lower_right
         when 4 then move_left(true)
         when 6 then move_right(true)
         when 7 then move_upper_left
         when 8 then move_up(true)
         when 9 then move_upper_right
         end
       end
       @force_movement -= 1 if @force_movement > 0
     end
   end
   super
   @step_anime2 = @step_anime
   @step_anime = (ANIMATED_IDS.include?($game_party.actors[@index].id) || @step_anime2)
 end
 
 def update_buffer(next_move)
   if next_move == nil
     @force_movement = @buffer.size
   else
     @buffer.push(next_move)
     @force_movement = @buffer.size if next_move.is_a?(Array)
   end
 end
 
 def check_event_trigger_touch(x, y) # don't remove this, it's necessary...
 end
 
 def screen_z(height = 0)
   return (super - @index)
 end
 
end

#==============================================================================
# Spriteset_Map
#==============================================================================

class Spriteset_Map
 
 alias init_caterpillar_later initialize
 def initialize
   init_caterpillar_later
   return if $BlizzABS && BlizzABS::VERSION >= 1.01
   $game_player.members.each {|member|
       sprite = Sprite_Character.new(@viewport1, member)
       sprite.update
       @character_sprites.push(sprite)}
 end
 
end

#==============================================================================
# Scene_Map
#==============================================================================

class Scene_Map
 
 alias transfer_player_caterpillar_later transfer_player
 def transfer_player
   transfer_player_caterpillar_later
   return if $BlizzABS
   case $game_temp.player_new_direction
   when 2 then $game_player.members.each {|member| member.turn_down}
   when 4 then $game_player.members.each {|member| member.turn_left}
   when 6 then $game_player.members.each {|member| member.turn_right}
   when 8 then $game_player.members.each {|member| member.turn_up}
   end
 end
 
end

class Interpreter
 
 def command_209
   character = nil
   $game_player.members.each {|member|
     if member.synced == @parameters[0]
       character = member
       character.frozen = true
     end}
   # If no character exists
   if character == nil
     # Get character
     character = get_character(@parameters[0])
     # Continue
   end
   if character == nil
     return true
   end
   # Force move route
   character.force_move_route(@parameters[1])
   # Continue
   return true
 end
 
 alias command_end_member command_end
 def command_end
   command_end_member
   $game_player.members.each {|member|
   if member.synced == @event_id
     member.unlock
   end}
 end
 
end



Instructions

Instructions in script.


Compatibility


  • Not compatible with other Pathfinding scripts.

  • Requires Tons Of Addons, but Caterpillar boolean must be set in this script.

  • Rewrites Interpreter command 209. Place above any scripts that alias this method!





Credits and Thanks


  • ForeverZer0, for the original Pathfinding

  • Blizzard, for the original caterpillar script.

  • My girlfriend, for unwavering support and allowing me to indulge my insomnia




Author's Notes

Feel free to post any feedback/complaints/improvements. I know this thing is far from complete!

Enjoy!
5
General Discussion / [XP]A proposition
January 16, 2012, 03:33:22 pm
Hi guys.

As some of you may know I've been offline for a while. This lack of internet has resulted in some down-time from RMXP. But being back on the scene has given me an idea. I know ARC is being developed to mop the floor with RMXP but I can't help but think, with each new project that I start, that RMXP could do so well if it just had the features that everyone is looking for. So I'm making a proposition (as stated in the thread title). I know at one point there was a craze for Test Beds and script packages and I think that if RMXP had a decent enough upgrade then it might bring people back in who had previously left it for dead.

So I'm proposing a bundle of scripts/content to bring commonly requested features into RMXP so that people can use it without searching for content for hours on end. I'm tentatively calling it RMXP+. It is my aim to include features such as:


  • Caterpillar actors controllable with event commands which can be returned to the 'train' with the pathfinding script

  • My Perishable Items script

  • A charset animation system, for when facing a certain direction just isn't enough

  • A friendship/loyalty system

  • An event management system which incorporates the Advanced Pathfinding + carrots script and a multi-map management script to allow events to move between maps in a town based on a 'daily schedule'

  • An improved menu/GUI system

  • More terrain tags

  • A message system (I'm unsure whether ccoas UMS can be used for this or whether it's a no-go)

  • A Quest Log, probably based off of game_guys but with features requested on that thread

  • 'The' Achievements script

  • A Bestiary, possibly incorporated into a Codex type system detailing items/history/important characters.

  • An options menu



Of course I know the difficulty of promising a pack like this. It's not a small project and no doubt it won't be a smooth ride, so I was hoping for some feedback before I begin proper (at time of writing I'm partway through the caterpillar enhancement, utilising the modified pathfinding script).

So let me know what you think and based off of your feedback I'll decide whether or not to pursue this (some might say) impossible dream.

Toodle pip!
6
RMXP Script Database / [XP] Perishable Items
October 12, 2011, 10:48:31 pm
Perishable Items
Authors: mad.array
Version: 1.0a
Type: Custom Item System
Key Term: Custom Item System



Introduction

This script adds a 'best before date' to any item that you choose. After you have bought/found an item, it will only have a limited shelf life, before it goes off. Now your heroes can experience stomach bugs from drinking Potions that are past their Use By Date and experience the wonderful smell of musty old perfume!



Features


  • Lets Items 'go off', changing their effects

  • Each Item ID has it's own life expectency

  • Items can have multiple stages of freshness

  • Each instance of each item has its own timer before it goes off




Screenshots
No screenshots, as rotten items are not pleasant to look at!



Script

Insert below default scripts and above Main. Jiggle it about it if it doesn't work!
Spoiler: ShowHide

#==============================================================================
# Perishable Items (Version 1.0a) by mad.array
#------------------------------------------------------------------------------
#  Use this script to give your items a limited shelf life.
#  To use, add a 'rotten' version of your item in the database, then
#  find def calculate_perish_time and add a case for your original item number.
#  e.g. (Item 1 = Potion, Item 33 = Potion [Rotten])
#  ---------------
#  when 1
#     return 400
# ----------------
# This is the amount of time, in frames, that your item will last before going
# off. Now 400 frames is only 20 seconds, so I'd use a larger number.
#
# Next, find def rot_time and again add a case for your item. Only this time
# it will be returning the item that it will 'rot' into.
# e.g. 2
#  ---------------
#  when 1
#     return 33
# ----------------
#
# Now, enjoy. 400 Frames after picking up a Potion, it will be removed from
# the item screen and replaced with it's rotten replacement. You can have your
# rotten equivalent do anything that a normal item would do, so go nuts!
#==============================================================================

class Game_Party
 attr_accessor    :perishablelist
 
 alias perinitialize initialize
 def initialize
   perinitialize
   @perishablelist = []
 end
 
 alias perish_gain_item gain_item
 def gain_item(item_id, n)
   perish_gain_item(item_id, n)
   for i in 0...n
     pt = calculate_perish_time(item_id)
     if pt !=false
       pt += Graphics.frame_count
       @perishablelist[item_id] = [] if @perishablelist[item_id] == nil
       @perishablelist.push[item_id].push(pt)
     end
   end
 end
 
 alias perish_lose_item lose_item
 def lose_item(item_id, n)
   perish_lose_item(item_id, n)
   for i in 0...n
     @perishablelist[item_id].delete_at(0) if @perishablelist[item_id] != nil
   end
 end
 
 def calculate_perish_time(item_id)
   case item_id
   #when 1
     #return 400
   end
   return false
 end
end

class Window_Item < Window_Selectable
 
 alias perish_draw draw_item
 def draw_item(index)
   perish_draw(index)
   item = @data[index]
   if item.is_a?(RPG::Item) && $game_party.perishablelist[item.id] != nil
     number = $game_party.item_number(item.id)
     changeamt = 0
     for i in 0...number
       if $game_party.perishablelist[item.id][i] < Graphics.frame_count
         changeamt +=1
       end
     end
     if changeamt > 0
       $game_party.gain_item(rot_item(item.id), changeamt)
       $game_party.lose_item(item.id, changeamt)
       refresh
     end
   end
 end
 
 def rot_item(item_id)
   case item_id
   #when 1
     #return 33
   end
   return false
 end
end



Instructions

Instructions are included in the script, but I'll put some here as well.

Once the script is inserted, create a 'rotten' version of your perishables items in the Database and adjust the properties as you see fit. For example have a Potion [Rotten] take away 500 HP rather than restoring it. Then, in the script, find the def calculate_rot_time and add a case for your original item id, returning the number of frames it will take to go off. In this example we'll be using the Potion:


when 1
   return 400


Note that by default there are 20 frames per second in RMXP, so the Potion would go off 20 seconds after you pick it up... I'd advise using a larger number.

Now that that's done, find def rot_time and again add a case with your original item id. Only this time we'll be returning the item that will be replacing our stinky Potion. In this example it's Item 33 (which doesn't exist by default in the Database):


when 1
   return 33


Et voila! Each Potion that you pick up will go off after 20 seconds... so I'd use them fast!


Compatibility

Not tested for compatability. May not work with other Custom Item Systems. Contact me if you are having compatability issues and if I can I'll help out.


Credits and Thanks

Please credit mad.array if you use this script.

newolds Configuration program can be found here http://www.megaupload.com/?d=XT8W253I
If you use it, give credit to him for making your life less rotten! (See what I did there?!)



Author's Notes

I'm sure there is a better way of doing this, so if you can think of another method then please contact me.
7
Advanced Pathfinding & Carrots
Authors: ForeverZer0, modifications by mad.array
Version: 1.01a
Type: Path finding by Event Name, includes array support.
Key Term: Custom Movement System



Introduction

A modification of ForeverZer0s Advanced Pathfinding script (Found here). As well as using tile co-ordinates, the path finding target can now be defined as an event with a specific name. An array of event names can also be input and will be randomly selected.

If multiple events with the given name are found, the script will find the nearest instance and move to that example. Note that unless the target events Through flag is set, you will need to have a range of 1 or more.

The main reason I decided to work on this was to help achieve the feeling of a busy town. I wanted people to have their own little routines and go to specific places such as market stalls and blacksmiths. But how to do it? Well after looking at Pathfinding in general I stumbled accross ForeverZer0s script and started tinkering (I actually came accross it while researching something unrelated, but that just personifies my inability to focus).


Features


  • All the features of ForeverZer0s Advanced Pathfinding.

  • Move to location of another event.

  • Will find the nearest instance of event with the right name.

  • Can choose between events with different names.




Screenshots

No screen shots, as they don't really show movement.


Demo

No demo at the moment. Sorry!


Script

Insert above Main & below default scripts.
Spoiler: ShowHide

#=begin
#+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
# Advanced Pathfinding
# Author: ForeverZer0, mad.array
# Version: 1.0
# Date: 10.12.2011
#+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
#
# Introduction:
#   This is an advanced an highly inteligent pathfinding system. It allows for
#   the user to either through script or script call quickly and easily have
#   events or the game player automatically walk a path to a given set of
#   coordinates. The system is smart enough to quickly find paths through
#   relatively complex areas, and asjust on the fly for any obstacle that moves
#   to block its path. I used the A* algorithm, basic search algorithm used
#   often for robotics. More on this algorithm can be read about here:
#
#               http://en.wikipedia.org/wiki/A*_search_algorithm
#
# Features:
#   - Fast and intelligent pathfinding
#   - Easy to use script calls
#   - Optional "range" parameter can have character find alternate locations
#     if the preferred one is blocked and they are within the given range.
#   - Optional callbacks can be given to have something execute if when the
#     character reaches its goal, or when it fails to do so.
#
# Instructions:
#   - Place script below default scripts, and above "Main".
#   - Use the following script call:
#
#     pathfind(X, Y, CHARACTER, RANGE, SUCCESS_PROC, FAIL_PROC)
#    
#     The X and Y are the only required arguments. The others can be omitted.
#    
#     X - The x-coordinate to pathfind to. If X is a string or array then
#         strings must be contained within "quotation marks" and the array
#         within [square brackets].
#     Y - The y-coordinate to pathfind to. If using a string or array, DO NOT
#         leave Y blank. It will cause the script to crash.
#
#     CHARACTER - Either an instance of the character ($game_player,
#                 $game_map.events[ID], etc) or the ID of a character. The ID
#                 will be the event ID. Use -1 for the game player.
#
#     SUCCESS_PROC - A Proc object that will be executed when the player
#                    reaches the defined coordinates.
#     FAILURE_PROC - A Proc object that will be executed when the player
#                    cannot reach the defined coordinates.
#
#   - As default, the pathfinder will make 35 attempts to recalculate a route
#     that gets blocked. This value can be changed in game with the script
#     call:
#           $game_map.collision_retry = NUMBER
#
#     You can change the default value if desired by looking down to the first
#     class below in the main script.
#   - For longer pathfind routes, it is sometimes necessary to reset the
#     search limiter. This may cause increased lag when an object blocks the
#     character from being able to move, but will increase the range that the
#     system can work with. Use the following script call:
#
#         $game_map.search_limiter = NUMBER  (Default 1000)
#
#   - If you are experiencing any compatibility problems, go to the Game_Map
#     class below and set @recalculate_paths to false. This will take away some
#     of the efficiency of recalculating collisions, but will improve may fix
#     your problem.
#
# Compatibility:
#   Highly compatible. May experience issues with Custom Movement scripts,
#   but even then, it is unlikely.
#
# Credits/Thanks:
#   - ForeverZer0, for the script
#   - Special thanks to Jragyn for help making the big maze for the demo and
#     help testing.
#   - Credit goes to the Peter Hart, Nils Nilsson and Bertram Raphael for the
#     original search algorithm that was implemented
#
#+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

#===============================================================================
# ** Game_Map
#===============================================================================

class Game_Map
 
 attr_accessor :collision_retry
 attr_accessor :recalculate_paths
 attr_accessor :search_limiter
 
 alias zer0_pathfinding_init initialize
 def initialize
   # Initialize instance variables used for pathfinding.
   @collision_retry = 35
   @recalculate_paths = true
   @search_limiter = 1000
   # Original method
   zer0_pathfinding_init
 end
end

#===============================================================================
# ** Interpreter
#===============================================================================

class Interpreter
 
 def pathfind(x, y, *args)
   @x = x
   @y = y
   args[0] = @event_id if args[0] == nil
   args[1] = 0 if args[1] == nil
   if @x.is_a?(Array)
     decidepath(@x, @y, @args)
   end
   findpathevent(@x,@y, args)
   Pathfind.new(Node.new(@x, @y), *args)
 end

 def decidepath(x, y, args)
   r = rand(100) + 1
   for i in 0...x.size
     targ1 = 1 + (100/x.size) * i
     targ2 = (100/x.size) * (i +1)
     if r >= targ1 && r <=targ2
       @x=x[i]
     end
   end
 end

 def findpathevent(x, y, args)
   xs = []
   ys = []
   proxx = []
   proxy = []
   distance = []
   chosen = nil
   if x.is_a?(String)
     for event in $game_map.events.values
       if event.name == x
         xs.push(event.x)
         ys.push(event.y)
       end
     end
     if args[0] >  0
       runnerx = $game_map.events[args[0]].x
       runnery = $game_map.events[args[0]].y
     else
       runnerx = $game_player.x
       runnery = $game_player.y
     end
     if xs.size > 1
       for i in 0...xs.size# - 1
         proxx[i] = runnerx - xs[i]
         proxy[i] = runnery - ys[i]
         proxx[i] *= -1 if proxx[i] <0
         proxy[i] *= -1 if proxy[i] <0
         if proxx[i] > proxy[i]
           distance[i] = proxx[i] - proxy[i]
         elsif proxx[i] < proxy[i]
           distance[i] = proxy[i] - proxx[i]
         elsif proxx[i]==0
           distance[i] = proxy[i]
         elsif proxy[i]==0 || proxy[i] == proxx[i]
           distance[i] = proxx[i]
         end
       end
       j = 0
       while chosen == nil
         chosen = distance.index(j)
         j+=1
       end
         @x = xs[chosen]
         @y = ys[chosen]
     else
       @x = xs[0]
       @y = ys[0]
     end
   end
 end
end


class Game_Event
 
def name
  return @event.name
end
end

#==============================================================================
# ** Pathfind
#==============================================================================

class Pathfind

 attr_reader   :route                  
 attr_accessor :range  
 attr_reader   :goal
 attr_reader   :found
 attr_reader   :character                                
 attr_accessor :success_proc          
 attr_accessor :failure_proc        
 attr_accessor :target    
 attr_accessor :collisions      
 
 def initialize(node, char = -1, range = 0, *callbacks)
   # Set the character. Can either us an ID or an instance of a Game_Character.
   # A value of -1, which is default, is the Game_Player.
   if char.is_a?(Integer)
     @character = (char == -1) ? $game_player : $game_map.events[char]
   elsif char.is_a?(Game_Character)
     @character = char
   end
   # Set forcing flag. Will be disabled for recalculating on the fly.
   @forcing = true
   # Call a public method, since this method may need to be used again,
   # and "initialize" is private.
   setup(node, range, *callbacks)
 end
 
 
 def setup(node, range = 0, *callbacks)
   # Initialize the node we are trying to get to.
   @target = Node.new(node.x, node.y)
   @goal = @target.clone
   # Set beginning nodes and required variables.
   @start_node = Node.new(@character.x, @character.y)
   @nearest = Node.new(0, 0, 0, -1)
   @range, @found, @collisions = range, false, 0
   # Set callbacks for success and failure if included, else nil.
   @success_proc = callbacks[0]
   @failure_proc= callbacks[1]
   # Initialize sets to track open and closed nodes
   @open_set, @close_set = [@start_node], {}  
   # Find the optimal path
   calculate_path  
 end

 def calculate_path
   # Only do calculation if goal is actually passable, unless we only
   # need to get close or within range
   if @character.passable?(@goal.x, @goal.y, 0) || @range > 0
     # Initialize counter
     counter, wait = 0, 0
     until @open_set.empty?

       counter += 1
       # Give up if pathfinding is taking more than 500 iterations
       if counter >= $game_map.search_limiter
         @found = false
         break
       end
       # Get the node with lowest cost and add it to the closed list
       @current_node = get_current
       @close_set[[@current_node.x, @current_node.y]] = @current_node
       if @current_node == @goal ||
          (@range > 0 && @goal.in_range?(@current_node, @range) &&
          !@character.passable?(@goal.x, @goal.y,0))
         # We reached goal, exit the loop!
         @target = @goal
         @goal, @found = @current_node, true
         break
       else # if not goal
         # Keep track of the node with the lowest cost so far
         if @current_node.heuristic < @nearest.heuristic ||
           @nearest.heuristic < 1
           @nearest = @current_node
         end
         # Get adjacent nodes and check if they can be added to the open list
         neighbor_nodes(@current_node).each {|neighbor|
           # Skip Node if it already exists in one of the lists.
           next if can_skip?(neighbor)
           # Add node to open list following the binary heap conventions
           @open_set.push(neighbor)
           arrange(@open_set.size - 1)
         }
       end
     end
   end
   # If no path was found, see if we can get close to goal
   unless @found
     if @range > 0 && @nearest.heuristic > 0  
       # Create an alternate path.
       setup(@nearest, @range, @success_proc, @failure_proc)
     elsif @failure_proc != nil && (($game_map.collision_retry == 0) ||
       (@collisions > $game_map.collision_retry))
       # If out of retries, call the Proc for failure if defined
       @failure_proc.call
     end
   end
   # Create the move route using the generated path
   create_move_route
 end

 def create_move_route
   # There's no path to generate if no path was found
   return if !@found
   # Create a new move route that isn't repeatable
   @route = RPG::MoveRoute.new
   @route.repeat = false
   # Generate path by starting from goal and following parents
   node = @goal
   while node.parent
     # Get direction from parent to node as RPG::MoveCommand
     code = case direction(node.parent.x, node.parent.y, node.x, node.y)
     when 2 then 4 # Up
     when 4 then 3 # Left
     when 6 then 2 # Right
     when 8 then 1 # Down
     else; 0
     end
     # Add movement code to the start of the array
     @route.list.unshift(RPG::MoveCommand.new(code)) if code != 0
     node = node.parent
   end
   # If the path should be assigned to the character
   if (@forcing && !@route.list.empty?)
     @collisions = 0
     @character.paths.push(self)
     @character.force_move_route(@route) if @character.paths.size == 1
   end
   # Reset forcing flag if needed
   @forcing = true
   # Return the constructed RPG::MoveRoute
   return @route
 end
 
 def arrange(index)
   # Rearrange nodes in the open_set
   while index > 0
     # Break loop unless current item's cost is less than parent's
     break if @open_set[index].score > @open_set[index / 2].score
     # Bring lowest value to the top.
     temp = @open_set[index / 2]
     @open_set[index / 2] = @open_set[index]
     @open_set[index] = temp
     index /= 2
   end
 end
 
 def get_current
   return if @open_set.empty?
   return @open_set[0] if @open_set.size == 1
   # Set current node to local variable and replace it with the last
   current = @open_set[0]
   @open_set[0] = @open_set.pop
   # Loop and rearrange array according to the A* algorithm until done.
   y = 0  
   loop {
     x = y
     # If two children exist
     if 2 * x + 1 < @open_set.size
       if @open_set[2 * x].score <= @open_set[x].score
         y = 2 * x
         if @open_set[2 * x + 1].score <= @open_set[y].score
           y = 2 * x + 1
         end
       end
     # If only one child exists
     elsif 2 * x < @open_set.size &&
       @open_set[2 * x].score <= @open_set[x].score
       y = 2 * x
     end
     # Swap a child if it is less than the parent.
     break if x == y
     temp = @open_set[x]
     @open_set[x] = @open_set[y]
     @open_set[y] = temp
   }
   # Return the original first node (which was removed)
   return current
 end

 def direction(x1, y1, x2, y2)
   # Return the numerical direction between coordinates.
   return 6 if x1 > x2 # Right
   return 4 if x1 < x2 # Left
   return 2 if y1 > y2 # Bottom
   return 8 if y1 < y2 # Top
   return 0            
 end
 
 def neighbor_nodes(node)
   # Create array to hold the nodes, then check each direction.
   nodes = []
   nodes.push(get_neighbor(node.x + 1, node.y, node)) # Right
   nodes.push(get_neighbor(node.x - 1, node.y, node)) # Left
   nodes.push(get_neighbor(node.x, node.y + 1, node)) # Down
   nodes.push(get_neighbor(node.x, node.y - 1, node)) # Up
   # Remove any nil elements, then return results.
   return nodes.compact
 end
 
 def get_neighbor(x, y, parent)
   # Calculate direction, return new node if passable.
   direction = direction(x, y, parent.x, parent.y)
   if @character.passable?(parent.x, parent.y, direction)
     # The heuristic is simply the distance
     heuristics = ((x - @goal.x).abs + (y - @goal.y).abs)
     return Node.new(x, y, parent, parent.cost + 1, heuristics)
   end
 end
 
 def can_skip?(node)
   # Branch by if node is in either the open or closed set.
   if @open_set.include?(node)
     index = @open_set.index(node)
     return true if @open_set[index].score <= node.score
     # Swap them and update list order
     @open_set[index] = node
     arrange(index)
     return true
   elsif @close_set[[node.x, node.y]] != nil
     # If the existing passed node has a lower score than this one.
     return true if @close_set[[node.x, node.y]].score <= node.score
     # Update the existing node
     @close_set[[node.x, node.y]] = node
   end
   # Return false if no criteria was met.
   return false
 end
end

#==============================================================================
# ** Game_Character
#==============================================================================

class Game_Character
 
 attr_accessor :paths
 attr_accessor :move_route_forcing
 attr_accessor :move_route

 alias zer0_pathfinding_init initialize
 def initialize
   # Add public instance variable for paths
   @paths = []
   # Original method
   zer0_pathfinding_init
 end
 
 def next_route
   # Stop any custom move route that may be occuring.
   if @move_route != nil
     # Set index and disable forcing of current route
     @move_route_index = @move_route.list.size
     @move_route_forcing = false
     # Reset to what it was originally
     @move_route = @original_move_route
     @move_route_index = @original_move_route_index
     @original_move_route = nil
   end
   # Remove first path from the paths array.
   @paths.shift
   # If there is another path to follow...
   if @paths[0] != nil
     # Setup path again to reflect any changes since original creation
     @forcing = false
     @paths[0].setup(@paths[0].target, @paths[0].range,
       @paths[0].success_proc, @paths[0].failure_proc)
     force_move_route(@paths[0].route) if @paths[0].found
   end
 end
 
 alias zer0_recalculate_paths_move move_type_custom
 def move_type_custom
   if $game_map.recalculate_paths
     # Interrupt if not stopping
     return if jumping? || moving?
     # Loop until finally arriving at move command list
     while @move_route_index < @move_route.list.size
       # Get the move command at index
       command = @move_route.list[@move_route_index]
       # If command code is 0 (end of list)
       if command.code == 0
         # If [repeat action] option is ON
         if @move_route.repeat
           # Reset move route index to the top of the list
           @move_route_index = 0
         end
         # If [repeat action] option is OFF
         unless @move_route.repeat
           # If move route is forced and not repeating
           if @move_route_forcing and not @move_route.repeat
             # The move route is no longer forced (moving ended)
             @move_route_forcing = false
             # Restore original move route
             @move_route = @original_move_route
             @move_route_index = @original_move_route_index
             @original_move_route = nil
             # If there was a path to follow and we reached goal
             if @paths[0] != nil
               if self.x == @paths[0].goal.x &&
                 y == @paths[0].goal.y && @paths[0].success_proc
                 # Call success Proc if goal is reached and it is defined.
                 @paths[0].success_proc.call
               end
               next_route
             end
           end
           # Clear stop count
           @stop_count = 0
         end
         return
       end # if command.code == 0
       # For move commands (from move down to jump)
       if command.code <= 14
         # Branch by command code
         case command.code
         when 1 then move_down                 # Move down
         when 2 then move_left                 # Move left
         when 3 then move_right                # Move right
         when 4 then move_up                   # Move up
         when 5 then move_lower_left           # Move lower left
         when 6 then move_lower_right          # Move lower right
         when 7 then move_upper_left           # Move upper left
         when 8 then move_upper_right          # Move upper right
         when 9 then move_random               # Move random
         when 10 then move_toward_player       # Move toward player
         when 11 then move_away_from_player    # Move away from player
         when 12 then move_forward             # Step forward
         when 13 then move_backward            # Step backward
         when 14 then jump(command.parameters[0], command.parameters[1]) # Jump
         end
         # If movement failure occurs when "Ignore If Can't Move" is unchecked.
         if !@move_route.skippable && !moving? && !jumping?
           # If path is current and collision limit is not reached
           if @paths[0] != nil &&
             @paths[0].collisions < $game_map.collision_retry
             # Setup path again to update starting location.
             # original goal node is used because pathfinding changes
             # the goal node to current node
             goal, range = @paths[0].target, @paths[0].range
             reach = @paths[0].success_proc
             fail = @paths[0].failure_proc
             counter = @paths[0].collisions + 1
             # Find another path to goal
             @paths[0] = Pathfind.new(goal, self, range, reach, fail)
             @paths[0].collisions = counter
             force_move_route(@paths[0].route) if @paths[0].found
             # Wait a bit before starting to follow the new path
             @wait_count = 6
             return
           elsif paths[0] != nil
             # Call failure Proc if defined and set move index.
             @move_route_index = @move_route.list.size
             @paths[0].failure_proc.call if @paths[0].failure_proc != nil
             next_route
           end
           # End method
           return
         end
         # Advance index
         @move_route_index += 1
         return
       end # if command.code <= 14
       # If waiting
       if command.code == 15
         # Set wait count (from provided parameter)
         @wait_count = command.parameters[0] * 2 - 1
         @move_route_index += 1
         return
       end # if command.code == 15
       # If direction change (turning) command
       if command.code >= 16 and command.code <= 26
         # Branch by command code
         case command.code
         when 16 then turn_down                      # Turn down
         when 17 then turn_left                      # Turn left
         when 18 then turn_right                     # Turn right
         when 19 then turn_up                        # Turn up
         when 20 then turn_right_90                  # Turn 90° right
         when 21 then turn_left_90                   # Turn 90° left
         when 22 then turn_180                       # Turn 180°
         when 23 then turn_right_or_left_90          # Turn 90° right or left
         when 24 then turn_random                    # Turn at Random
         when 25 then turn_toward_player             # Turn toward player
         when 26 then turn_away_from_player          # Turn away from player
         end
         @move_route_index += 1
         return
       end
       # If other command (commands that don't 'return')
       if command.code >= 27
         # Branch by command code
         case command.code
         when 27                                              # Switch ON
           $game_switches[command.parameters[0]] = true
           $game_map.need_refresh = true
         when 28                                              # Switch OFF
           $game_switches[command.parameters[0]] = false
           $game_map.need_refresh = true
         when 29 then @move_speed = command.parameters[0]     # Change speed
         when 30 then @move_frequency = command.parameters[0] # Change freq
         when 31 then @walk_anime = true                      # Move ON
         when 32 then @walk_anime = false                     # Move OFF
         when 33 then @step_anime = true                      # Stop ON
         when 34 then @step_anime = false                     # Stop OFF
         when 35 then @direction_fix = true                   # Direction ON
         when 36 then @direction_fix = false                  # Direction OFF
         when 37 then @through = true                         # Through ON
         when 38 then @through = false                        # Through OFF
         when 39 then @always_on_top = true                   # On top ON
         when 40 then @always_on_top = false                  # On top OFF
         when 41                                              # Change Graphic
           # Can't change into a tile
           @tile_id = 0
           @character_name = command.parameters[0]
           @character_hue = command.parameters[1]
           # Update direction
           if @original_direction != command.parameters[2]
             @direction = command.parameters[2]
             @original_direction = @direction
             @prelock_direction = 0
           end
           # Update frame
           if @original_pattern != command.parameters[3]
             @pattern = command.parameters[3]
             @original_pattern = @pattern
           end
         when 42 then @opacity = command.parameters[0]        # Change Opacity
         when 43 then @blend_type = command.parameters[0]     # Change Blending
         when 44 then $game_system.se_play(command.parameters[0]) # Play SE
         when 45 then result = eval(command.parameters[0])    # Script
         end
         # Increment move index.
         @move_route_index += 1
       end
     end
   else
     # Original method
     zer0_recalculate_paths_move
   end
 end
end

#==============================================================================
# ** Node
#==============================================================================

class Node

 attr_accessor :x                      
 attr_accessor :y                      
 attr_accessor :parent                  
 attr_accessor :cost                
 attr_accessor :heuristic                  

 def initialize(x, y, parent = nil, cost = 0, heuristic = 0)
   # Set public instance variables.
   @x, @y, @parent, @cost, @heuristic = x, y, parent, cost, heuristic
 end

 def score
   # Return the current "score" of this node
   return @cost + @heuristic
 end
 
 def in_range?(node, range)
   # Return true/false if Nodes are within RANGE of each other.
   return (@x - node.x).abs + (@y - node.y).abs <= range
 end

 def ==(node)
   # Returns true/false of whether self and other are equal.
   return ((node.is_a?(Node)) && (node.x == @x) && (node.y == @y))
 end
end
#=end



Instructions

Place script below default scripts and above "Main".
Further instructions are within the script and demo.


Compatibility
Should be compatible with most scripts. Cannot be used in conjunction with the original Pathfinding script, but it shouldn't need to, should it?


Credits and Thanks


  • ForeverZer0 for the original script

  • Credit goes to Peter Hart, Nils Nilsson and Bertram Raphael for the original search algorithm that was implemented




Author's Notes

To use the pathfinding script you can follow ForeverZer0s instructions for the default methods or... to move to an event with a specific name use the Script command with these details:

pathfind("carrot",y, e, r)



  • "carrot" is the name of the event to search for. It is case sensitive but only needs to be in quotation marks in the script call, not in the actual event!

  • Y isn't strictly needed for this mode, but cannot be left blank so I advise just putting a 0 in

  • E is the event number, identical to ForeverZer0s script

  • R is range. How many tiles away the moving event will be from its destination before it's satisfied and stops



If you want your event to choose from multiple events then your Script call should look like this:

pathfind(["carrot","orange","apple],y, e, r)


Pretty much the same as before. Just be aware of the limitations of the Script call in RMXP...

I'm afraid I'm a rather haphazard coder so if there are any problems then let me know.


History

Version 1.01a


  • $game_actor changed to $game_player as actor has no x or y.

  • Fixed problem with 'normal' move routes crashing the game when blocked due to not having awareness of the failure_proc



Enjoy