#==============================================================================
#
# HERETIC'S UNLIMITED EVENT PAGE CONDITIONS [XP]
# Version - 1.0
# Monday, August 8th, 2016
#
#==============================================================================
#
# --- Overview ---
#
# This script will allow you to use Scripts as a Page Condition!
#
# This completely unlocks the functionality of Page Conditions, which now have
# absolutely NO LIMITS! For example, the Default Page Conditions allow
# you to check a Game Variable, and the Page is only active if that
# Game Variable is equal to or greater than what ever number you put there.
# But, you could not check if the Game Variable was equal to or less than!
# Now you can easily make Game Variable Less Than a Page Condition!
#
# --- Installation ---
#
# Place above Main and below Scene Debug. Place below the SDK if used.
#
# --- Instructions ---
#
# Add a Comment to an Event says "Condition:" followed by a Script Condition.
#
# Example 1:
# @>Comment: Condition: $foo == $bar
#
# Example 2:
# @>Comment: Condition: $game_player.direction == 2 and $game_switches[12]
#
# Example 3:
# @>Comment: Condition: $game_player.moving? and $game_switches[12] and
# : (not $game_system.map_interpreter.running? or $foo == $bar)
#
# Example 4: (Not every line needs to be dedicated to evaluation.)
# @>Comment: Condition: p = $game_player
# : p.direction != 2
#
# Example 5: (Comments within Comments work too, note the # Character)
# @>Comment: Condition: p = $game_player
# : # If Player is facing Down
# : p.direction == 2
#
# --- Common Events ----
#
# This script does NOT affect Common Events, ONLY Map Events.
#
# --- Battle Event Pages ---
#
# This script does NOT affect Battle Event Page Conditions. I wrote another
# script for Battle Event Pages already.
#
# That script is called "Unlimited Battle Page Conditions" and is available
# as one of my many scripts in Heretic's Collection.
#
# --- Multi Line Support ---
#
# You can extend your scripts to Multiple Lines of Comment Boxes! The
# Comment Box should be plenty big enough to hold your text! Besides
# that, you're using Script Calls, so if you can't fit your text into
# one Box, you can write a Method that returns true or false and plug
# that into your own script!
#
# You can have Multiple Conditions also, each in their own Comment Box.
#
#
# --- Self Switches ---
#
# This script doesn't interfere with the use of Self Switches (ABCD). Feel
# free to combine both Self Switches and Script Conditions.
#
#
# --- Skipping Evaluation ---
#
# There may be certain conditions when you do NOT want a certain Page to
# evaulate its Script Conditions. For example, running an Event and you
# don't want the Page to change until it is done doing its thing. You
# can turn Script Evaluation ON or OFF by either a Script Call or with
# a Comment. It is intended to use BOTH in conjunction with each other.
# Basically, it gives you more control over when Scripts are evaluated.
#
# To temporarily prevent a Page from executing its Script Conditions, simply
# add a Comment to the Event's Page that reads:
#
# @>Comment: \skip_eval
#
# This is intended to be turned OFF with a Script Call or Move Route.
#
# @>Script: $game_map.events[id].skip_eval = true / false
# @>Set Move Route: This Event
# : $>Script: self.skip_eval = false
# : $>Script: skip_eval=(false)
#
# NOTE: The Page MUST BE ACTIVE to change Skip Eval or else you will set
# the Skip Eval on the WRONG PAGE.
#
# NOTE: Once Skip Eval has been changed, it will retain the state you set
# until the Map has been left entirely and transferred back to. This
# includes going into Battle Scenes. The value of Skip Eval will be
# remembered even after Battles are exited, but RESET if you leave
# the Map and come back to this Map.
#
#
# --- Performance ---
#
# Each Script Condition is evaluated once per frame so don't go crazy using
# too many Script Conditions, or at least make sure they evaluate quickly.
# Script Conditions all evaluated on each Map. Thus, if you have many maps
# but only a few maps that use Script Conditions, don't worry too much. You
# may see performance issues if you use lots and lots of Script Conditions
# on the same map. This does end up being tons faster than using multiple
# Parallel Events for very specific purposes however.
#
#
# --- Compatability ---
#
# This script may have some compatability issues with other scripts that
# modify the RPG::Event::Page::Conditions class. It has been tested with
# More Self-Switches by Gameus / Game Guy and although only briefly tested
# appears to work just fine. This script works by replacing attr_accessor
# methods with my custom definitions. Instead of returning a property of
# an object, it now uses self_switch_valid and self_switch_ch as getter
# methods which consider if Script Conditions are being used.
#
# It should also work just fine with Optimization Scripts as evaluation of
# the Script Conditions is handled outside of Event and Game Map update
# methods entirely.
#
#
# --- Legal ---
#
# You may distribute this script on websites in the scripts unaltered form.
#
# You may use this script in Commercial or Non Commercial projects without
# compensation as long as you give me credit for the use of my scripts.
#
#
# --- Config ---
#
# This script has no configurable Options.
#
#
# --- Version History ---
#
# Version 1.0 - Monday, August 8th, 2016
# - Initial Release
#
#==============================================================================
#==============================================================================
# ** RPG - Main RPG Module
#==============================================================================
module RPG
#----------------------------------------------------------------------------
# ** Event - RPG::Event
#----------------------------------------------------------------------------
class Event
#--------------------------------------------------------------------------
# ** Page - RPG::Event::Page
#--------------------------------------------------------------------------
class Page
#------------------------------------------------------------------------
# ** Condition - RPG::Event::Page::Condition
#------------------------------------------------------------------------
class Condition
#----------------------------------------------------------------------
# * Public Instance Variables - RPG::Event::Page::Condition
#----------------------------------------------------------------------
attr_accessor :script_condition
attr_accessor :map_id
attr_accessor :event_id
attr_accessor :skip_eval
#----------------------------------------------------------------------
# * Initialize - RPG::Event::Page::Condition
# - Adds Default Values for new Properties
#----------------------------------------------------------------------
alias script_condition_initialize initialize unless $@
def initialize
# Call Original or other Aliases
script_condition_initialize
# Container for Script Conditions
@script_condition = nil
# New Properties used for generating a Self Switches Hash Key
@map_id = nil
@event_id = nil
end
#----------------------------------------------------------------------
# * Self Switch Valid - RPG::Event::Page::Condition
# - Replaces attr_reader with reader method
#----------------------------------------------------------------------
def self_switch_valid
# Overrides @self_switch_valid value if a Script Condition exists
return true if not @script_condition.nil?
# Return Original Value (Self Switch is Checked in Edit Event)
@self_switch_valid
end
#----------------------------------------------------------------------
# * Self Switch Ch - RPG::Event::Page::Condition
# - Replaces attr_reader with reader method
# - Self Switch Channel is usually 'A' unless 'BCD' are specified
# - Checks both Self Switch and Script Condition to return Channel
#----------------------------------------------------------------------
def self_switch_ch
# Use Self Switch Ch (ABCD) if Valid and Switch is OFF
if @self_switch_valid
# Hash Key for Self Switches
key = [@map_id, @event_id, @self_switch_ch]
# Use Self Switch Ch (ABCD) if Valid and Switch is OFF
return @self_switch_ch if not $game_self_switches[key]
end
# If Script Condition Array has any Scripts
if not @script_condition.nil? and @script_condition.size > 0
# Iterate each Self Switch Script Condition
for script in @script_condition
# Create a Hash Key for Self Switches Hash with Script
ss_key = [@map_id, @event_id, script]
# Return the Script if Self Switch Script is OFF
return script if not $game_self_switches[ss_key]
end
# Return Last Script in Array as Self Switch Channel
return @script_condition.last
end
# Default Self Switch Channel (ABCD)
@self_switch_ch
end
end
end
end
end
#==============================================================================
# ** Game_Event
#==============================================================================
class Game_Event < Game_Character
#----------------------------------------------------------------------------
# * Initialize - Game_Event
# - Checks each Page of Event for Script Conditions in Comments
# map_id : Map ID
# event : Game_Event stored in $data
#----------------------------------------------------------------------------
alias script_condition_initialize initialize unless $@
def initialize(map_id, event)
# Default value and Shorthand
script, sc = nil, $game_map.script_conditions
# Iterate each of the Event's Pages
event.pages.each {|page|
# Store values in Condition Object for Self Switch Keys
page.condition.map_id, page.condition.event_id = map_id, event.id
# Iterate Each Command
page.list.each {|command|
# If Event Command is the first line of a Comment
if command.code == 108
# If Script is not nil (two Script Conditions in sequence)
if not script.nil?
# Modify Condition Object and Add to Hash for Evaluation
add_script_condition(page.condition, script, map_id, event.id, sc)
# Clear the String since it is now stored in the Condition Object
script = nil
end
# Scan the Comment and look for \skip_eval Comments for this Page
command.parameters[0].gsub(/^\\skip_eval/i) {
page.condition.skip_eval = true
}
# Use Regular Expression to look for "Condition:" and Capture String
command.parameters[0].gsub(/^Condition:(.*)/){ script = $1.strip }
# Else if Script and Event Command is a Comment, but not the first line
elsif not script.nil? and command.code == 408
# Append Script String with any text from this line of the Comment
script += "\n" + command.parameters[0]
# If Script String has contents
elsif not script.nil?
# Modify Condition Object and Add to Hash for Evaluation
add_script_condition(page.condition, script, map_id, event.id, sc)
# Clear the String since it is now stored in the Condition Object
script = nil
# Next Command (One Condition per Comment Box)
next
end
}
}
# Call Original or other Aliases
script_condition_initialize(map_id, event)
end
#----------------------------------------------------------------------------
# * Add Script Condition - Game_Event
# - Modifies the Condition Object with New Parameters for Script Evaluation
# c : RPG::Event::Page::Condition
# map_id : Map ID of Event
# event_id : Event ID
# sc : Shorthand for $game_map.script_conditions
#----------------------------------------------------------------------------
def add_script_condition(c, script, map_id, event_id, sc)
# Loop to check for Syntax Errors
begin
# Evaluate the Script String and remember result
result = eval(script)
# Script Evaluated has a Syntax Error
rescue
# Display Warning to User
script_condition_error(script, event_id, map_id)
# Prevent Storing of Script Condition
return
end
# Create a Boolean Value based on result for proper storage
value = (result) ? true : false
# Remember value of Script Evaluation in the Self Switch Hash
$game_self_switches[[map_id, event_id, script]] = value
# Create Array if Nil
c.script_condition = [] if c.script_condition.nil?
# Push Script on to Script Condition Array
c.script_condition << script
# Add Script to Script Conditions Hash in Game Map with Event ID as Key
sc[event_id] ? sc[event_id] << script : sc[event_id] = [script]
end
#----------------------------------------------------------------------------
# * Eval Script Condition - Game_Event
# - Evaluates Script Conditions
# scripts : Array of Scripts for this Event's Conditions
#----------------------------------------------------------------------------
def eval_script_condition(scripts)
# Default
refresh_event = false
# Iterate each Script in the Array
for script in scripts
# Run the Script and remember the result (Syntax already checked)
result = eval(script)
# Create a Boolean Value based on result for proper storage
value = (result) ? true : false
# If Stored Self Switch Value is not the same as the result
if $game_self_switches[[$game_map.map_id, id, script]] != value
# Store the Result in the Self Switches Hash
$game_self_switches[[$game_map.map_id, id, script]] = value
# Flag to Refresh this Event after running all Scripts if more than 1
refresh_event = true
end
end
# Refresh this Event if the Refresh Flag is set
refresh if refresh_event
end
#----------------------------------------------------------------------------
# * Script Condition Error - Game_Event
# - Prints a Warning and shows Script with a Syntax Error
# script : String of Script with Syntax Error
# id : Event ID with the Problem
# map_id : ID of Map with Event with Syntax Error in Condition
#----------------------------------------------------------------------------
def script_condition_error(script, id, map_id)
# If running game from Editor
if $DEBUG
# Explain the Problem
print "Warning: A Script Condition has a Syntax Error\n",
"Event ID: ", id, "\nMap ID: ", map_id, "\n\n",
"Condition: ", script, "\n\n",
"Conditions should evaluate to true or false\n",
"Example 1: Condition: $foo == $bar\n",
"Example 2: Condition: $foo == $bar or $baz"
end
end
#----------------------------------------------------------------------------
# * Erased? - Game_Event
# - Returns true if Event is Erased
#----------------------------------------------------------------------------
def erased?
return @erased
end
#----------------------------------------------------------------------------
# * Skip Eval? - Game_Event
# - Getter method, returns Flag set in RPG::Event::Page::Condition
#----------------------------------------------------------------------------
def skip_eval?
@page.condition.skip_eval if @page
end
#----------------------------------------------------------------------------
# * Skip Eval= - Game_Event
# - Setter method, sets Flag set in RPG::Event::Page::Condition
#----------------------------------------------------------------------------
def skip_eval=(arg)
@page.condition.skip_eval = (arg) ? true : false
end
end
#==============================================================================
# ** Game_Map
#==============================================================================
class Game_Map
#----------------------------------------------------------------------------
# * Public Instance Variables - Game_Map
#----------------------------------------------------------------------------
attr_accessor :script_conditions # Holds Event Script Page Conditions
#----------------------------------------------------------------------------
# * Setup - Game_Event
# - Creates a Hash to hold Script Conditions for constant Evaluation
# map_id : Map ID from $data
#----------------------------------------------------------------------------
alias script_condition_setup setup unless $@
def setup(map_id)
# If Map ID is Valid and does not match current Map ID
if map_id > 0 and map_id != @map_id
# Create or Clear Hash
@script_conditions = {}
end
# Call Original or other Aliases
script_condition_setup(map_id)
end
#----------------------------------------------------------------------------
# * Eval Script Conditions - Game_Map
# - Evaluates all Script Conditions in Hash and Refreshes Event if needed
#----------------------------------------------------------------------------
def eval_script_conditions
# Check that Script Conditions exists
return unless @script_conditions
# Iterate any Script Condition
@script_conditions.each {|id, scripts|
# Get the Event
event = @events[id]
# If Event does not exist (typically event removed during game editing)
if not event
# Remove the Script Conditions from the Hash
@script_conditions.delete(id)
# Next Script
next
end
# Skip this Event if Event has a Skip Eval flag
next if event.skip_eval?
# Evaluate Script Conditions (Array of Scripts) from within the Event
event.eval_script_condition(scripts) unless event.erased?
}
end
end
#==============================================================================
# ** Game_Screen
#==============================================================================
class Game_Screen
#----------------------------------------------------------------------------
# * Update - Game_Screen
# - Calls to eval_script_conditions in the Map, so it will still evaluate
# even during Battle Scenes
# - Game_Screen is updated after important objects are updated for proper
# timing of changing Pages. Thus, the Map, Events, Interpreter, Player
# and System are all updated before evaulating Script Conditions. If
# the evaluations were run, for example, prior to updating either the
# Player or Map Interpreter, Page Changes would occur at improper times
# and most likely cause you a headache trying to figure out why thinggs
# did not work as you expect at the times you expect.
#----------------------------------------------------------------------------
alias script_condition_update update unless $@
def update
# Call Original or other Aliases
script_condition_update
# Update any Event Script Conditions
$game_map.eval_script_conditions
end
end