Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #═╦═════════════════════════════════════════════════════════════════════════════
- # ║ § Event Movement (1.0) by Solistra [License: CC BY-SA 3.0]
- # ║ Original path-finding code by Near_Fantastica <RMVX Ace>
- #═╬═════════════════════════════════════════════════════════════════════════════
- # ║ § Change Log
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ v1.0 (December 30th, 2012) - Initial release
- # ║
- #═╬═════════════════════════════════════════════════════════════════════════════
- # ║ § Summary
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ This script adds a number of new movement types for events, including simple
- # ║ path finding (originally written by Near_Fantastica for RMXP), easy patrol
- # ║ routes, and movement types that can move events closer to other characters
- # ║ and positions on the map. There is also a simple script call available for
- # ║ determining a character's proximity to any other character (the player or
- # ║ another event, for example).
- # ║
- # ║ NOTE: Make sure to credit Near_Fantastica as well as me (Solistra) if you
- # ║ use this script!
- # ║
- #═╬═════════════════════════════════════════════════════════════════════════════
- # ║ § Required Scripts
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ This script requires the SES Core script version 1.0 or higher.
- # ║
- #═╬═════════════════════════════════════════════════════════════════════════════
- # ║ § Known Incompatibilities
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ None.
- # ║
- #═╬═════════════════════════════════════════════════════════════════════════════
- # ║ § Installation
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ Place this script below Materials, but above Main -- preferably relatively
- # ║ high in your list of custom scripts. This script must be below the SES Core
- # ║ script and the SES Event Memory script (if you are using it).
- # ║
- #═╬═════════════════════════════════════════════════════════════════════════════
- # ║ § Configuration
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ There is only one configuration option: PATH_FINDING_DEPTH. The value of
- # ║ this option is important, though: it defines how large the path-finding tree
- # ║ may be when trying to determine a path. High values are more computationally
- # ║ expensive than low values, but a value that is too low may make the path
- # ║ finder relatively useless (as it may not be able to find paths that exist).
- # ║ Generally, a value from 50-150 is quite safe, but if you are experiencing
- # ║ lag in-game, you should try lowering this value as much as you reasonably
- # ║ can.
- # ║
- # ║ With that in mind, here is some explanation regarding patrol routes: in
- # ║ order to use patrol routes, you will have to "tag" the event you want to
- # ║ patrol with a comment. This comment is in the format of "<patrol [route]>".
- # ║ Patrol routes must be written as a series of comma-separated x and y values
- # ║ enclosed in brackets (these: []). The event will then move from its current
- # ║ position to the first position in the patrol route, then the next, until it
- # ║ reaches the end of the route and goes back to the first position in the
- # ║ route, effectively looping it.
- # ║
- # ║ Example of how to set up the comment:
- # ║ <patrol [0,0], [10,5], [5,10]>
- # ║
- # ║ This will cause the event to move to 0, 0 on the map, then 10, 5, then 5,
- # ║ 10, and finally back to 0, 0 -- looping through these patrol points.
- # ║
- # ║ NOTE: Patrol routes use path finding to get from one destination to another.
- # ║ This makes for very efficient patrols, but inefficient processing. Try not
- # ║ to use too many events with patrols on the same map -- you may find that
- # ║ your map begins to lag otherwise. Consider yourself informed.
- # ║
- #═╬═════════════════════════════════════════════════════════════════════════════
- # ║ § Tags
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ ● Event Comment
- # ║ <patrol !route!>
- # ║ ► Replacements:
- # ║ !route! with a comma-separated list of x and y values written as
- # ║ Ruby arrays. Example: <patrol [0,0], [10,5], [5,10]>
- # ║
- #═╬═════════════════════════════════════════════════════════════════════════════
- # ║ § Script Calls
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ This script features a number of script calls relating to event movement
- # ║ types (which should be used in an event's Move Route). If you wish to use
- # ║ any of these movement types as the default movement type for an event page,
- # ║ simply use the Custom movement type and insert the appropriate script call
- # ║ in that Move Route.
- # ║
- # ║ There are a few script calls that you will likely want to make use of if
- # ║ you plan to use the path finder: find_path, find_path_to, and reset_path.
- # ║ The find_path method finds a path to a given x and y value on the map, while
- # ║ the find_path_to method finds the path to a given character (the player or
- # ║ another event). This is how to use them:
- # ║ find_path([x], [y]) - Finds a path to [x] and [y] on the map.
- # ║ find_path_to($game_player) - Finds a path to the player.
- # ║ find_path_to(event([id])) - Finds a path to the event with ID # [id].
- # ║ reset_path - Cancels path finding by removing the tree.
- # ║
- # ║ There are also script calls for movement types that can move an event
- # ║ towards a specific x and y position on the map or another character (the
- # ║ player or another event). These do not use path finding, and are very
- # ║ efficient (but also easily confused on complicated maps). To use them, make
- # ║ use of these script calls:
- # ║ move_type_toward_position([x], [y])
- # ║ move_type_toward_character(event([id])
- # ║
- # ║ In addition to this, there are also path-finding movement types -- but be
- # ║ warned: they are NOT efficient at all, and may cause serious lag if abused!
- # ║ With that in mind, these movement types will recalculate the path each time
- # ║ the character moves, meaning it will actively avoid obstacles. If you wish
- # ║ to use them, make use of these script calls:
- # ║ move_type_path([x], [y])
- # ║ move_type_path_to($game_player)
- # ║ move_type_path_to(event([id]))
- # ║
- # ║ You can also use a script call to determine whether or not a character is
- # ║ near the calling event (very useful in Conditional Branches). It will return
- # ║ "true" if the character is in proximity, "false" otherwise. Use it like so:
- # ║ near_character?($game_player, [range in tiles])
- # ║ in_proximity?(event([id]), [range in tiles])
- # ║
- # ║ If you leave out the range, it will default to 20 tiles to be consistent
- # ║ with RGSS3's default near_the_player? method in Game_Event.
- # ║
- #═╬═════════════════════════════════════════════════════════════════════════════
- # ║ § Aliased Methods
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ ● Game_Map
- # ║ setup_events
- # ║ ● Game_Character
- # ║ initialize
- # ║ update
- # ║ ● Game_Player
- # ║ move_by_input
- # ║ ● Game_Event
- # ║ initialize
- # ║ update_self_movement
- # ║ refresh
- # ║
- #═╬═════════════════════════════════════════════════════════════════════════════
- # ║ § New Methods
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ ● Game_Character
- # ║ move_toward_position
- # ║ find_path
- # ║ find_path_to
- # ║ run_next_path_step
- # ║ reset_path
- # ║ determine_path_tree
- # ║ moved?
- # ║ on_movement
- # ║ reset_movement_variables
- # ║ move_failed?
- # ║ ● Game_Event
- # ║ move_type_toward_character
- # ║ move_type_toward_position
- # ║ move_type_path
- # ║ move_type_path_to
- # ║ move_type_patrol
- # ║ near_character?
- # ║ determine_patrol_points
- # ║
- #═╬═════════════════════════════════════════════════════════════════════════════
- # ║ ▼ module SES::Event_Movement
- #═╩═════════════════════════════════════════════════════════════════════════════
- module SES module Event_Movement
- #═╦═══════════════════════════════════════════════════════════════════════════
- # ║ α BEGIN CONFIGURATION
- #═╩═══════════════════════════════════════════════════════════════════════════
- # This determines how large the path tree can be when trying to determine a
- # path. Higher values require more computation while lower values may not
- # find a path -- even if one exists. A modest amount from 50-150 works well.
- PATH_FINDING_DEPTH = 100
- #═╦═══════════════════════════════════════════════════════════════════════════
- # ║ Ω END CONFIGURATION
- #═╩═══════════════════════════════════════════════════════════════════════════
- end end
- #═╦═════════════════════════════════════════════════════════════════════════════
- # ║ ▲ module SES::Event_Movement
- #═╩═════════════════════════════════════════════════════════════════════════════
- ($imported ||= {})["SES - Event Movement"] = 1.0
- if $imported["SES - Core"].nil? || $imported["SES - Core"] < 1.0
- raise("SES Event Movement requires SES Core 1.0 or higher.") end
- if $imported["SES - Event Memory"]
- module SES module Event_Memory; @event_memory[:patrol] = :patrol end end end
- #═╦═════════════════════════════════════════════════════════════════════════════
- # ║ ▼ class Game_Map
- #═╩═════════════════════════════════════════════════════════════════════════════
- class Game_Map
- if $imported["SES - Event Memory"]
- # Aliased to remember patrol points if SES Event Memory is in use.
- alias :ses_evmov_gm_setupev :setup_events
- def setup_events(*args, &block)
- ses_evmov_gm_setupev(*args, &block)
- $game_system.events[@map_id].each{|i, v| @events[i].patrol = v[:patrol]
- } if $game_system.events[@map_id]
- end
- end
- end
- #═╦═════════════════════════════════════════════════════════════════════════════
- # ║ ▲ class Game_Map
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ ▼ class Game_Character
- #═╩═════════════════════════════════════════════════════════════════════════════
- class Game_Character < Game_CharacterBase
- # Initialize the new instance variables @old_x and @old_y.
- alias :ses_evmov_gc_init :initialize
- def initialize(*a, &b) ses_evmov_gc_init(*a, &b); @old_x, @old_y = @x, @y end
- # Aliased to provide the ability to run code whenever an event moves via the
- # on_movement method. (Scripters, alias on_movement if you need this.)
- alias :ses_evmov_gc_upd :update
- def update(*a, &b) ses_evmov_gc_upd(*a, &b); on_movement if moved? end
- # Moves the character towards a specific x and y position on the map.
- def move_toward_position(x, y)
- sx, sy = @x - x, @y - y
- if sx != 0 || sy != 0
- if sx.abs > sy.abs
- sx > 0 ? move_straight(4) : move_straight(6)
- (sy > 0 ? move_straight(8) : move_straight(2)) if move_failed?
- else
- sy > 0 ? move_straight(8) : move_straight(2)
- (sx > 0 ? move_straight(4) : move_straight(6)) if move_failed?
- end
- end
- end
- # Convenience method to quickly build a path tree for an event. Original code
- # by Near_Fantastica, stripped and modified by Solistra.
- def find_path(x, y)
- result = determine_path_tree(@x, @y, x, y)
- @path_tree = result[0].is_a?(Table) ? result[0] : nil
- @path_tree[@x, @y] = result[1] unless @path_tree.nil?
- end
- # Convenience method to build a path tree to an ancestor of Game_Character.
- def find_path_to(character) find_path(character.x, character.y) end
- # Moves a character along their path tree. Original version was written by
- # Near_Fantastica, stripped and modified by Solistra.
- def run_next_path_step
- return if moving?
- step = @path_tree[@x, @y]
- if step <= 1 then reset_path; return
- else
- move_straight(6) if @path_tree[@x + 1, @y] == step - 1
- move_straight(2) if @path_tree[@x, @y + 1] == step - 1
- move_straight(4) if @path_tree[@x - 1, @y] == step - 1
- move_straight(8) if @path_tree[@x, @y - 1] == step - 1
- end
- end
- # Reset the path tree. Original code by Near_Fantastica, modified by Solistra.
- def reset_path() remove_instance_variable(:@path_tree) end
- # Creates the path tree used for path finding. Original code written by
- # Near_Fantastica, modified by Solistra.
- def determine_path_tree(sx, sy, ex, ey)
- map = Table.new($game_map.width, $game_map.height)
- map[ex, ey], depth, old_positions, new_positions = 1, 2, [[ex, ey]], []
- depth.upto(SES::Event_Movement::PATH_FINDING_DEPTH) do |step|
- loop do
- break if old_positions[0].nil?
- x, y = old_positions.shift
- return [map, step] if x == sx && y + 1 == sy
- if passable?(x, y, 2) && map[x, y + 1] == 0
- map[x, y + 1] = step
- new_positions.push([x, y + 1])
- end
- return [map, step] if x - 1 == sx && y == sy
- if passable?(x, y, 4) && map[x - 1, y] == 0
- map[x - 1, y] = step
- new_positions.push([x - 1, y])
- end
- return [map, step] if x + 1 == sx && y == sy
- if passable?(x, y, 6) && map[x + 1, y] == 0
- map[x + 1, y] = step
- new_positions.push([x + 1, y])
- end
- return [map, step] if x == sx && y - 1 == sy
- if passable?(x, y, 8) && map[x, y - 1] == 0
- map[x, y - 1] = step
- new_positions.push([x, y - 1])
- end
- end
- old_positions, new_positions = new_positions, []
- end
- end
- # Movement-related convenience methods -- certainly easy enough to figure out.
- def moved?() @old_x != @x || @old_y != @y end
- def on_movement() reset_movement_variables end
- def reset_movement_variables() @old_x, @old_y = @x, @y end
- def move_failed?() !@move_succeed end
- end
- #═╦═════════════════════════════════════════════════════════════════════════════
- # ║ ▲ class Game_Character
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ ▼ class Game_Player
- #═╩═════════════════════════════════════════════════════════════════════════════
- class Game_Player < Game_Character
- # Aliased to move the player along their path tree if one exists before any
- # movement by input is processed.
- alias :ses_evmov_gp_move :move_by_input
- def move_by_input(*args, &block)
- if @path_tree
- run_next_path_step
- move_failed? ? reset_path : return
- end
- ses_evmov_gp_move(*args, &block)
- end
- end
- #═╦═════════════════════════════════════════════════════════════════════════════
- # ║ ▲ class Game_Player
- #─╫─────────────────────────────────────────────────────────────────────────────
- # ║ ▼ class Game_Event
- #═╩═════════════════════════════════════════════════════════════════════════════
- class Game_Event < Game_Character
- attr_accessor :patrol
- # Aliased to initialize the new instance variable @patrol, which is used to
- # determine the patrol points for an event.
- alias :ses_evmov_ge_init :initialize
- def initialize(*args, &block)
- ses_evmov_ge_init(*args, &block)
- @patrol = determine_patrol_points
- end
- # Aliased to move events along their patrol route if a route exists and they
- # are not currently running a path-finding tree.
- alias :ses_evmov_ge_updmov :update_self_movement
- def update_self_movement(*args, &block)
- ses_evmov_ge_updmov(*args, &block)
- if near_the_screen? && @stop_count > stop_count_threshold
- move_type_patrol if @patrol
- run_next_path_step if @path_tree
- end
- end
- # Aliased to reset the path when this event is refreshed and to get any new
- # patrol routes (or remove them if necessary).
- alias :ses_evmov_ge_ref :refresh
- def refresh(*args, &block)
- ses_evmov_ge_ref(*args, &block)
- unless @erased
- reset_path if @path_tree
- @patrol = determine_patrol_points
- end
- end
- # Self-explanatory enough, but this method provides a new movement type that
- # will move this event towards any ancestor of Game_Character.
- def move_type_toward_character(character)
- if near_character?(character)
- case rand(6)
- when 0..3 then move_toward_character(character)
- when 4 then move_random
- when 5 then move_forward
- end
- else move_random end
- end
- # Also self-explanatory, but provides a movement type that will cause this
- # event to move towards a specific x and y position on the map.
- def move_type_toward_position(x, y)
- case rand(6)
- when 0..3 then move_toward_position(x, y)
- when 4 then move_random
- when 5 then move_forward
- end
- end
- # Custom movement type that will move to a specified path, moving around any
- # obstacles if they exist. Warning: this recalculates the path each step,
- # which is NOT efficient! Do not abuse this!
- def move_type_path(x, y)
- find_path(x, y) if [@x, @y] != [x, y] || move_failed?
- end
- # Convenience method for move_type_path which moves to an ancestor of the
- # Game_Character class.
- def move_type_path_to(character) move_type_path(character.x, character.y) end
- # The patrol movement type. Simply uses the path finder to move from one point
- # in its patrol route to the next.
- def move_type_patrol
- return unless @patrol
- [@x,@y] == @patrol[0] ? @patrol.push(@patrol.shift) : find_path(*@patrol[0])
- end
- # Method used by move_type_toward_character to keep it consistent with the
- # behavior of the RGSS3 default move_type_toward_player method. Can also be
- # used as a simple proximity-checking method.
- def near_character?(character, range = 20)
- distance_x_from(character.x).abs + distance_y_from(character.y).abs < range
- end
- alias :in_proximity? :near_character?
- # Gets patrol points from an event's comments. (Note: patrol points can also
- # be manually added with $game_map.events[event_id].patrol = [route]. The
- # route is just an array of arrays containing x and y values.)
- def determine_patrol_points
- if comments.any?{|c| c =~ /\<patrol (.+)\>/} then eval("[#{$1}]") end
- end
- end
- #═╦═════════════════════════════════════════════════════════════════════════════
- # ║ ▲ class Game_Event
- #═╩═════════════════════════════════════════════════════════════════════════════
Advertisement
Add Comment
Please, Sign In to add comment