#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
# Simple Event Ai by Nathmatt
# Version: 1.16
# Type: Add On
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#
# This work is protected by the following license:
# #----------------------------------------------------------------------------
# #
# # Creative Commons - Attribution-NonCommercial-ShareAlike 3.0 Unported
# # ( http://creativecommons.org/licenses/by-nc-sa/3.0/ )
# #
# # You are free:
# #
# # to Share - to copy, distribute and transmit the work
# # to Remix - to adapt the work
# #
# # Under the following conditions:
# #
# # Attribution. You must attribute the work in the manner specified by the
# # author or licensor (but not in any way that suggests that they endorse you
# # or your use of the work).
# #
# # Noncommercial. You may not use this work for commercial purposes.
# #
# # Share alike. If you alter, transform, or build upon this work, you may
# # distribute the resulting work only under the same or similar license to
# # this one.
# #
# # - For any reuse or distribution, you must make clear to others the license
# # terms of this work. The best way to do this is with a link to this web
# # page.
# #
# # - Any of the above conditions can be waived if you get permission from the
# # copyright holder.
# #
# # - Nothing in this license impairs or restricts the author's moral rights.
# #
# #-----------------------------------------------------------------------------
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
# Config
#-------------------------------------------------------------------------------
# This module provides the configurations.
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
module Config
# the event tag that blocks the view events
Wall = 1
end
#==============================================================================
# Game_Map
#------------------------------------------------------------------------------
# This class adds check names to the original Game_Map.
#==============================================================================
class Game_Map
attr_reader :map
alias setup_Event_Ai_later setup
def setup(map_id)
setup_Event_Ai_later(map_id)
check_names
end
#--------------------------------------------------------------------------
# check_names
# This calls the check_event_names on all the event on the map.
#--------------------------------------------------------------------------
def check_names
$game_map.events.each_key {|i|
check_event_names(i) if $game_map.events[i] != nil}
end
#--------------------------------------------------------------------------
# check_event_name
# event_id - event ID
# Checks events name and adds its id to the proper array.
# Then stores a few needed variables
#--------------------------------------------------------------------------
def check_event_names(event_id)
event = @map.events[event_id]
if event.name.clone.gsub!(/\\[Pp]\[([\d, ]+)\]/) {"#[$1]"}
get = eval("[#{$1}]")
view = get[0]
range = get[1]
target_id = get[2]
type = 4
end
if event.name.clone.gsub!(/\\[Rr]\[([\d, ]+)\]/) {"#[$1]"}
get = eval("[#{$1}]")
view = get[0]
target_id = get[1]
type = 2
end
if event.name.clone.gsub!(/\\[Cc]\[([\d, ]+)\]/) {"#[$1]"}
get = eval("[#{$1}]")
view = get[0]
target_id = get[1]
type = 1
end
if event.name.clone.gsub!(/\\[Vv]\[([\d, ]+)\]/) {"#[$1]"}
get = eval("[#{$1}]")
view = get[0]
switch_id = get[1]
target_id = get[2]
type = 3
end
if type.is_a?(Numeric) && type != nil
view = 0 if !view.is_a?(Numeric) || view == nil
target_id = 0 if target_id == nil
$game_map.events[event_id] = Ai_Event.new($game_map.map_id,event,view,type,
range,event.x,event.y,target_id,switch_id)
end
end
end
Location_Holder = Struct.new(:x, :y)
#==============================================================================
# ** Ai_Event
#------------------------------------------------------------------------------
# This is a modified version of Game_Event that controls the events movements
# @ whether or not the event can see its target.
#==============================================================================
class Ai_Event < Game_Character
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_reader :trigger # trigger
attr_reader :list # list of event commands
attr_reader :starting # starting flag
#--------------------------------------------------------------------------
# * Object Initialization
# map_id : map ID
# event : event (RPG::Event)
#--------------------------------------------------------------------------
def initialize(map_id,event,view,type,range,start_x,start_y,target_id,
switch_id = nil)
super()
@map_id = map_id
@event = event
@id = event.id
@view = view
@type = type
@range = range
@switch_id = switch_id
@erased = false
@starting = false
@through = true
#call dummy class
@start = Location_Holder.new(start_x,start_y)
# get type from type
@target = check_target(target_id)
# Move to starting position
moveto(@event.x, @event.y)
refresh
end
#--------------------------------------------------------------------------
# * Clear Starting Flag
#--------------------------------------------------------------------------
def clear_starting
@starting = false
end
#--------------------------------------------------------------------------
# * Determine if Over Trigger
# (whether or not same position is starting condition)
#--------------------------------------------------------------------------
def over_trigger?
# If not through situation with character as graphic
# Starting determinant is face
return false if @character_name != "" and not @through
# If this position on the map is impassable
# Starting determinant is face
return false unless $game_map.passable?(@x, @y, 0)
# Starting determinant is same position
return true
end
#--------------------------------------------------------------------------
# * Start Event
#--------------------------------------------------------------------------
def start
# If list of event commands is not empty
@starting = true if @list.size > 1
end
#--------------------------------------------------------------------------
# * Temporarily Erase
#--------------------------------------------------------------------------
def erase
@erased = true
refresh
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
# Initialize local variable: new_page
new_page = nil
# If not temporarily erased
unless @erased
# Check in order of large event pages
@event.pages.reverse.each { |page|
# Make possible referrence for event condition with c
c = page.condition
# Switch 1 condition confirmation
if c.switch1_valid
next if $game_switches[c.switch1_id] == false
end
# Switch 2 condition confirmation
if c.switch2_valid
next if $game_switches[c.switch2_id] == false
end
# Variable condition confirmation
if c.variable_valid
next if $game_variables[c.variable_id] < c.variable_value
end
# Self switch condition confirmation
if c.self_switch_valid
key = [@map_id, @event.id, c.self_switch_ch]
next if $game_self_switches[key] != true
end
# Set local variable: new_page
new_page = page
# Remove loop
break}
end
# If event page is the same as last time
return if new_page == @page
# Set @page as current event page
@page = new_page
# Clear starting flag
clear_starting
# If no page fulfills conditions
if @page == nil
# Set each instance variable
@tile_id = 0
@character_name = ""
@character_hue = 0
@move_type = 0
@through = true
@trigger = nil
@list = nil
@interpreter = nil
# End method
return
end
# Set each instance variable
@tile_id = @page.graphic.tile_id
@character_name = @page.graphic.character_name
@character_hue = @page.graphic.character_hue
if @original_direction != @page.graphic.direction
@direction = @page.graphic.direction
@original_direction = @direction
@prelock_direction = 0
end
if @original_pattern != @page.graphic.pattern
@pattern = @page.graphic.pattern
@original_pattern = @pattern
end
@opacity = @page.graphic.opacity
@blend_type = @page.graphic.blend_type
@original_type = @page.move_type
@move_speed = @page.move_speed
@move_frequency = @page.move_frequency
@move_route = @page.move_route
@move_route_index = 0
@move_route_forcing = false
@walk_anime = @page.walk_anime
@step_anime = @page.step_anime
@direction_fix = @page.direction_fix
@through = @page.through
@always_on_top = @page.always_on_top
@trigger = @page.trigger
@list = @page.list
@interpreter = nil
# If trigger is [parallel process]
# Create parallel process interpreter
@interpreter = Interpreter.new if @trigger == 4
# Auto event start determinant
check_event_trigger_auto
end
#--------------------------------------------------------------------------
# * Touch Event Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_touch(x, y)
# If event is running
return if $game_system.map_interpreter.running?
# If trigger is [touch from event] and consistent with player coordinates
if @trigger == 2 && x == $game_player.x && y == $game_player.y
# If starting determinant other than jumping is front event
start if ! jumping? && ! over_trigger?
end
end
#--------------------------------------------------------------------------
# * Automatic Event Starting Determinant
#--------------------------------------------------------------------------
def check_event_trigger_auto
# If trigger is [touch from event] and consistent with player coordinates
if @trigger == 2 && @x == $game_player.x && @y == $game_player.y
# If starting determinant other than jumping is same position event
start if ! jumping? && over_trigger?
end
# If trigger is [auto run]
start if @trigger == 3
end
#------------------------------------------------------------------------
# check_event_trigger_at
# x - x-coordinate
# y - y-coordinate
# Check event if it was triggered at a specific position.(pixel movement)
#------------------------------------------------------------------------
def check_event_trigger_at(x, y)
# get pixel movement rate
pix = $BlizzABS.pixel
# if player touched this event and not jumping and not over_trigger
if !jumping? && !over_trigger? && $BlizzABS.util.rect_intersection(
Rect.new(@x * pix, @y * pix, pix, pix), Rect.new(x, y, pix, pix))
# start
start
# started
return true
end
# not started
return false
end
#--------------------------------------------------------------------------
# distance_from_target(target)
# target - is the target
# Checks the distance from self and target and returns it.
#--------------------------------------------------------------------------
def distance_from_target(target)
return Math.hypot((@x - target.x),(@y - target.y))
end
#--------------------------------------------------------------------------
# check_target(target_id)
# target_id - is the event id unless it equals 0 thean its the player
# Checks what kind of target and returns it.
#--------------------------------------------------------------------------
def check_target(target_id)
return $game_player if target_id == 0
return $game_map.events[target_id] if target_id > 0
end
#--------------------------------------------------------------------------
# move_type_away
# moves self away from target if in view
#--------------------------------------------------------------------------
def move_type_away
if distance_from_target(@target) <= @view
move_away
else
@original_type
end
end
#--------------------------------------------------------------------------
# move_type_toward
# moves self toward from target if in view
#--------------------------------------------------------------------------
def move_type_toward
if distance_from_target(@target) <= @view
move_toward(@target)
else
@original_type
end
end
#--------------------------------------------------------------------------
# view_type
# turns on defined switch if event can_see? self
#--------------------------------------------------------------------------
def view_type
if can_see?
$game_switches[@switch_id] = true
$game_map.refresh
end
return
end
#--------------------------------------------------------------------------
# passave_type
# moves self toward target unless it gets out of range from start
#--------------------------------------------------------------------------
def passave_type
if distance_from_target(@target) < @view
if distance_from_target(@start) > @range
move_toward(@start)
else
move_toward(@target)
end
else
return move_toward(@start)
end
end
#--------------------------------------------------------------------------
# change_type
#--------------------------------------------------------------------------
def change_type(type,view,target_id = nil,range = nil,switch_id = nil)
@type = type
@view = view
@target_id = target_id if target_id != nil
@range = range if range != nil
@swith_id = switch_id if switch_id != nil
end
#--------------------------------------------------------------------------
# can_see?
# event_id - is the events id
# This checks to see if the event can see you.
#--------------------------------------------------------------------------
def can_see?
(0...@view).each { |r|
case @direction
when 2
if $game_map.terrain_tag(@x, (@y + r)) == Config::Wall
break
elsif @target.x == @x && @target.y == (@y + r)
return true
end
when 4
if $game_map.terrain_tag((@x - r), @y) == Config::Wall
break
elsif @target.x == (@x - r) && @target.y == @y
return true
end
when 6
if $game_map.terrain_tag((@x + r), @y) == Config::Wall
break
elsif @target.x == (@x + r) && @target.y == @y
return true
end
when 8
if $game_map.terrain_tag(@x, (@y - r)) == Config::Wall
break
elsif @target.x == @x && @target.y == (@y - r)
return true
end
end}
return false
end
def check_other(x,y,d)
case d
when 2
if passable?(x, y,4)
return move_left
elsif passable?(x, y,6)
return move_right
elsif passable?(x, y,8)
return move_up
end
when 4
if passable?(x, y,2)
return move_down
elsif passable?(x, y,8)
return move_up
elsif passable?(x, y,6)
return move_right
end
when 6
if passable?(x, y,2)
return move_down
elsif passable?(x, y,8)
return move_up
elsif passable?(x, y,4)
return move_left
end
when 8
if passable?(x, y,4)
return move_left
elsif passable?(x, y,6)
return move_right
elsif passable?(x, y,2)
return move_down
end
end
end
#--------------------------------------------------------------------------
# * Move toward target
#--------------------------------------------------------------------------
def move_toward(target)
# Returns if it is targeting itself
return if target == @event
# Get difference in target and selfs coordinates
sx = @x - target.x
sy = @y - target.y
# If coordinates are equal
return @original_type if sx == 0 && sy == 0
# Get absolute value of difference
abs_sx = sx.abs
abs_sy = sy.abs
# If horizontal and vertical distances are equal
# Increase one of them randomly by 1
rand(2) == 0 ? abs_sx += 1 : abs_sy += 1 if abs_sx == abs_sy
# If horizontal distance is longer
if abs_sx > abs_sy
# Move towards player, prioritize left and right directions
sx > 0 ? move_left : move_right
sy > 0 ? move_up : move_down if ! moving? && sy != 0
# If vertical distance is longer
else
# Move towards player, prioritize up and down directions
sy > 0 ? move_up : move_down
sx > 0 ? move_left : move_right if ! moving? && sx != 0
end
return
end
#--------------------------------------------------------------------------
# * Move away from target
#--------------------------------------------------------------------------
def move_away
# Returns if it is targeting itself
return if @target == @event
# Get difference in target and selfs coordinates
sx = @x - @target.x
sy = @y - @target.y
if !passable?(@x, @y,@direction)
check_other(@x, @y,@direction)
else
# If coordinates are equal
return if sx == 0 && sy == 0
# Get absolute value of difference
abs_sx = sx.abs
abs_sy = sy.abs
# If horizontal and vertical distances are equal
# Increase one of them randomly by 1
rand(2) == 0 ? abs_sx += 1 : abs_sy += 1 if abs_sx == abs_sy
# If horizontal distance is longer
if abs_sx > abs_sy
# Move away from player, prioritize left and right directions
sx > 0 ? move_right : move_left
sy > 0 ? move_down : move_up if ! moving? && sy != 0
# If vertical distance is longer
else
# Move away from player, prioritize up and down directions
sy > 0 ? move_down : move_up
sx > 0 ? move_right : move_left if ! moving? && sx != 0
end
end
return
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
super
# Automatic event starting determinant
check_event_trigger_auto
# If parallel process is valid
if @interpreter != nil
# If not running
unless @interpreter.running?
# Set up event
@interpreter.setup(@list, @event.id)
end
# Update interpreter
@interpreter.update
end
# If stop count exceeds a certain value (computed from move frequency)
if @stop_count > (40 - @move_frequency * 2) * (6 - @move_frequency)
@move_type = case @type
when 1
move_type_toward
when 2
move_type_away
when 3
view_type
when 4
passave_type
end
end
end
end
class Control_Sprite_Character
#----------------------------------------------------------------------------
# character_valid?
# Checks if this sprite should be displayed and updated.
#----------------------------------------------------------------------------
def character_valid?
return (@character.is_a?(Game_Event) || @character.is_a?(Ai_Event) ||
@character.is_a?(Map_Enemy) &&
@character.precondition || @character.is_a?(Map_Remote) ||
@character.dropped?) && @character.update? ||
!@character.is_a?(Map_Enemy) && !@character.is_a?(Map_Remote) &&
@character.is_a?(Map_Battler)
end
end