Stealth Detection System (SDS) Multi-style stealth system (v1.1 since June 17 2008)
Version: 1.1 Creator: Cmpsr2000 VX Release Date: June 17 2008 Exclusive VX Version:Stealth Detection System for VX Edited by: Night_Runner XP Release Date: July 13 2010
Introduction SDS allows the developer to build games that include "Stealth" features similar to certain Final Fantasy games or even Metal Gear Solid. . Features Make any event "aware" of its surroundings, effectively turning it into a "guard" Execute 4 different actions on detection: Mode 0: Send to Jail (transfer player) Mode 1: Game Over Mode 2: Common Event Mode 3: MGS Mode Create a "jail" event anywhere on the map! MGS Mode allows guards to be alerted before trying to capture the player Guard intercept speed in MGS mode can be customized Final capture action in MGS mode can be customized Guard search time in MGS mode can be customized Guards can have custom sight ranges Guards can have tunnel vision or a "cone" field of view Tunnel width for tunnel vision can be customized Guards' sight is blocked by objects by default, but this can be disabled by granting "truesight" Mode 2 can execute any custom event you specify Guards have a circle of awareness around themselves that can be disabled if desired Script
Redefinitions
CODE
#------------------------------------------------------------------------------- # This is a surprise ^^ #------------------------------------------------------------------------------- module Sound def self.play_found Audio.se_play("Audio/SE/found.wav", 100, 100) end end
#------------------------------------------------------------------------------- # This contains command for object movement and can be reused and included in # any game_character or it's descendants. #------------------------------------------------------------------------------- module Movement #----------------------------------------------------------------------------- # Checks to see whether this object has moved since the last check. # RETURNS: Boolean #----------------------------------------------------------------------------- def moved? if self.x != @oldX or self.y != @oldY setPosition return true else return false end end #----------------------------------------------------------------------------- # Checks to see whether this object has turned. # RETURNS: Boolean #----------------------------------------------------------------------------- def turned? if self.direction != @oldDirection setDirection return true else return false end end #----------------------------------------------------------------------------- # Saves the current direction so that it can be checked against after a turn #----------------------------------------------------------------------------- def setDirection @oldDirection = self.direction end #----------------------------------------------------------------------------- # Saves the current position so that it can be checked against after a move #----------------------------------------------------------------------------- def setPosition @oldX = self.x @oldY = self.y end #----------------------------------------------------------------------------- # Changes the object's route to perform an in-place spin while waiting after # each turn. It is recommended to call object.lock before using this, and # call object.unlock when it has complete. #----------------------------------------------------------------------------- def spinInPlace(waitTime) spinRoute = RPG::MoveRoute.new spinRoute.repeat = false #spinRoute.wait = true for x in 0..3 spinRoute.list.push(RPG::MoveCommand.new(15, [waitTime])) spinRoute.list.push(RPG::MoveCommand.new(16 + x)) end spinRoute.list.push(RPG::MoveCommand.new(15, [waitTime])) spinRoute.list.push(RPG::MoveCommand.new(0)) spinRoute.list.delete_at(0) #weird RGSS Anomoly, must delete empty position
self.move_route = spinRoute self.move_route_index = 0 end #----------------------------------------------------------------------------- # This is an advanced pathfinding algorithm that returns a boolean indicating # whether or not it was able to find a path from the start point (the object's # current location) to the endpoint, then changes the object's move values # to initiate movement. RETURNS: Boolean # finalX: x coordinate of the destination # finalY: y coordinate of the destination #----------------------------------------------------------------------------- def goto(finalX, finalY) return true if self.x == finalX and self.y == finalY startX = self.x startY = self.y
#main logic while @closedList.index(finalNode) == nil nodeToCheck = @activeList[0] #lowest F is always in position 0! if nodeToCheck == nil noPath = true break end moveToClosed(nodeToCheck) for node in adjacentNodes(nodeToCheck) #a "node" is an array: [x, y] !!! if ($game_map.passable?(node[0], node[1], 0) and @closedList.index(node) == nil) or node == finalNode index = @activeList.index(node) if index == nil scores = calcScores(node, nodeToCheck, finalNode) insertionPoint = findInsertionPoint(scores[0]) @activeList.insert(insertionPoint, node) @activeParents.insert(insertionPoint, nodeToCheck) @activeScores.insert(insertionPoint, scores) else g = calcG(nodeToCheck) if g < @activeScores[index][1] @activeParents[index] = nodeToCheck h = @activeScores[index][2] f = g + h @activeScores[index] = [f, g, h] insertionPoint = findInsertionPoint(@activeScores[index][0])
#we don't need to reinsert if we already exist in the right place if insertionPoint != index tempNode = @activeList[index] tempParent = @activeParents[index] tempScores = @activeScores[index]
#reinsert @activeList.insert(insertionPoint, tempNode) @activeParents.insert(insertionPoint, tempParent) @activeScores.insert(insertionPoint, tempScores) end end end end end end
#return if there is no path, otherwise build the path return false if noPath path = [finalNode] parent = @closedParents[@closedList.index(finalNode)] while parent != [startX, startY] path.push(parent) parent = @closedParents[@closedList.index(parent)] end path.reverse! #put the path in order of execution
#make a new route object that doesn't repeat (one time use only!) gotoRoute = RPG::MoveRoute.new gotoRoute.repeat = false
#itterate through the path and add the appropriate commands to the route #we can't move diagonal, so only one x or one y should change between steps lastNode = [startX, startY] for node in path if node[0] > lastNode[0] commandCode = 3 # move right elsif node[0] < lastNode[0] commandCode = 2 # move left else if node[1] > lastNode[1] commandCode = 1 # move down elsif node[1] < lastNode[1] commandCode = 4 # move up end end lastNode = node gotoRoute.list.push(RPG::MoveCommand.new(commandCode)) end gotoRoute.list.push(RPG::MoveCommand.new(0)) gotoRoute.list.delete_at(0) #weird RGSS Anomoly, must delete empty position
#set the object's route and return! self.move_route = gotoRoute self.move_route_index = 0 return true end #----------------------------------------------------------------------------- # moves the active node to the closed list so it's not checked twice! #----------------------------------------------------------------------------- def moveToClosed(activeNode) index = @activeList.index(activeNode)
#add to closed @closedList.push(@activeList[index]) @closedParents.push(@activeParents[index]) @closedScores.push(@activeScores[index])
#delete from active @activeList.delete_at(index) @activeParents.delete_at(index) @activeScores.delete_at(index) end #----------------------------------------------------------------------------- # finds the array insertion point based on the f score #----------------------------------------------------------------------------- def findInsertionPoint(f) insertionPoint = 0 if @activeList.length != 0 while insertionPoint < @activeList.length if f <= @activeScores[insertionPoint][0] break else insertionPoint += 1 end end end
return insertionPoint end #----------------------------------------------------------------------------- # calculates all the scores for a node #----------------------------------------------------------------------------- def calcScores(node, parentNode, finalNode) h = calcH(node, finalNode) g = calcG(parentNode) f = g + h
return [f, g, h] end #----------------------------------------------------------------------------- # calculates the G value (route distance) #----------------------------------------------------------------------------- def calcG(parentNode) #can't move diagonly: just add 1 to parent score index = @closedList.index(parentNode) score = @closedScores[index][1] + 1 return score end #----------------------------------------------------------------------------- # claculates the H value (distance from start to finish) #----------------------------------------------------------------------------- def calcH(node, finalNode) #Manhattan method is admissible in this context score = (node[0] - finalNode[0]).abs + (node[1] - finalNode[1]).abs
return score end #----------------------------------------------------------------------------- # Finds the adjacent nodes of the active node #----------------------------------------------------------------------------- def adjacentNodes(sourceNode) node1 = [sourceNode[0] + 1, sourceNode[1]] node2 = [sourceNode[0], sourceNode[1] + 1] node3 = [sourceNode[0] - 1, sourceNode[1]] node4 = [sourceNode[0], sourceNode[1] - 1] return [node1, node2, node3, node4] end end
#------------------------------------------------------------------------------- # the instance of $game_stealth needs to be created #------------------------------------------------------------------------------- class Scene_Title alias oldCommandNewGameStealth command_new_game def command_new_game $game_stealth = Game_Stealth.new oldCommandNewGameStealth end end
#------------------------------------------------------------------------------- # saveing and loading $game_stealth #------------------------------------------------------------------------------- class Scene_Save #-------------------------------------------------------------------------- # * Write Save Data # file : write file object (opened) #-------------------------------------------------------------------------- alias old_WriteSaveDataStealth write_save_data def write_save_data(file) old_WriteSaveDataStealth(file) Marshal.dump($game_stealth, file) end end class Scene_Load #-------------------------------------------------------------------------- # * Read Save Data # file : write file object (opened) #-------------------------------------------------------------------------- alias old_ReadSaveDataStealth read_save_data def read_save_data(file) old_ReadSaveDataStealth(file) $game_stealth = Marshal.load(file) end end
#------------------------------------------------------------------------------- # The stealth system needs to be updated every frame along with the map scene #------------------------------------------------------------------------------- class Scene_Map alias oldUpdateStealth update def update oldUpdateStealth unless $game_temp.message_window_showing # Unless displaying a message $game_stealth.update end end end
class Game_Character alias nr_sds_initialize initialize def initialize(*args) nr_sds_initialize(*args) @move_failed = false end #-------------------------------------------------------------------------- # * Determine if Stopping #-------------------------------------------------------------------------- def stopping? return (not (moving? or jumping?)) end #-------------------------------------------------------------------------- # * Move Down # turn_enabled : a flag permits direction change on that spot #-------------------------------------------------------------------------- def move_down(turn_enabled = true) # Turn down if turn_enabled turn_down end # If passable if passable?(@x, @y, 2) # Turn down turn_down # Update coordinates @y += 1 # Increase steps increase_steps # Set move failed flag @move_failed = false # If impassable else # Determine if touch event is triggered check_event_trigger_touch(@x, @y+1) # Set move failed flag @move_failed = true end end #-------------------------------------------------------------------------- # * Move Left # turn_enabled : a flag permits direction change on that spot #-------------------------------------------------------------------------- def move_left(turn_enabled = true) # Turn left if turn_enabled turn_left end # If passable if passable?(@x, @y, 4) # Turn left turn_left # Update coordinates @x -= 1 # Increase steps increase_steps # Set move failed flag @move_failed = false # If impassable else # Determine if touch event is triggered check_event_trigger_touch(@x-1, @y) # Set move failed flag @move_failed = true end end #-------------------------------------------------------------------------- # * Move Right # turn_enabled : a flag permits direction change on that spot #-------------------------------------------------------------------------- def move_right(turn_enabled = true) # Turn right if turn_enabled turn_right end # If passable if passable?(@x, @y, 6) # Turn right turn_right # Update coordinates @x += 1 # Increase steps increase_steps # Set move failed flag @move_failed = false # If impassable else # Determine if touch event is triggered check_event_trigger_touch(@x+1, @y) # Set move failed flag @move_failed = true end end #-------------------------------------------------------------------------- # * Move up # turn_enabled : a flag permits direction change on that spot #-------------------------------------------------------------------------- def move_up(turn_enabled = true) # Turn up if turn_enabled turn_up end # If passable if passable?(@x, @y, 8) # Turn up turn_up # Update coordinates @y -= 1 # Increase steps increase_steps # Set move failed flag @move_failed = false # If impassable else # Determine if touch event is triggered check_event_trigger_touch(@x, @y-1) # Set move failed flag @move_failed = true end end #-------------------------------------------------------------------------- # * Move Lower Left #-------------------------------------------------------------------------- def move_lower_left # If no direction fix unless @direction_fix # Face down is facing right or up @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction) end # When a down to left or a left to down course is passable if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 4)) or (passable?(@x, @y, 4) and passable?(@x - 1, @y, 2)) # Update coordinates @x -= 1 @y += 1 # Increase steps increase_steps # Set move failed flag @move_failed = false else # Set move failed flag @move_failed = true end end #-------------------------------------------------------------------------- # * Move Lower Right #-------------------------------------------------------------------------- def move_lower_right # If no direction fix unless @direction_fix # Face right if facing left, and face down if facing up @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction) end # When a down to right or a right to down course is passable if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 6)) or (passable?(@x, @y, 6) and passable?(@x + 1, @y, 2)) # Update coordinates @x += 1 @y += 1 # Increase steps increase_steps # Set move failed flag @move_failed = false else # Set move failed flag @move_failed = true end end #-------------------------------------------------------------------------- # * Move Upper Left #-------------------------------------------------------------------------- def move_upper_left # If no direction fix unless @direction_fix # Face left if facing right, and face up if facing down @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction) end # When an up to left or a left to up course is passable if (passable?(@x, @y, 8) and passable?(@x, @y - 1, 4)) or (passable?(@x, @y, 4) and passable?(@x - 1, @y, 8)) # Update coordinates @x -= 1 @y -= 1 # Increase steps increase_steps # Set move failed flag @move_failed = false else # Set move failed flag @move_failed = true end end #-------------------------------------------------------------------------- # * Move Upper Right #-------------------------------------------------------------------------- def move_upper_right # If no direction fix unless @direction_fix # Face right if facing left, and face up if facing down @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction) end # When an up to right or a right to up course is passable if (passable?(@x, @y, 8) and passable?(@x, @y - 1, 6)) or (passable?(@x, @y, 6) and passable?(@x + 1, @y, 8)) # Update coordinates @x += 1 @y -= 1 # Increase steps increase_steps # Set move failed flag @move_failed = false else # Set move failed flag @move_failed = true end end end
class Game_Player < Game_Character include Movement attr_accessor :detected def transfer(new_map, new_x, new_y, new_dir) # Set transferring player flag $game_temp.player_transferring = true # Set player move destination $game_temp.player_new_map_id = new_map $game_temp.player_new_x = new_x $game_temp.player_new_y = new_y $game_temp.player_new_direction = new_dir Graphics.freeze # Set transition processing flag $game_temp.transition_processing = true $game_temp.transition_name = "" end end
#------------------------------------------------------------------------------- # Events have tons of new attributes with the stealth system. Plus, we need to # include the movement module and initialize awareness to false. #------------------------------------------------------------------------------- class Game_Event < Game_Character include Movement
Demo: SDS DEMO for XP You'll also need this sound if you didn't download the demo: found.wav ( 83.52K )
Number of downloads: 59
Customization For customization, go to the original thread - Stealth Detection System for VX. As customizing the script is the same for both systems. Compatibility
QUOTE (Night_Runner @ Jan 3 2010, 02:37 AM)
Give this a shot, I haven't tested it extensively, so there's almost guaranteed to be at least 999 bugs, but I tried re-enacting all the default maps, and I didn't notice anything odd, oh well, give it a shot, and let me know
As you can see it's still kind of in the beta stage for XP, so if obviously it might run into some areas with some other scripts that Redefines Scene_Title, Scene_Map and Game_Event. Screenshot Not yet! FAQ Not yet! Terms and Conditions
QUOTE (cmpsr2000 @ Jun 12 2008, 03:16 AM)
Feel free to use this in your game, but please give me a shout in the credits! Also, feel free to edit this for your own personal purposes but please do not repost an edited version without my consent first.
Thanks ^^/
Special Thanks Cmrp2000 - for creating this script Night_Runner - for converting it to XP
This post has been edited by Bigace: Mar 10 2011, 02:27 PM
__________________________
Use Dropbox to upload your files. Much simpler than other upload sites, you can simply place a folder on your desktop that will sync with your DropBox account.
QUOTE ('Exiled One')
"If you are one of the very few teenagers that know what real rap is and don't blindly listen to the hate statements (rap is crap), then put this in your sig. I say this in the name of Common, Mos Def, Lupe Fiasco, 2Pac, Nas, Talib Kweli, Eminem, and many others."