Super Event Sensor - Event NPC AI [XP]
Authors: Heretic
Version: 1.12
Type: Event NPC AI
Key Term: Misc Add-on
IntroductionThis Script is highly useful as an Artifical Intelligence by allowing you to create different "behaviors" through Event Pages. When a Sensor is "Triggered", Self Switches change automatically! Since a Sensor can detect a Target both through "Sight" and "Sound", TWO Self Switches can be specified. Due to using up half of your Self Switches, it is HIGHLY RECOMMENDED that you also grab More Self-Switches (http://forum.chaos-project.com/index.php/topic,9855.0.html) by Game_Guy / gameus as it allows for More Page Conditions
Features
- Total Overkill of Options (yeah, I think that is kind of a feature)
- Highly Useful for Enemy AI
- Line of Sight to Target
- Different Types of Views (think Metal Gear)
- Obstruction of Line of Sight - WALL
- Can "See" Over Specified Tiles like Water for "Smarter Enemies"
- Triggered Settings can be Different than Non Triggered Settings
- Sensors can be set to Ignore Walls once triggered
- Uses Terrain Tags to Fix Problem Tiles like Water or Fences
- Should be compatible with Terrain Tag Scripts
- Can use Bush Tags to obstruct the View of Small Enemies
- Allows Terrain Tags to specify Trees that obstruct Flying Enemies View
- Sound - Movement makes Sound, and Movement can be Detected
- Sound Detection doesnt need additional scripts, just DONT MOVE!
- Compatible with Pathfinding Scripts
- Supports Suprise Attack Supported Battle Systems - XRXS Rewrite 1.03
- Suprise Attack Script Calls can prevent Event from turning toward Player
- Can Target ANY Game_Character, not just Player
- Move Route Index Reset on Detrigger - Trust me, you want this.
- Every Event can have Different Settings
- The Constants in Config are used for Defaults, you can change Per Event
- Expandable "View" Definitions by Easy Aliasing
- Added Triggers for Enemy Contact with Heretic's Caterpillar
- Stores XY Coordinates of First Seen and First Heard for other uses.
- Stores XY Coordinates of Location of Sensor Event for returning to path
- Stealth abilities enabled by Game Switches (not Self Switches)
- Stealth Switches can also alter View and Range
- Documentation - Intended for better understanding of specific parts
- Demo - Extremely complex script is given Demos for each feature
Screenshots
Image Borrowed from Little Drago's Simple Event Sensor
Concept is exactly the same with way way more features!
(http://i.imgur.com/6wfGJ.gif)
DemoThis Demo contains MANY different Scripts. A high number of the Scripts contained in this Collection Demo are designed to enhance Super Event Sensor! However, you should know that this Script can work just fine as a Standalone Script and is NOT DEPENDANT on any other Scripts!
http://downloads.chaos-project.com/heretic86/CollectionVer2.4.zip
Scripthttp://downloads.chaos-project.com/heretic86/SuperEventSensor1.12.txt
History Version 1.0 : Saturday, November 23rd, 2013
Version 1.01 : Saturday, October 18th, 2014
- Fixed a Bug with Caterpillar where Touch Events would Trigger even
if the Caterpillar was paused.
Version 1.02 : Saturday, April 4th, 2015
- Due to the creation of a Modular Passable Script which supports
a whole ton of features, another script called Looping Maps
needed to be made compatible
- Fixed a bug where Save Games had wrong pointer for $game_player
Bug caused loaded games to not recognize new instance of $game_player
as the Target for the Sensor.
InstructionsPut above Main and below Scene_Debug (and SDK if installed)
Create a Sensor by putting a COMMENT on Page 1 of an Event. It does NOT have to be at the Top of the Page, but needs to be fairly close. Also optional in the Scrit Configuration of how many lines to read while looking for Sensor_Configs
In the Comment, put the following:
Sensor_Config
range=4
listen=4
listen_switch=C
* The Keyword "Sensor_Config" needs to be on its OWN LINE. Do NOT put any Config Options on the same line as the Keyword of Sensor_Config!
Sensor_Config range=4 WILL NOT WORK!!!
* Do NOT use Spaces between your Option Name and Option Value
range = 4 WILL NOT WORK!!!
range=4 WILL WORK because there are No Spaces!!!
** See Documentation and Demo for explanation of the list of Sensor Config Options. There are a LOT of them!
** There are so many Options, that you can easily fill up an entire COMMENT BOX. Due to this, you can have MORE THAN ONE Sensor_Config! Each Sensor_Config needs to have Sensor_Config as the FIRST LINE.
CompatibilityNot compatible with SIMPLE Event Sensor due to the nature of the Script.
Should be compatible with everything else, including both major Pathfinder Scripts and the SDK.
NOTE: The only supported Battle System at this time for the "Suprise Attack" feature is Heretic's Overhaul of the XRXS Battle System - Version 1.03 and above (included in that massive Demo).
Credits and Thanks
- Little Drago for the Original Concept
- Blizzard for modifying his Lagless Pathfinder to expand the functionality of this Script
Author's NotesThis script is designed to Change Pages, which is where the Events Behaviors are created. Really, it is only about HALF of a true NPC AI as the other half would allow for movements toward the Sensor's Target.
I have no intention of making this Script work with VX or VX Ace.
Sensors can only detect ONE TARGET at this time. I will probably change this later so expect Updates!
Creating any form of Artifical Intelligence is not easy, considering the semi-limited functionality of the nature of RMXP. Because this script is so complex, expect to be confused by a good number of the Options!
Please ASK if you have any difficulty in getting your Sensors to work exactly as you expect them to, but do expect that they can behave exactly the way you want them to!
---
Updated to Version 1.12!
New features include full integration with Dynamic Lighting so you can use Darkness to hide from Sensors!
This looks pretty awesome! I love all the different options you build into it. Just one quick tip though after reading through your instructions. I really think that allowing users to have whitespace in their comments would be nice. It would be really annoying debugging a game just because you added an extra space. To do this just use
where you want to allow whitespace. Another way to do this would be just to use a regexp with
, which would ignore whitespace.
Not gonna add whitespaces, sorry. Once you really get into this script, you'll find that space in the Comment Boxes is really needed. I know I could put it in as optional, but decided not to because of the high number of space consuming options.
---
Off topic, I used your Event Transitions script in the Demo, if that's alright...
If a script is too large, there's always http://pastebin.com Not many people are willing to download a 70mb demo of a shit load of scripts just to figure out one script.
Quote from: gameus on November 28, 2013, 01:22:03 am
If a script is too large, there's always http://pastebin.com Not many people are willing to download a 70mb demo of a shit load of scripts just to figure out one script.
Agreed. I just put it up on an old server I still have access too. Not much space available on it, but for a text file, it works.
Please check Script page, It seems the file was removed.
this script is very useful but I don't want to download the demo for it.
That old server died, company went out of business. I just made a text file and put it up here without the rest of the very large and cumbersome demo. Its on the Script link in the original post.
Maybe too late to ask but... can I set some Event as Wall.
just like hinding behind the door or carriage.
Unfortunately no, cant use an Event as a Wall. Its a good idea and I wanted to do it, but the performance hit would have been way too much.
Is there a way to check if the player is currently been "seen"?
I tried doing it with switch (seen->on, defeat the guard->off), but if the player is been seen by two or more enemies at the same time, defeating the first one would set the switch off despite the fact player is still been seen.
(I'm using my own common-event-based battle system, so there is no scene transition between battles, and the sensors can not reset.)
Also, if you set something like listen=5, you get an error "Undefined method "move_speed" for Game_Player" on line 2044
You might need individual switches for each guard then.
Quote from: Helios on April 09, 2016, 05:53:08 am
Is there a way to check if the player is currently been "seen"?
I tried doing it with switch (seen->on, defeat the guard->off), but if the player is been seen by two or more enemies at the same time, defeating the first one would set the switch off despite the fact player is still been seen.
(I'm using my own common-event-based battle system, so there is no scene transition between battles, and the sensors can not reset.)
Also, if you set something like listen=5, you get an error "Undefined method "move_speed" for Game_Player" on line 2044
Sensors typically change Self Switches, but in your case, you could try directly accessing the @sensor object and do something like this:
On a Parallel event, run a Conditional Branch -> Script "$game_map.events[@event_id].sensor.can_see?" without the quotes. Then you can event to your hearts content, but, you cant interact with a Parallel Event.
Another thing you could try is doing the stuff in a Move Route.
@step_anime = (sensor.can_see?) ? true : false
You CAN interact with an Event like this, but, youre fairly limited to the Events you can do. Thats why they were set up to use Event Pages.
If you REALLY wanna get fancy, you can use Event Pages (Default is Self Switch D) so have a Page for Self Switch D and in a Move Route, use a script and put in the word "start" to start running event commands.
NOTE: Put the "start" move route on the Page that checks for Self Switch D
Quote from: Heretic86 on April 11, 2016, 06:37:10 amSensors typically change Self Switches, but in your case, you could try directly accessing the @sensor object and do something like this:
On a Parallel event, run a Conditional Branch -> Script "$game_map.events[@event_id].sensor.can_see?" without the quotes. Then you can event to your hearts content, but, you cant interact with a Parallel Event.
Another thing you could try is doing the stuff in a Move Route.
@step_anime = (sensor.can_see?) ? true : false
You CAN interact with an Event like this, but, youre fairly limited to the Events you can do. Thats why they were set up to use Event Pages.
If you REALLY wanna get fancy, you can use Event Pages (Default is Self Switch D) so have a Page for Self Switch D and in a Move Route, use a script and put in the word "start" to start running event commands.
NOTE: Put the "start" move route on the Page that checks for Self Switch D
Thanks for your reply, if my understanding is correct this Parallel Event serves as a "controller" instead of actual "guard" right? Anyway I got an error "undefined method 'can_see?' for nilclass".
P.S. What I'm trying to achieve here is something like "if any guard is seeing the player then lock that door/rise the alarm/etc etc until the guards are no longer alerted one way or the other"
And any luck with the "listen=" crash? This should be the easiest and most straightforward way to set up a listening guard, but it seems to be broken. Or it's caused by conflicting scripts? I can't really tell.
Ok, take a look at these two things:
#==============================================================================
#
# SUPER EVENT SENSOR ADDON[XP]
#
# - Run "guards_can_see?( [1,2,3] ) from Conditional Branch - Script in a
# Parallel Event. The numbers 1, 2, 3 need to be the EVENT IDs of your
# events you are using as Guards.
#
# ** REQUIRES "CONTROL SELF SWTICHES ANYWHERE" and SUPER EVENT SENSOR
#
#==============================================================================
#==============================================================================
# ** Interpreter
#==============================================================================
class Interpreter
#--------------------------------------------------------------------------
# * Guards Can See? - Interpreter
# - Run this in Event Commands -> Conditional Branch -> Script
# guard_ids : Array - Use Event IDs
# Example: guards_can_see?( [4,5,12,21,32,44,63] )
#--------------------------------------------------------------------------
def guards_can_see?(guard_ids)
return if not guard_ids.is_a?(Array)
# Default
result = false
# Iterate the Guards
for guard_id in guard_ids
# Get the Guard Event
guard = $game_map.events[guard_id]
# If the Guuard exists and Guard is a Sensor
if guard and guard.sensor
# Get the Guards "See" Switch
see_switch = guard.sensor.switch
# Check if that Self Switch is set to True
if guard.get_self_switch(see_switch) == true
# Set the Result Flag to True
result = true
# Quit iterating (performance)
break
end
end
end
# Return the Result
return result
end
end
#==============================================================================
#
# HERETIC'S CONTROL SELF SWITCHES ANYWHERE
# Version 1.1
# Saturday, November 15th, 2014
#
#==============================================================================
#
# - Version 1.1 added an Optional Argument for Map ID which allows for
# getting and setting Self Switches across different maps!
#
# The Default Game Engine allows you to change Game Switches from a Move Route
# but does NOT have anything to allow you to change Self Switches. This
# script will allow you to Check and Change ANY Self Switches for Any Event
# on your Current Map.
#
# * get_self_switch( Letter, event_id, (Optional) Map ID)
# - Letter is 'A', 'B', 'C', or 'D', WITH Quotes, Upper case doesnt matter
# - Returns True if Switch is ON
# - Returns False if Switch is OFF
# - Example : get_self_switch('A', 24)
# - Example : get_self_switch('D', id = 18, map_id = 5)
# * set_self_switch( Letter, On or Off, event_id, (Optional) Map ID)
# - Letter is 'A', 'B', 'C', or 'D', WITH Quotes, Upper case doesnt matter
# - Sets Switch Letter to Value (true or false, 'On' and 'Off' okay too)
# - Example : set_self_switch('B', true, id = 48)
# - Example : set_self_switch('C', 'On', id = 27, map_id = 12)
#
# The intent of this script is to save you from always having to use
# Game Switches by allowing you more access to Self Switches. Too
# many Game Switches can make your game excessively complex for things
# that will most likely only relate to Events on One Map. If you need
# to check Switches across Game Maps or during Battle, then the use of
# Game Switches is a better idea.
#
# NOTE: The script calls in Event -> Script and Move Route -> Script are
# quite similar, but not exactly the same. It may be easiest for you to
# use this script by calling ALL of the arguments.
#
# get_self_switch can use THREE Arguments
# set_self_switch can use FOUR Arguments
#
# If you have any difficulty with the Script Calls, just use all arguments
# and that will usually solve your problems. I tried to set up this script
# to provide lots of error messages that clearly explain what went wrong
# should something go wrong in your script call.
#
# NOTE: I allowed for the usage of get_self_switch inside of Set Move Route
# because you can use a Ternary Operator for Conditional Move Routes. It is
# very unlikely that you'll ever need to use get_self_switch inside of
# Set Move Route -> Script.
#
# NOTE: You can set a Self Switch for ANY Event on your Game Map, even from
# setting a Player Move Route -> Script. When using Player, you MUST call
# for an Event ID as the Game Player has no Self Switches. This may be
# much easier than jumping in and out of Set Move Route when trying to
# synchronize movements.
#
# Installation
#
# Put anywhere between the Default Scripts and Main. These are all unique
# definitions so this script should be perfectly compatible with ALL other
# scripts in existence.
#
# --- Limitations ---
#
# You cant use during either Battle or Different Maps.
#
# --- Usage ---
#
# You can use anywhere you can make a Script Call, except in Battle.
#
# For Conditional Branching, in Events Page 1, click on Conditional Branch.
# Then in Page 4 of the Conditional Branch, go to Script.
# In Script, enter "get_self_switch(Letter, event_id) == true / false"
# - Dont use Quotes on the whole statement
# - Dont use the word IF
# - (Letter is 'A', 'B', 'C', or 'D') WITH Quotes in the Script Call.
# - Event ID does NOT have Quotes.
#
# Dont forget you CAN PRINT anywhere you can enter a Script Call also.
# print get_self_switch(Letter, event_id)
#
# --- Version History ---
#
# Version 1.1 - Saturday, November 15th, 2014
# * Added Optional Argument for Map ID to change Self Switches for Events
# from different Maps entirely.
# NOTE: When specifying a Map ID, the Event is NOT checked for existence
#
# Version 1.0 - Monday, September 9th, 2013
# * Initial Release
#
#==============================================================================
class Game_Character
#--------------------------------------------------------------------------
# * Set Self Switch(ch, value, id, map_id) - Game_Character
# ch : A, B, C, or D
# value : true, false, 'On', 'Off', 1, or 0
# id : Event ID
# map_id : (Optional) Current or Specified Map ID
#
# - Change a Self Switch from a Move Route Event
#--------------------------------------------------------------------------
def set_self_switch(ch, value, id = @id, map_id = $game_map.map_id)
# if Player Move Route and id is not Specified
if id == 0 and $DEBUG
# Print Error
print "When using set_self_switch from Player Move Route, you need to\n",
"specify an Event ID because the Game Player does not\n",
"have any Self Switches"
end
# Valid Values
value_valid = [true, false, 0, 1, 'on','off']
if value.is_a?(String)
value = true if value.to_s.downcase == 'on'
value = false if value.to_s.downcase == 'off'
elsif value.is_a?(Integer)
value = true if value == 1
value = false if value == 0
end
# If we have A, B, C, or D, and the Event exists
if ch.is_a?(String) and "ABCD".include?(ch.upcase) and
(value == true or value == false) and
(map_id != $game_map.map_id or $game_map.events[id])
# If event ID is valid
if @id > 0 and
# Make Upper Case for Key
ch = ch.to_s.upcase
# Make a self switch key
key = [map_id, id, ch]
# Change self switches
$game_self_switches[key] = value
end
# Refresh map
$game_map.need_refresh = true
# Continue
return true
else
if $DEBUG
print "Warning: set_self_switch expects Two Arguments\n",
"The First Argument should be the letter A, B, C, or D\n",
"The Second Argument should be either True or False.\n",
"(On or Off is acceptable too. Just need you",
"to say what you want to set it to.)\n\n",
"Example: set_self_switch('A',true)\n\n",
"Example 2: set_self_switch('A','On')\n\n",
"There is an Optional 3rd Argument for",
"specifying an Event ID\n\n",
"Example 2: set_self_switch('B',false, 32)\n\n",
"This Script call to get_self_switch was made\n",
"from MOVE ROUTE => SCRIPT\n\n",
"set_self_switch in MOVE ROUTES => SCRIPT expect TWO Arguments,",
"THIRD Optional\n",
"set_self_switch in EVENT => SCRIPT expects THREE Arguments\n\n",
"Your Script: Move Route -> Script set_self_switch",
"('",ch,"','",value,"','",id,"')"
# If on the Same Map and Event doesn't exist, explain the Problem
if map_id == $game_map.map_id and not $game_map.events[id]
print "The Event ID: ", id, " you specified\n",
"doesn't exist on this map"
end
end
end
end
#--------------------------------------------------------------------------
# * Get Self Switch(ch, id) - Game_Character
# ch : A, B, C, or D
# id : Event ID
# map_id : (Optional) Current or Specified Map ID
#
# - Returns True if a Switch is ON, False if Switch is OFF
# - This is usually only good with Ternary Operator but I included it anyway
# Example: @direction = (get_self_switch('A',15) ? 8 : 2
#--------------------------------------------------------------------------
def get_self_switch(ch, id = @id, map_id = $game_map.map_id)
# if Player Move Route and id is not Specified
if id == 0 and $DEBUG
# Print Error
print "When using get_self_switch for Player Set Move Route,",
"you need to\n",
"specify an Event ID because the Game Player does not\n",
"have any Self Switches\n\n",
"Calling in Player with no ID argument causes\n",
"the ID to be set to 0"
end
# If we have A, B, C, or D, and the Event exists if same Map
if ch.is_a?(String) and "ABCD".include?(ch.upcase) and
id and (map_id != $game_map.map_id or $game_map.events[id])
# Make a Key
key = [map_id, id, ch.upcase]
return $game_self_switches[key]
else
if $DEBUG
print "Warning: get_self_switch expects Two Arguments\n",
"The First Argument should be the Letter of\n",
" the Self Switch you are Checking, A, B, C, or D\n",
"The Second Argument should be the Event's ID\n",
"Example: get_self_switch('B', 23)\n\n",
"This Script call to get_self_switch was made\n",
"from MOVE ROUTE => SCRIPT\n\n",
"Your Script: Move Route -> Script get_self_switch",
"('",ch,"','",id,"')"
if map_id == $game_map.map_id and not $game_map.events[id]
print "The Event ID: ", id, " you specified\n",
"doesn't exist on this map"
end
end
end
end
end
class Interpreter
#--------------------------------------------------------------------------
# * Get Self Switch(ch, id) - Interpreter
# ch : A, B, C, or D
# id : Event ID (Default to self.id)
# map_id : (Optional) Current or Specified Map ID
#
# - Returns True if a Switch is ON, False if Switch is OFF
# - This is NOT called from Move Route - Script
#--------------------------------------------------------------------------
def get_self_switch(ch, id = nil, map_id = $game_map.map_id)
# If we have A, B, C, or D, and the Event exists on same Map
if ch.is_a?(String) and "ABCD".include?(ch.upcase) and
id and (map_id != $game_map.map_id or $game_map.events[id])
# Make a Key for the Hash in a Key / Value Pair
key = [map_id, id, ch.upcase]
# Return the boolean value of the Self Switch
return $game_self_switches[key]
else
if $DEBUG
print "Warning: get_self_switch expects Two Arguments\n",
"The First Argument should be the Letter of\n",
" the Self Switch you are Checking, A, B, C, or D\n",
"The Second Argument should be the Event's ID\n",
"Example: get_self_switch('B', 23)\n\n",
"Note: The call that generated this error",
"was NOT called from a Move Route\n ",
"just an Event Script\n\n",
"Your Script: Event -> Script get_self_switch('",ch,"','",id,"')"
# Explain the Problem of No ID
if id.nil?
print "The Event ID: ", id, " isn't set in your script call"
# If on the Same Map and Event doesn't exist, explain the Problem
elsif map_id == $game_map.map_id and not $game_map.events[id]
print "The Event ID: ", id, " doesn't exist on this map"
end
end
end
end
#--------------------------------------------------------------------------
# * Set Self Switch(ch, value, id) - Interpreter
# ch : A, B, C, or D
# value : true, false, 'On', 'Off', 1, or 0
# id : Event ID (default self.id)
# map_id : (Optional) Current Map ID or Specified Map ID
#
# - Change a Self Switch for any Event from another Event -> Script
# - Use this ONLY to change a Self Switch for another Event. The
# game engine already has a button for changing Self Switches.
# - This is NOT called from Move Route - Script
#--------------------------------------------------------------------------
def set_self_switch(ch, value, id = nil, map_id = $game_map.map_id)
# Valid Values
value_valid = [true, false, 0, 1, 'on','off']
if value.is_a?(String)
value = true if value.to_s.downcase == 'on'
value = false if value.to_s.downcase == 'off'
elsif value.is_a?(Integer)
value = true if value == 1
value = false if value == 0
end
if ch.is_a?(String) and "ABCD".include?(ch.upcase) and
(value == true or value == false) and id and
(map_id != $game_map.map_id or $game_map.events[id])
# If event ID is valid
if id > 0 and
# Make Upper Case for Key
ch = ch.to_s.upcase
# Make a Key for the Hash in a Key / Value Pair
key = [map_id, id, ch]
# Set the boolean value of the Self Switch (true / false)
$game_self_switches[key] = value
end
# Refresh map
$game_map.need_refresh = true
# Continue
return true
else
if $DEBUG
print "Warning: set_self_switch expects THREE Arguments\n",
"The First Argument should be the letter A, B, C, or D\n",
"The Second Argument should be either True or False\n",
"The 3rd Argument is used to specify an Event ID\n\n",
"Example: set_self_switch('B','Off', 32)\n\n",
"Note: The call that generated this error ",
"was NOT called from a Move Route\n",
"just an Event Script\n\n",
"set_self_switch in MOVE ROUTES => SCRIPT expect TWO Arguments,",
"THIRD Optional\n",
"set_self_switch in EVENT => SCRIPT expects THREE Arguments\n\n",
"Your Script: Event -> Script set_self_switch('",ch,"','",value,
"','",id,"')"
# Explain the Error to the User
if id.nil?
print "The Event ID: ", id, " isn't set in your script call"
# If on the Same Map and Event doesn't exist, explain the Problem
elsif map_id == $game_map.map_id and not $game_map.events[id]
print "The Event ID: ", id, " doesn't exist current Map"
end
end
end
end
end
That should allow you to do what you are seeking. Just run "guards_can_see?( [1, 2, 5, 16] )" in a Conditional Branch -> Script. Im pretty sure I already did this, but theres only a thousand lines of documentation, literally...
---
Edit: Quick thought, if you use a Self Switch to detect "Defeated", change " if guard.get_self_switch(see_switch) == true" add to it " and not guard.get_self_switch('A')" to make sure dead guards dont trigger changes, assuming switch A is a self switch for defeat.
Quote from: Heretic86 on April 11, 2016, 10:16:38 pm
SUPER EVENT SENSOR ADDON[XP]
Just what I need, many thanks! Works perfectly.
Now about that "listen=X" cause "undefined method move_speed in Game_Player" bug...
After a lot of trial-and-errors, I figured out the problem. It was caused by the absent of "HERETIC's CATERPILLAR SCRIPT".
Tested by deleting the Caterpillar script in "CollectionOfArtAndScripts", got the same error.
In other words, if you use "Super Event Sensor" but not "HERETIC's CATERPILLAR SCRIPT", you'll get this error when you walk into a guard with "listen=X".
Could you please make a fix for that? Shouldn't be too hard I guess.
class Game_Character
attr_accessor :move_speed
end
I probably forgot to put that in as it was made available by another script somewhere...
Yep, that did it! Thanks again.
Thanks for letting me know.
Theres usually two things I find myself messing up constantly. Forgetting to put in attr_accessors and messing with Save Games. Im glad the fix worked. I'm working on putting together some Demo Maps for a couple of new scripts to put in my Collection. New version with this teeny weeny bugfix will be up pretty soon!
Another question:
Is there a way to have more than one set of "Sensor_Config" for the same event? It seems the "Sensor_Config" settings are fixed to page 1 even if there is another set of "Sensor_Config" on later pages.
Or if there is a way to disable its "Sensor_Config" state completely? So the "guard" would still move along its patrol route but ignore the player, and act like a normal NPC if talked to. Currently if a NPC is made a guard by putting "Sensor_Config" on page 1, they retain their guard status no matter what page they are on.
What I'm trying to achieve here is a "disguised" state. Think Hitman series, when the player is in a public area guards have no reason to be hostile to the player (the second method, guard act like normal NPC). When the player put on some disguise like enemy uniform, they could enter restricted zones but enemy would notice the player up close (the first method, by changing the view range to 1 or 2).
I try to do it with multiple copies of map, but it would mean at least 3 different version of the same map (safe, disguised, hostile), and the change won't take effect until you leave the current map.
For your situation, take your view page, and immediately to the right of that, put another page that checks for the view condition Self Switch. This is where certain types of equipment and a script called "Auto State Switches" comes in to play. Create a Ring or some sort of item the Player equips as a "Disguise". Create a "state" called "disguise" in your Database. Set up the config in Auto State Switches for the Item ID of the "Disguise Ring", and the Game Switch you want to turn on and off. Thus, when your players equip that item on any of the characters in the party, the Game Switch is turned on. When they unequip it, that Game Switch is automatically turned off. Use that Switch ID as an additional page condition for your Guard character, and a standard condition the See Self Switch, typically D. Then you can just Event out what you want to happen from there on that page. Since this page is to the right of your "See Trigger Page" and to the left of the "Defeated" page, this page will be used when youre in disguise, but not if the guard event is already defeated.
Do NOT use your Stealth Gear switches, if you are incorporating that as well. This is a normal Game Switch that youre customizing your guards in this area for. Just tie that Game Switch and Equipment ID together in the script config of Auto State Switches. That is all that needs to be done. Its just Changing Pages. Pages to the right will be executed before a Page to the left. Your "Disguised" page can just be text like "guard duty is so boring" or something like that. No battles, just dialogue. How ever you want to event it.
Heres the point. Super Event Sensor at its core is just a very fancy way of changing event pages. And each of those Pages can be overridden with just more Pages and Conditions. Although Super Event Sensor is complex, the nature of simply changing Pages and checking Page Conditions allows customization without scripting!
That's not the problem here. I know how switches and event page orders work btw, been playing around with RM series since 2008.
The problem here is when you switch page, their move route would reset. This won't be a problem for stationary guards, but moving guards would turn back and try to reach their first waypoint if you put the same move route on that page, or just stand still if you do not, and again go for the first waypoint when you leave their sight because they are on the first page again. The result looks like every guard is trying to avoid you. That's why I want to disable the "Sensor_Config" entirely. Nevermind. I just realized its more about Path Finder than SES. I'll make do with that.
No problem.
Handling Pathfinding with SES was tricky when the script was built because the Pathfind was cleared between page changes.
Aside from that, the whole explanation of Switches and Pages wasnt directed at you specifically. As this is a public support question, you probably wont be the only one probably with similar questions, so answers like that are intended to help out people who may be reading our conversation in an effort to resolve the same issue. Some of those other people may or may not have a strong grasp of what Event Pages and Page Conditions are, so it just tries to provide ideas of doing things as simply and easily as possible. Unfortunately, sometimes that involves using additional scripts to do things that may not have been considered.
If you still need any help, let me know.
After some analysis of your script, I figured out how to disable and enable SES on the fly.
Find this line, should be somewhere around line 1505.
return if not @enabled or $game_map.events[@id].starting or not @target
add a switch check:
return if not @enabled or $game_map.events[@id].starting or not @target or $game_switches[123] == true
and turn that switch on to disable SES.
Actually it didn't disable the entire script, it just make the guards stop caring about you (and pretty much everything else).
Then, on the "GUARD TRIGGER BATTLE" page, add something to differ the guards reaction:
if $game_switches[123] == true
"peaceful dialog"
else
"BATTLE"
end
Then edit the move route:
change
into
$game_switches[123] ? $game_system.map_interpreter.self_switch("D", false, @id):@move_type = 2
$game_switches[123] ? $game_system.map_interpreter.self_switch("huh", false, @id):@move_type = 2
This will prevent them from chasing you after "peaceful" dialog, especially if you use Multiple Message Windows "Auto-close" function.
Ta-da! You can now put on/off disguise by turning that switch.
Hi, it's me again. :haha:
Recently I have observed another issue: stationary guards won't change direction after returning to post.
This is the movement setting of Page 1:
PathFinder.dyn_request(@id, [13, 47],0,true) <---- So they would return to their post after giving up the chase.
wait 1 frame
face Left <---- not working, the guard would return to 13,47 but does not change direction, usually facing the wall at this point, which would make subsequent sneaking attempts hilariously easy. :facepalm:
I think this might be caused by the Lagless Path Finder, but can't nail down the exact reason.
It has nothing to do with either of the scripts--your eventing is the problem.
When you use the script call the dynamically path find, the event commands don't just stop there and wait until the event reaches its destination. The event will keep running through its commands. Basically, frame 1 you make the path request and call the Wait event. Then, frame 3 I believe (frame 2 would be if Wait was 0.0 sec) it will change the event to face left--which gets lost since the path finding script is currently moving the event.
I don't see anything in the path finder script that allows executing event commands upon reaching its destination, so you're going to have to find another way to event that in. Something like making a parallel process that checks if the event's coordinates are [13,47] then face left.
If I change
PathFinder.dyn_request(@id, [13, 47],0,true)
to
PathFinder.dyn_request(@id, [13, 47],1,true)
Then the turning command works. I add another "wait 60 frames" after the turning command to make the result more obvious, and the guard would do like this (after giving up the chase):
walk to the target tile
turn left
wait 60 frames
walk 1 tile away from the target tile
turn left
wait 60 frames
And then the guard would repeat the above. The turning command does work.
The same setting would fail to work if I change RANGE to 0. The guard would get stuck on the "walk to the target tile" part, without running the subsequent commands. I confirmed this by adding a "Play SE" command before "turn left". With RANGE 1, the SE plays every time the guard turns. With RANGE 0, the guard move to the target tile and does not turn, and the SE never plays.
BUT, this only happens when the guard is returning from giving up chasing the player. If the guard begins on a different tile other than the target tile when the map is loaded, and then move towards the target tile, it does turn when reaching it even if RANGE is 0. So I'm not sure which script is causing the problem now.
It might be easier to just use a move left or move right command if the guard is only moving one tile. For example, Pathfind XY 20, 20, Wait 60 frames, Pathfind 50, 50, Wait 60 frames. Pathfinding too close with a range of 1 would when only moving 1 tile would cause Pathfinding to be skipped.
One of the problems with Move Routes in general is that each Move Command (like Move Left or Move Up) don't have an option to make individual moves skippable. They also dont handle conditions very well without scripting, but it IS possible. Hence, why we have Pathfinding scripts. There are some cases where the use of other tricks without Pathfinding calls is simpler to pull off.
Some of the Tricks I use when making complex Move Routes involve changing the Index to cause a loop to occur as a way of making a Conditional Branch to ensure event positions:
$>Turn Left
$>Wait: 15 Frame(s)
$>Script: @move_route_index -= 2 if @x != 27 or @y != 53
$>Move Left
Using a "@move_route_index -= 1" will ALWAYS cause your game to hang so ALWAYS adjust a Move Route Index by 2 or more.
(NOTE: Pathfinding scripts generate their own Move Routes so Index adjustments are not recommended)
---
One other thing that may be worth while to note is Pathfinding sometimes fails if the Player (or Caterpillar) is standing at the location an event is trying to Pathfind to. I may have to do some work to allow Character Events like Guards to pathfind correctly even if the Player is at the location an event is trying to pathfind to. That is usually the reason that a Range of 1 is needed for correct pathfinding. Current possible untested workaround, Pathfind to a location with a range of 1, Wait a frame, then pathfind again to the same location with a range of 0.
Thank you for your reply.
I think a demo would explain better so here it is.
https://mega.nz/#!dZE0EAzB!NMBY8O4tEoBPlq-8D-4NytkjsaWK65oeWwS1Qh385Lk
Note the guard on the left (with RANGE 0) walk toward the target tile and face left as commanded.
Now move the Player to the top of the screen. Wait for both guards to investigate then give up and return to their target tile.
The guard on the right (with RANGE 1) would walk up and down, but still face right as commanded.
The guard on the left will get stuck on the target tile without running any subsequent command (like face left). <-- This is the problem.
It only happens if the guard is returning from chasing. If the guard can't chase the player somehow (i.e. by extending both walls to the bottom of the map), or if the guard was undisturbed (like in the beginning), the guard would face left normally.
There definitely is something screwy. Everything checks out correctly up until the end of Page 2's move route. It jumps back to Page 1 after turning off the "huh" switch, but the @move_route_index variable doesn't start back at 0; rather it continues off to the next value it was before leaving Page 1 (EDIT: due to event sensor
@move_route_index = @sensor.last_page_data[0]). Then, after returning to its spot, it jumps to using the move route in Page 3 while still interpreting Page 1, thereby hanging the move route processing (EDIT: caused by calling force_move_route, which stores the @move_route and @move_route_index to @original_* variables (and restores them after the event returns back to their spot)).
To see what I mean, please follow these dubugging steps:
First, add this script to the project: http://forum.chaos-project.com/index.php/topic,7816.0.html
In Game_Character 2, add this to
move_type_custom, right under while
@move_route_index < @move_route.list.size
puts [@move_route_index, @move_route.list.size]
puts "Page #{@event.pages.index(@page) + 1}"
Remove the right guard and playtest.
Throw in some commented scripts in the move routes too--it'll make the problem more obvious.
So ehhhh... how to fix this? I did what you said and still pretty clueless.
It's pretty much up for Heretic to decide. Clearly, there's an incompatibility going on here.
@Heretic: If you can make it so that the @original_move_route(_index) variables only get applied to the @move_route(_index) variables if the event is currently on the same page, this would probably fix it. Either that or just reset @original_move_route(_index) every time the page changes, perhaps?
I may have to look at this weekend. A bit busy right now.
Are there any other scripts that affect pages or move routes that I didnt make?
Only other thing is the extra self switches but I am pretty sure that is not the problem.
It shouldnt be.
Just woke up, sort of thinking about this when Ive had time for a few days. I think what has happened is if a space is occupied by an event when pathfinding by the player, the pathfind may fail. Not sure. Have a ton of code re-reading to look thru to see what is going on.
Just repeat what I did in my test above. I only had one event on the map. I already told you the cause, you just need to find a reasonable solution to it.
I havent started work on a fix for this yet. :(
Two known issues. First is some trouble with Pathfinding.
#1 - If the spot a guard / npc pathfinds to is occupied by the player, pathfinding typically fails. I may need to use Modular Passable to make a fix for that, but I am hesitant because I dont want to force dependancies. Basically, a pathfinding event should not consider the Players position during a pathfind calculation (or caterpillar).
#2 - Move Route Indeces - Im thinking a possible solution to this would be to use a Hash and set the Page as a Hash Key to retain the Move Route Index across page changes. Move Routes are already per page. The Index resets properly, but when there are too many page changes, I think the wrong Index may be in use.
Before I start working on this, does this sound like an acceptable resolution to the problem?
Im sorry for the delay, been working a lot lately, and holidays, havent had much down time...
No problem, take your time. I'm not in any hurry. :)
Just make sure you try the DEMO I posted above when you are ready to work on this. No need to take guesses here.
The first is not the case - pathfinding is successful, problem occurs after the successful pathfinding.
Not sure about the second - although there are 8 pages in the guard event, only the first 3 are actually activated, and the guard did use the first page's move route so I think page/index switching is also successful, or at least partially.
=================================================
Eh, it's been 3 months... any news?
Hello, Heretic86! First of all, thank you very much for your Super Event Sensor script, it is just perfect for my project! Now forgive me if I am being dumb, but I just cannot figure out how to make the event go back to its starting position when the target is out of range. My event has 3 pages:
- Page 1 has a custom move route (it is not stationary) and the sensor comment (Sensor_Config;range=4).
- Page 2, which is triggered by self-switch A, has the approach route and the battle processing on event touch.
- Page 3 is triggered by self-switch B but it is just an empty page for when the enemy is defeated.
When the player is out of range, the event does not go back to its starting position but instead stays exactly where it lost track of the player. I am not using a path finding script so far. Do I need to use one? Would you please help me? Thanks in advance!
You mention the event moves towards the player. Where and how are you making the event move back to its starting location?
I get the question now...
Yes, you should use a path-finding script since it's not built-in to RMXP's default move event commands.
Quote from: Denver on June 07, 2017, 10:06:15 am
Hello, Heretic86! First of all, thank you very much for your Super Event Sensor script, it is just perfect for my project! Now forgive me if I am being dumb, but I just cannot figure out how to make the event go back to its starting position when the target is out of range. My event has 3 pages:
- Page 1 has a custom move route (it is not stationary) and the sensor comment (Sensor_Config;range=4).
- Page 2, which is triggered by self-switch A, has the approach route and the battle processing on event touch.
- Page 3 is triggered by self-switch B but it is just an empty page for when the enemy is defeated.
When the player is out of range, the event does not go back to its starting position but instead stays exactly where it lost track of the player. I am not using a path finding script so far. Do I need to use one? Would you please help me? Thanks in advance!
I would actually recommend using a pathfinding script. There are two to choose from in the Collection so you should have both.
On Page 1, instead of using standard movement commands, instead, have your event pathfind its patrol route. That will allow your character go back to where they were before they saw the player.
I apologize if I am necroposting this but I need to ask, is this compatible with Blizz ABS?
Honestly, not sure. Probably. I dont think the Blizz ABS does anything with Switches, so in theory it should be. You could try it out and see if it is or is not, then post! If it isnt, then both Blizz and I will have some work to do as they would be quite nice working with each other...