Submit Your Article


 
RPG Maker

Welcome Guest ( Log In | Register )


  Games Resources RPG Maker VX RPG Maker XP Scripts Tutorials Downloads

> Stealth Detection System, Translated from VX (something people been waiting for since Janurary)
Bigace
post Jul 13 2010, 05:11 PM
Post #1


The King of Spades
Group Icon

Group: Revolutionary
Posts: 400
Type: Developer
RM Skill: Intermediate




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
    
    #figure out the route: A* algorithm
    @activeList = []
    @activeParents = []
    @activeScores = []
    @closedList = []
    @closedParents = []
    @closedScores = []
    @activeList.push([startX, startY])
    @activeParents.push([startX, startY])
    @activeScores.push([0,0,0])
    noPath = false
    finalNode = [finalX, finalY]
    
    #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]
                
                #delete existing
                @activeList.delete(tempNode)
                @activeParents.delete(tempParent)
                @activeScores.delete(tempScores)
                
                #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
  
  #for all stealth
  attr_accessor :isAware
  attr_accessor :detectRange
  attr_accessor :tunnelVision
  attr_accessor :trueSight
  attr_accessor :detectAction
  attr_accessor :originalAction
  
  #For MGS-style stealth
  attr_accessor :move_speed
  attr_accessor :move_frequency
  attr_accessor :detectState
  attr_accessor :move_route_index
  attr_accessor :move_route
  attr_accessor :returnX
  attr_accessor :returnY
  attr_accessor :returnRoute
  attr_accessor :returnRouteIndex
  attr_accessor :returnSpeed
  attr_accessor :returnFrequency
  attr_reader   :move_failed
  
  alias oldInitStealth initialize
  def initialize(map_id, event)
    oldInitStealth(map_id, event)
    @isAware = false
  end
end

Game_Stealth
CODE
#-------------------------------------------------------------------------------

#

#                           Stealth Detection System v 1.0

#                    code by cmpsr2000 @ rpgrevolution.com/forums

#                               Released June 11, 2008

#

#-------------------------------------------------------------------------------

#-------------------------------------------------------------------------------

#

# SDS is an advanced stealth detection system for use in RPG Maker VX games.

# To use the system, you need to build an event that begins with a script call:

#

#   $game_stealth.detector(eventID, detectRange, detectAction,

#                          tunnelVision, trueSight)

#

#   eventID:        The ID of the event. Use @event_id as it's the easiest way

#   detectRange:    How far the "guard" is able to see. Higher numbers require

#                   more CPU time to proccess! Lag increases exponentially if

#                   you are NOT using tunnel vision.

#   detectAction:   The action to perform when the guard detects the player

#                   DEFAULT = 1

#                   0: Goto jail event

#                   1: Game Over

#                   2: Execute common event

#                   3: MGS Mode

#   tunnelVision:   determines whether the guard's field of view cones out or

#                   goes in a straight line.

#                   DEFAULT = false

#   trueSight:      determines whether the guard can see through obstacles

#                   DEFAULT = false

#

#   NOTE: You do NOT have to set parameters that have a default.

#

#                         MGS MODE EXPLAINATION:

#

#       When using detectAction 3 (MGS Mode) guards will be "alerted" if

#       they spot the player. The guard will run to the position they spotted

#       the player at, then begin to look around for the player again. If the

#       guard sees the player a second time, the captureAction is performed.

#

#-------------------------------------------------------------------------------

class Game_Stealth

  

  attr_accessor :common_event_id

  

  def initialize

    @checkedTiles   = []

    @fovPassability = {}

    @detectingEvent = nil

    @tempInterpreter = nil

    @alertedGuards = []

    

    #---------------------------------------------------------------------------

    # If you use tunnel vision, set the tunnel width here. It MUST be an ODD

    # number or the game will round up to the next odd number! Widths over 3

    # are not recomended.

    #---------------------------------------------------------------------------

    @tunnelWidth = 3

    

    #---------------------------------------------------------------------------

    # The common event ID to execute when using the common event detect action

    #---------------------------------------------------------------------------

    @common_event_id = 1

    

    #---------------------------------------------------------------------------

    # The speed and frequency the guards move when they detect the player in

    # MGS mode.

    #   speed:      1: x8 slower,

    #               2: x4 slower

    #               3: x2 slower

    #               4: normal

    #               5: x2 faster

    #               6: x4 faster

    #

    #   frequency:  1: lowest

    #               2: lower

    #               3: normal

    #               4: higher

    #               5: highest

    #---------------------------------------------------------------------------

    @guardInterceptSpeed = 4

    @guardInterceptFrequency = 6

    

    #---------------------------------------------------------------------------

    # When in MGS mode, the action to be performed if the guard detects the

    # player a second time. This is set by default to game_over since all other

    # options require some configuration. Valid values are:

    #   captureAction:  0: Goto jail event

    #                   1: Game Over

    #                   2: Execute common event

    #---------------------------------------------------------------------------

    @captureAction = 1

    

    #---------------------------------------------------------------------------

    # How many frames a guard will wait before executing each turn when

    # searching for the player after detecting them in MGS mode.

    #---------------------------------------------------------------------------

    @waitTime = Graphics.frame_rate / 2 # 40

    

    #---------------------------------------------------------------------------

    # Change this to false to disable the detection radius around guards.

    # This means the player can safely stand next to a guard as long as he's

    # not in the guard's line of sight.

    #---------------------------------------------------------------------------

    @allowDetectRadius= true</FONT></P> <P><FONT size=6><FONT size=2>    @tunnelWidth += 1 if (@tunnelWidth % 2) == 1

  end

  

  #-----------------------------------------------------------------------------

  # Standard update method; checks for player detection then handles MGS

  # state changes for guards then checks for player detection again

  #-----------------------------------------------------------------------------

  def update

    if $game_player.detected and not $game_player.moving?

      doDetectAction

    end

    for guard in @alertedGuards

      case guard.detectState

      when nil, 0 #alerted

        guard.lock

        guard.returnX           = guard.x

        guard.returnY           = guard.y

        guard.returnRoute       = guard.move_route

        guard.returnRouteIndex  = guard.move_route_index

        guard.returnSpeed       = guard.move_speed

        guard.returnFrequency   = guard.move_frequency

        guard.move_speed        = @guardInterceptSpeed

        guard.move_frequency    = @guardInterceptFrequency

        guard.isAware = false

        guard.detectState = guard.goto($game_player.x, $game_player.y) ? 1 : 3

        guard.unlock

      when 1 #intercepting

        if (guard.move_route_index == guard.move_route.list.length - 1 and

           guard.stopping?) or guard.move_failed

          guard.lock

          guard.isAware = true

          guard.spinInPlace(@waitTime)

          guard.detectState = 2

          guard.unlock

        end

      when 2 #checking

        if guard.move_route_index == guard.move_route.list.length - 1 and

           guard.stopping?

          guard.lock

          guard.isAware = false

          go = guard.goto(guard.returnX, guard.returnY)

          guard.detectState = 3

          guard.unlock

        end

      when 3 #returning

        if guard.move_route_index == guard.move_route.list.length - 1 and not

           guard.moving?

          guard.lock

          guard.isAware = true

          guard.move_route        = guard.returnRoute

          guard.move_route_index  = guard.returnRouteIndex

          guard.move_speed        = guard.returnSpeed

          guard.move_frequency    = guard.returnFrequency

          guard.detectState       = 0

          @captured = false

          @alertedGuards.delete(guard)

          guard.unlock

        end

      end

    end

    observe

  end

  #-----------------------------------------------------------------------------

  # Runs through the aware events(guards) on the map and tells them to check

  # for the player.

  #-----------------------------------------------------------------------------

  def observe

    for event in $game_map.events.values #events is a hash!

      if event.isAware

        if event.moved? or event.turned? or $game_player.moved?

          if checkForDetection(event)

            $game_player.detected = true

            @detectingEvent = event

            return

          end

        end

      end

      @checkedTiles   = []

      @fovPassability = {}

    end

  end

  #-----------------------------------------------------------------------------

  # Runs through each tile in the event(guard)'s field of view and checks

  # it for the player. RETURNS: Boolean

  #   event:    The guard that is currently checking for the player.

  #-----------------------------------------------------------------------------

  def checkForDetection(event)

    return true if playerInDetectionRadius(event)

    return false if playerOutOfRange(event)

    fieldOfView = event.tunnelVision ? @tunnelWidth : 1

    for distance in 1..event.detectRange

      for width in 1..fieldOfView

        return true if checkTile(event, width, distance)

      end

      fieldOfView += 2 unless event.tunnelVision

    end

    return false

  end

  #-----------------------------------------------------------------------------

  # Checks a tile for the player. RETURNS: Boolean

  #   event:    The guard that is currently checking for the player.

  #   width:    The width-index of the tile being checked

  #   distance: The depth-index of the tile being checked

  #-----------------------------------------------------------------------------

  def checkTile(event, width, distance)

    if event.tunnelVision

      if @tunnelWidth > 1

        width = width - ((@tunnelWidth - 1)/2)

      else

        width = 0

      end

    else

      width -= distance

    end

    x = event.x

    y = event.y

    direction = event.direction

    case direction

    when 2

      y += distance

      x += width

    when 4

      y += width

      x -= distance

    when 6

      y += width

      x += distance

    when 8

      y -= distance

      x += width

    end

    return false if @checkedTiles.index([x,y]) != nil

    return false if tileHidden?(event, x, y)

    return true if $game_player.x == x and $game_player.y == y

    return false

  end

  #-----------------------------------------------------------------------------

  # Determines the visibility of a tile to a guard. RETURNS: Boolean

  #   event:    The guard that is currently checking for the player.

  #   x:        The x coordinate of the tile to be checked

  #   y:        The y coordinate of the tile to be checked

  #-----------------------------------------------------------------------------

  def tileHidden?(event, x, y)

    return false if event.trueSight

    #check the current tile first

    @checkedTiles.push([x,y])

    originalX = x

    originalY = y

    if not $game_map.passable?(x, y, 0)

      @fovPassability[[x,y]] = false

      return true

    end

    

    #now check all adjacent tiles one step closer to the detector

    direction = event.direction

    case direction

    when 2 #down

      y -= 1

      for i in (x-1)..(x+1)

        #if we've checked the tile, then it exists in the FoV

        if @checkedTiles.index([i,y]) != nil

          if not @fovPassability[[i,y]]

            @fovPassability[[originalX,originalY]] = false

            return true

          end

        end

      end

    when 4 #left

      x += 1

      for i in (y-1)..(y+1)

        #if we've checked the tile, then it exists in the FoV

        if @checkedTiles.index([x,i]) != nil

          if not @fovPassability[[x,i]]

            @fovPassability[[originalX,originalY]] = false

            return true

          end

        end

      end

    when 6 #right

      x -= 1

      for i in (y-1)..(y+1)

        #if we've checked the tile, then it exists in the FoV

        if @checkedTiles.index([x,i]) != nil

          if not @fovPassability[[x,i]]

            @fovPassability[[originalX,originalY]] = false

            return true

          end

        end

      end

    when 8 #up

      y += 1

      for i in (x-1)..(x+1)

        #if we've checked the tile, then it exists in the FoV

        if @checkedTiles.index([i,y]) != nil

          if not @fovPassability[[i,y]]

            @fovPassability[[originalX,originalY]] = false

            return true

          end

        end

      end

    end

    

    #this tile and the blocking tiles must be passable

    @fovPassability[[originalX,originalY]] = true

    return false

  end

  #-----------------------------------------------------------------------------

  # Guards and other "detector" events have an awareness of their immediate

  # surroundings. If the player is adjacent to the event, they will be

  # discovered if @allowDetectRadius is true. RETURNS: Boolean

  #   event:    The guard that is currently checking for the player.

  #-----------------------------------------------------------------------------

  def playerInDetectionRadius(event)

    return false unless @allowDetectRadius

    adjacentTiles = [ [event.x, event.y - 1],

                      [event.x + 1, event.y - 1],

                      [event.x + 1, event.y],

                      [event.x + 1, event.y + 1],

                      [event.x, event.y + 1],

                      [event.x - 1, event.y + 1],

                      [event.x - 1, event.y],

                      [event.x - 1, event.y - 1] ]

    for tile in adjacentTiles

      if $game_player.x == tile[0] and $game_player.y == tile[1]

        return true

      end

    end

    return false

  end

  

  def playerOutOfRange(event)

    direction = event.direction

    case direction

    when 2 #down

      yDifference = event.y - $game_player.y

      xDifference = event.x - $game_player.x

      coneWidth = event.tunnelVision ? (@tunnelWidth / 2).floor : event.detectRange - 1

      if yDifference > event.detectRange or $game_player.y < event.y - 1 or

         (xDifference.abs > coneWidth)

        return true

      end

    when 4 #left

      yDifference = event.y - $game_player.y

      xDifference = event.x - $game_player.x

      coneWidth = event.tunnelVision ? (@tunnelWidth / 2).floor : event.detectRange - 1

      if xDifference > event.detectRange or $game_player.x > event.x + 1 or

         (yDifference.abs > coneWidth)

        return true

      end

    when 6 #right

      yDifference = $game_player.y - event.y

      xDifference = $game_player.x - event.x

      coneWidth = event.tunnelVision ? (@tunnelWidth / 2).floor : event.detectRange - 1

      if xDifference > event.detectRange or $game_player.x < event.x - 1 or

         (yDifference.abs > coneWidth)

        return true

      end

    when 8 #up

      yDifference = event.y - $game_player.y

      xDifference = event.x - $game_player.x

      coneWidth = event.tunnelVision ? (@tunnelWidth / 2).floor : event.detectRange - 1

      if yDifference > event.detectRange or $game_player.y > event.y + 1 or

         (xDifference.abs > coneWidth)

        return true

      end

    end

    return false

  end

  #-----------------------------------------------------------------------------

  # Called in an event to enable detection for the event (guard).

  #   eventID:      The id of the event. use @event_id in your event call!

  #   detectRange:  How far away the guard can see

  #   detectAction: What happens when caught. defaults to game_over

  #   tunnelVision: Whether the guard has field of view or tunnel vision

  #   trueSight:    Whether the guard can see through objects

  #-----------------------------------------------------------------------------

  def detector(eventID, detectRange, detectAction = 1,

               tunnelVision = false, trueSight = false)

    event               = $game_map.events[eventID]

    event.isAware       = true

    event.detectAction  = detectAction

    event.detectRange   = detectRange

    event.tunnelVision  = tunnelVision

    event.trueSight     = trueSight

    event.setPosition

  end

  #-----------------------------------------------------------------------------

  # Called in an event to set the location tile of the "jail"

  #   eventID:   The ID of the event that is at the jail location.

  #              Again, use @event_id

  #-----------------------------------------------------------------------------

  def jail(eventID)

    event = $game_map.events[eventID]

    @jailX      = event.x

    @jailY      = event.y

  end

  #-----------------------------------------------------------------------------

  # Executes the desired action upon detecting the player

  #-----------------------------------------------------------------------------

  def doDetectAction

    case @detectingEvent.detectAction

    when 0 # goto jail

      sendToJail

    when 1 # game over

      $scene = Scene_Gameover.new

    when 2 # execute common event

      doCommonEvent

    when 3 # MGS - enemy moves towards player position

      if @detectingEvent.detectState == 2

        if not @captured

          case @captureAction

          when 0

            sendToJail

          when 1, 3

            gameOver

          when 2

            doCommonEvent

          end

          @captured = true

        end

      else

        Sound.play_found

        @detectingEvent.animation_id = 98

        unless @alertedGuards.include?(@detectingEvent)

          @alertedGuards.push(@detectingEvent)

        end

      end

    end

    $game_player.detected = false

    @detectingEvent = nil

  end

  #-----------------------------------------------------------------------------

  # MODE 0: Send player to the "jail" tile

  #-----------------------------------------------------------------------------

  def sendToJail

      $game_player.transfer($game_map.map_id, @jailX, @jailY,

                                    @detectingEvent.direction)

  end

  #-----------------------------------------------------------------------------

  # MODE 1: Game Over

  #-----------------------------------------------------------------------------

  def gameOver

    $scene = Scene_Gameover.new

  end

  #-----------------------------------------------------------------------------

  # MODE 2: Execute Common Event

  #-----------------------------------------------------------------------------

  def doCommonEvent

      $game_temp.common_event_id = @common_event_id

  end

end

Demo: SDS DEMO for XP
You'll also need this sound if you didn't download the demo: Attached File  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."
Go to the top of the page
 
+Quote Post
   



Closed TopicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:

 

Lo-Fi Version Time is now: 22nd May 2013 - 04:40 PM
RPG RPG Revolution is an Privacy Policy and Legal
eXTReMe Tracker