#=============================================================================== # Stealth System # By Jet10985 (Jet) # Inspired By: Touchfuzzy #=============================================================================== # This script will implement a realistic stealth detection system for use # with events. All measurements are interpreted as metres. # This script has: 20 customization options. #=============================================================================== # Overwritten Methods: # None #------------------------------------------------------------------------------- # Aliased methods: # Game_System: initialize # Game_Player: update #=============================================================================== =begin To set an event's height, use this Comment in their event page: HEIGHT = number -------------------------------------------------------------------------------- To set the player's default camo rating, use this in an event "Script...": change_player_camo(number) -------------------------------------------------------------------------------- To give an equipment a bonus to camo rating, use this in the armor's notebox: -------------------------------------------------------------------------------- To change the player's height, use this in an event "Script...": change_player_height(number) -------------------------------------------------------------------------------- To manually set a region or terrain tag's camo or height for a map, use these in an event's "Script..." command: set_region_height(region_id, number) set_terrain_height(terrain_id, number) set_region_camo(region_id, number) set_terrain_camo(terrain_id, number) -------------------------------------------------------------------------------- You can check for sighting of any event or the player using this in an event's Conditional Branch "Script...": can_see?(char_id) char_id by default is -1, which means the Player 0 is the calling event anything above 0 is the id of an event on the map =end module Jet module Stealth # This is the button used for the player to enter a "ducking" position. DUCK_BUTTON = :ALT # This is the suffix of the sprite that the player's will be changed to when # ducking. If the player's sprite name is "Jimmy" and the suffix is "_duck" # then the game will look for "Jimmy_duck" DUCK_SUFFIX = "_duck" # This is how many metres a single tile represents. TILE_METRE_DIST = 75 # this is how tall events are by default. DEFAULT_EVENT_HEIGHT = 1.7 # This is how tall the player is by default. PLAYER_HEIGHT = 1.7 # this is how much "camo" rating is gained from ducking. DUCKING_CAMO_GAINED = 20 # This is how much "camo" rating is lost when moving while dashing. DASHING_CAMO_LOST = 15 # This is how much "camo" is lost when just moving without dashing. MOVEMENT_CAMO_LOST = 10 # This is how much movement speed is lost when ducking. DUCKING_SPEED_LOST = 2 # This is how many metres away a character has to be to have the # detector begin to lose some vision per metre. POINT_OF_VISION_LOSS = TILE_METRE_DIST * 5 # This is how much "camo" is gained per metre once distance has passed the # POINT_OF_VISION_LOSS mark. VISION_LOSS_PER_METRE = 0.00271 # How tall are unpassable tiles by default? This only applies if there are # no events on the tile. UNPASSABLE_HEIGHT = (1.0 / 0.0) # These are the default heights of Region IDs for every map. # A map's specific region height can be changed by using a script command # found in the instructions above. # This follows the format: region_id => height REGION_HEIGHTS = { #1 => 0, #2 => 2, #3 => 0.2 } # This is the default height of any undefined region above. REGION_HEIGHTS.default = 0 # These are the default heights of Terrains for every map. # A map's specific terrain height can be changed by using a script command # found in the instructions above. # This follows the format: terrain_id => height TERRAIN_HEIGHTS = { #1 => 0, #2 => 2, #3 => 0.2 } # This is the default height of any undefined terrain above. TERRAIN_HEIGHTS.default = 0 # These are the default camo of Region IDs for every map. # A map's specific region camo can be changed by using a script command # found in the instructions above. # This follows the format: region_id => camo REGION_CAMOS = {} # This is the default camo of any undefined region above. REGION_CAMOS.default = 0 # These are the default camo of Terrains for every map. # A map's specific terrain camo can be changed by using a script command # found in the instructions above. # This follows the format: terrain_id => camo TERRAIN_CAMOS = {} # This is the default camo of any undefined terrain above. TERRAIN_CAMOS.default = 0 end end #=============================================================================== # DON'T EDIT FURTHER UNLESS YOU KNOW WHAT TO DO. #=============================================================================== module Math module_function def dist_form(x, y, x2, y2) sqrt((x2 - x).abs ** 2 + (y2 - y).abs ** 2) end def horizon(metres) 3.856 * sqrt(metres) * 1000 end def rad_to_deg(rads) rads * 180 / PI end end class RPG::Armor def camo @camoflague ||= ( f = self.note.match(//i) f.nil? ? 0 : f[2].to_f ) end end class Game_Actor def character_name @character_name + ($game_player.ducking? ? Jet::Stealth::DUCK_SUFFIX : "") end end class Game_Event def check_for_comment(regexp) return false if empty? @list.select {|a| [108, 408].include?(a.code) }.collect {|a| a.parameters[0] }.each {|a| if !a[regexp].nil? return a.match(regexp) end } return false end def height f = check_for_comment(/HEIGHT[ ]*(\:|=)[ ]*(\d+)/i) f == false ? Jet::Stealth::DEFAULT_EVENT_HEIGHT : f[2].to_f end def movable? return false if moving? return false if @move_route_forcing return false if $game_message.busy? || $game_message.visible return true end end class Game_Player def height if ducking? if moving? f = (2.0 / 3.0) else f = (1.0 / 3.0) end else f = 1.0 end $game_system.player_height * f end def ducking? Input.press?(Jet::Stealth::DUCK_BUTTON) end def camoflague camo = 0 camo += $game_system.player_camo camo += $game_map.xy_camo(self.x, self.y) begin camo += $game_party.members[0].armors.inject {|a, b| a.camo + b.camo } rescue end if moving? if dash? camo -= Jet::Stealth::DASHING_CAMO_LOST else camo -= Jet::Stealth::MOVEMENT_CAMO_LOST end end camo += Jet::Stealth::DUCKING_CAMO_GAINED if ducking? [camo, 0].max end def real_move_speed super - (ducking? ? Jet::Stealth::DUCKING_SPEED_LOST : 0) end alias jet3745_update update def update(*args, &block) jet3745_update(*args, &block) @in_duck ||= false if ducking? && !@in_duck refresh @in_duck = true elsif !ducking? && @in_duck refresh @in_duck = false end end end class Game_Character attr_writer :sighted def camoflague camo = 0 camo += $game_map.xy_camo(self.x, self.y) camo -= Jet::Stealth::MOVEMENT_CAMO_LOST if moving? [camo, 0].max end def sight_range map_height = $game_map.xy_height(self.x, self.y) Math.horizon(self.height + map_height) end def true_height self.height + $game_map.xy_height(self.x, self.y) end def horizontal_angle_from(char) x_dist = self.x - char.x y_dist = self.y - char.y hypo = Math.hypot(x_dist, y_dist) (Math.rad_to_deg(Math.atan2(y_dist, x_dist)) - 180).abs end def viewing_angle_horizontal case self.direction when 2 [210, 330] when 4 [120, 240] when 6 10 when 8 [30, 150] end end def vertical_angle_from(char) height = (self.true_height - $game_map.xy_height(char.x, char.y)).abs distance = Math.dist_form(self.x, self.y, char.x, char.y) distance *= Jet::Stealth::TILE_METRE_DIST hypo = Math.hypot(height, distance) Math.rad_to_deg(Math.asin(height / hypo.to_f)) end def tiles_seen(x, y, x1, y1, char = nil) tiles = {} sx = x - x1 sy = y - y1 if sx.abs > sy.abs direction = sx > 0 ? 4 : 6 elsif sy != 0 direction = sy > 0 ? 8 : 2 end x_distance = x1 - x y_distance = y1 - y total_distance = Math.dist_form(x, y, x1, y1) x_per_tile = x_distance / total_distance y_per_tile = y_distance / total_distance x_dist_t = 0.0 y_dist_t = 0.0 if !char.nil? vert_angle = vertical_angle_from(char) end self_height = self.true_height until x_dist_t.abs >= x_distance.abs && y_dist_t.abs >= y_distance.abs x_dist_t += x_per_tile y_dist_t += y_per_tile x_tile = (x + x_dist_t).to_i y_tile = (y + y_dist_t).to_i height = $game_map.total_height(x_tile, y_tile, direction) tiles[[x_tile, y_tile]] = [height] if !char.nil? dist = (x_dist_t.abs + y_dist_t.abs) - total_distance dist = dist.abs viewing_height = self.height * dist - height tiles[[x_tile, y_tile]].push(viewing_height) end end tiles end def sighted?(char) distance = Math.dist_form(self.x, self.y, char.x, char.y) distance *= Jet::Stealth::TILE_METRE_DIST return false if distance > sight_range h_angle = horizontal_angle_from(char) case viewing_angle_horizontal when Array h_viewing_angle = viewing_angle_horizontal return false if !h_angle.between?(*h_viewing_angle) when 10 return false unless h_angle.between?(0, 60) || h_angle.between?(320, 360) end v_angle = vertical_angle_from(char) if self.true_height >= $game_map.xy_height(char.x, char.y) return false unless v_angle <= 75 v_viewing_angle = 75 else return false unless v_angle <= 60 v_viewing_angle = 60 end camo = char.camoflague distance += (self.true_height - $game_map.xy_height(char.x, char.y)).abs if distance.between?(Jet::Stealth::POINT_OF_VISION_LOSS, sight_range) add = (distance - Jet::Stealth::POINT_OF_VISION_LOSS) add *= Jet::Stealth::VISION_LOSS_PER_METRE camo += add elsif distance > sight_range return false elsif distance < Jet::Stealth::POINT_OF_VISION_LOSS camo /= 4 end camo = [camo, 0].max return false if rand(100) + 1 <= camo tiles = tiles_seen(self.x, self.y, char.x, char.y, char) tiles.each {|coords, heights| next if coords == [self.x, self.y] if heights[1] <= 0 return false end } return true end end class Game_System attr_accessor :player_height, :player_camo alias jet3745_initialize initialize def initialize(*args, &block) jet3745_initialize(*args, &block) @player_height = Jet::Stealth::PLAYER_HEIGHT @player_camo = 0 end end class Game_Map def xy_height(x, y, dir = 0) reg = region_id(x, y) reg_h = region_heights(reg) ter = terrain_tag(x, y) ter_h = terrain_heights(ter) pas_h = $game_map.passable?(x, y, dir) ? 0 : Jet::Stealth::UNPASSABLE_HEIGHT reg_h + ter_h + pas_h end def xy_camo(x, y) reg = region_id(x, y) reg_c = region_camos(reg) ter = terrain_tag(x, y) ter_c = terrain_camos(ter) reg_c + ter_c end def total_height(x, y, dir = 0) xy = xy_height(x, y, dir) evs = $game_map.events_xy(x, y) ev_height = evs.sort {|a, b| a.height <=> b.height } ev_height = (ev_height[-1].true_height rescue 0) xy + (ev_height || 0) end def region_heights(reg) (@map_region_heights ||= {})[@map_id] ||= Jet::Stealth::REGION_HEIGHTS @map_region_heights[@map_id][reg] end def set_region_height(reg, height) (@map_region_heights ||= {})[@map_id] ||= Jet::Stealth::REGION_HEIGHTS @map_region_heights[@map_id][reg] = height end def terrain_heights(ter) (@map_terrain_heights ||= {})[@map_id] ||= Jet::Stealth::TERRAIN_HEIGHTS @map_terrain_heights[@map_id][ter] end def set_region_height(ter, height) (@map_terrain_heights ||= {})[@map_id] ||= Jet::Stealth::TERRAIN_HEIGHTS @map_terrain_heights[@map_id][ter] = height end def region_camos(reg) (@map_region_camos ||= {})[@map_id] ||= Jet::Stealth::REGION_CAMOS @map_region_camos[@map_id][reg] end def set_region_camo(reg, camo) (@map_region_camos ||= {})[@map_id] ||= Jet::Stealth::REGION_CAMOS @map_region_camos[@map_id][reg] = camo end def terrain_camos(ter) (@map_terrain_camos ||= {})[@map_id] ||= Jet::Stealth::TERRAIN_CAMOS @map_terrain_camos[@map_id][ter] end def set_region_camo(ter, camo) (@map_terrain_camos ||= {})[@map_id] ||= Jet::Stealth::TERRAIN_CAMOS @map_terrain_camos[@map_id][ter] = camo end end class Game_Interpreter def set_region_height(reg, height) $game_map.set_right_height(reg, height) end def set_terrain_height(ter, height) $game_map.set_terrain_height(ter, height) end def set_region_camo(reg, camo) $game_map.set_right_height(reg, camo) end def set_terrain_camo(ter, camo) $game_map.set_terrain_height(ter, camo) end def change_player_height(height) $game_system.player_height = height end def change_player_camo(camo) $game_system.player_camo = camo end def can_see?(ev = -1) return true if ev == 0 get_character(0).sighted?(get_character(ev)) end end