#=============================================================================== # ** Game_Player #------------------------------------------------------------------------------- # This class handles the player. Its functions include event starting # determinants and map scrolling. Refer to "$game_player" for the one # instance of this class. #=============================================================================== class Game_Player < Game_Character attr_accessor :charsetData attr_accessor :encounter_count SCREEN_CENTER_X = ((Settings::SCREEN_WIDTH / 2) - (Game_Map::TILE_WIDTH / 2)) * Game_Map::X_SUBPIXELS SCREEN_CENTER_Y = ((Settings::SCREEN_HEIGHT / 2) - (Game_Map::TILE_HEIGHT / 2)) * Game_Map::Y_SUBPIXELS # Time in seconds for one cycle of bobbing (playing 4 charset frames) while # surfing or diving. SURF_BOB_DURATION = 1.5 def initialize(*arg) super(*arg) @lastdir = 0 @lastdirframe = 0 end def map @map = nil return $game_map end def map_id return $game_map.map_id end def screen_z(height = 0) ret = super return ret + 1 end def has_follower? return $PokemonGlobal.followers.length > 0 end def can_map_transfer_with_follower? return $PokemonGlobal.followers.length == 0 end def can_ride_vehicle_with_follower? return $PokemonGlobal.followers.length == 0 end #----------------------------------------------------------------------------- def can_run? return @move_speed > 3 if @move_route_forcing return false if @bumping return false if $game_temp.in_menu || $game_temp.in_battle || $game_temp.message_window_showing || pbMapInterpreterRunning? return false if !$player.has_running_shoes && !$PokemonGlobal.diving && !$PokemonGlobal.surfing && !$PokemonGlobal.bicycle return false if jumping? return false if pbTerrainTag.must_walk return ($PokemonSystem.runstyle == 1) ^ Input.press?(Input::BACK) end def set_movement_type(type) meta = GameData::PlayerMetadata.get($player&.character_ID || 1) new_charset = nil case type when :fishing new_charset = pbGetPlayerCharset(meta.fish_charset) when :surf_fishing new_charset = pbGetPlayerCharset(meta.surf_fish_charset) when :diving, :diving_fast, :diving_jumping, :diving_stopped self.move_speed = 3 if !@move_route_forcing new_charset = pbGetPlayerCharset(meta.dive_charset) when :surfing, :surfing_fast, :surfing_jumping, :surfing_stopped if !@move_route_forcing self.move_speed = (type == :surfing_jumping) ? 3 : 4 end new_charset = pbGetPlayerCharset(meta.surf_charset) when :descending_waterfall, :ascending_waterfall self.move_speed = 2 if !@move_route_forcing new_charset = pbGetPlayerCharset(meta.surf_charset) when :cycling, :cycling_fast, :cycling_jumping, :cycling_stopped if !@move_route_forcing self.move_speed = (type == :cycling_jumping) ? 3 : 5 end new_charset = pbGetPlayerCharset(meta.cycle_charset) when :running self.move_speed = 4 if !@move_route_forcing new_charset = pbGetPlayerCharset(meta.run_charset) when :ice_sliding self.move_speed = 4 if !@move_route_forcing new_charset = pbGetPlayerCharset(meta.walk_charset) else # :walking, :jumping, :walking_stopped self.move_speed = 3 if !@move_route_forcing new_charset = pbGetPlayerCharset(meta.walk_charset) end self.move_speed = 3 if @bumping @character_name = new_charset if new_charset end # Called when the player's character or outfit changes. Assumes the player # isn't moving. def refresh_charset meta = GameData::PlayerMetadata.get($player&.character_ID || 1) new_charset = nil if $PokemonGlobal&.diving new_charset = pbGetPlayerCharset(meta.dive_charset) elsif $PokemonGlobal&.surfing new_charset = pbGetPlayerCharset(meta.surf_charset) elsif $PokemonGlobal&.bicycle new_charset = pbGetPlayerCharset(meta.cycle_charset) else new_charset = pbGetPlayerCharset(meta.walk_charset) end @character_name = new_charset if new_charset end #----------------------------------------------------------------------------- def bump_into_object pbSEPlay("Player bump") if !@move_route_forcing $stats.bump_count += 1 @move_initial_x = @x @move_initial_y = @y @move_timer = 0.0 @bumping = true end def add_move_distance_to_stats(distance = 1) if $PokemonGlobal&.diving || $PokemonGlobal&.surfing $stats.distance_surfed += distance elsif $PokemonGlobal&.bicycle $stats.distance_cycled += distance else $stats.distance_walked += distance end $stats.distance_slid_on_ice += distance if $PokemonGlobal.ice_sliding end def move_generic(dir, turn_enabled = true) turn_generic(dir, true) if turn_enabled if !$game_temp.encounter_triggered if can_move_in_direction?(dir) x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0 y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0 # Jump over ledges if pbFacingTerrainTag.ledge if jumpForward(2) pbSEPlay("Player jump") increase_steps end return elsif pbFacingTerrainTag.waterfall_crest && dir == 2 $PokemonGlobal.descending_waterfall = true $game_player.through = true $stats.waterfalls_descended += 1 end # Jumping out of surfing back onto land return if pbEndSurf(x_offset, y_offset) # General movement turn_generic(dir, true) if !$game_temp.encounter_triggered @move_initial_x = @x @move_initial_y = @y @x += x_offset @y += y_offset @move_timer = 0.0 add_move_distance_to_stats(x_offset.abs + y_offset.abs) increase_steps end elsif !check_event_trigger_touch(dir) bump_into_object end end $game_temp.encounter_triggered = false end def turn_generic(dir, keep_enc_indicator = false) old_direction = @direction super(dir) if @direction != old_direction && !@move_route_forcing && !pbMapInterpreterRunning? EventHandlers.trigger(:on_player_change_direction) $game_temp.encounter_triggered = false if !keep_enc_indicator end end def jump(x_plus, y_plus) old_x = @x old_y = @y super add_move_distance_to_stats(x_plus.abs + y_plus.abs) if @x != old_x || @y != old_y end #----------------------------------------------------------------------------- def pbTerrainTag(countBridge = false) return $map_factory.getTerrainTagFromCoords(self.map.map_id, @x, @y, countBridge) if $map_factory return $game_map.terrain_tag(@x, @y, countBridge) end def pbFacingEvent(ignoreInterpreter = false) return nil if $game_system.map_interpreter.running? && !ignoreInterpreter # Check the tile in front of the player for events new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0) new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0) return nil if !$game_map.valid?(new_x, new_y) $game_map.events.each_value do |event| next if !event.at_coordinate?(new_x, new_y) next if event.jumping? || event.over_trigger? return event end # If the tile in front is a counter, check one tile beyond that for events if $game_map.counter?(new_x, new_y) new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0) new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0) $game_map.events.each_value do |event| next if !event.at_coordinate?(new_x, new_y) next if event.jumping? || event.over_trigger? return event end end return nil end def pbFacingTerrainTag(dir = nil) dir = self.direction if !dir return $map_factory.getFacingTerrainTag(dir, self) if $map_factory facing = pbFacingTile(dir, self) return $game_map.terrain_tag(facing[1], facing[2]) end # Passable Determinants # x : x-coordinate # y : y-coordinate # d : direction (0, 2, 4, 6, 8) # * 0 = Determines if all directions are impassable (for jumping) def passable?(x, y, d, strict = false) # Get new coordinates new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0) new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0) # If coordinates are outside of map return false if !$game_map.validLax?(new_x, new_y) if !$game_map.valid?(new_x, new_y) return false if !$map_factory return $map_factory.isPassableFromEdge?(new_x, new_y) end # If debug mode is ON and Ctrl key was pressed return true if $DEBUG && Input.press?(Input::CTRL) return super end # Set Map Display Position to Center of Screen def center(x, y) self.map.display_x = (x * Game_Map::REAL_RES_X) - SCREEN_CENTER_X self.map.display_y = (y * Game_Map::REAL_RES_Y) - SCREEN_CENTER_Y end # Move to Designated Position # x : x-coordinate # y : y-coordinate def moveto(x, y) super center(x, y) make_encounter_count end # Make Encounter Count def make_encounter_count # Image of two dice rolling if $game_map.map_id != 0 n = $game_map.encounter_step @encounter_count = rand(n) + rand(n) + 1 end end def refresh @opacity = 255 @blend_type = 0 end #----------------------------------------------------------------------------- def pbTriggeredTrainerEvents(triggers, checkIfRunning = true, trainer_only = false) result = [] # If event is running return result if checkIfRunning && $game_system.map_interpreter.running? # All event loops $game_map.events.each_value do |event| next if !triggers.include?(event.trigger) next if !event.name[/trainer\((\d+)\)/i] && (trainer_only || !event.name[/sight\((\d+)\)/i]) distance = $~[1].to_i next if !pbEventCanReachPlayer?(event, self, distance) next if event.jumping? || event.over_trigger? result.push(event) end return result end def pbTriggeredCounterEvents(triggers, checkIfRunning = true) result = [] # If event is running return result if checkIfRunning && $game_system.map_interpreter.running? # All event loops $game_map.events.each_value do |event| next if !triggers.include?(event.trigger) next if !event.name[/counter\((\d+)\)/i] distance = $~[1].to_i next if !pbEventFacesPlayer?(event, self, distance) next if event.jumping? || event.over_trigger? result.push(event) end return result end def check_event_trigger_after_turning; end def pbCheckEventTriggerFromDistance(triggers) events = pbTriggeredTrainerEvents(triggers) events.concat(pbTriggeredCounterEvents(triggers)) return false if events.length == 0 ret = false events.each do |event| event.start ret = true if event.starting end return ret end # Trigger event(s) at the same coordinates as self with the appropriate # trigger(s) that can be triggered def check_event_trigger_here(triggers) result = false # If event is running return result if $game_system.map_interpreter.running? # All event loops $game_map.events.each_value do |event| # If event coordinates and triggers are consistent next if !event.at_coordinate?(@x, @y) next if !triggers.include?(event.trigger) # If starting determinant is same position event (other than jumping) next if event.jumping? || !event.over_trigger? event.start result = true if event.starting end return result end # Front Event Starting Determinant def check_event_trigger_there(triggers) result = false # If event is running return result if $game_system.map_interpreter.running? # Calculate front event coordinates new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0) new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0) return false if !$game_map.valid?(new_x, new_y) # All event loops $game_map.events.each_value do |event| next if !triggers.include?(event.trigger) # If event coordinates and triggers are consistent next if !event.at_coordinate?(new_x, new_y) # If starting determinant is front event (other than jumping) next if event.jumping? || event.over_trigger? event.start result = true if event.starting end # If fitting event is not found if result == false && $game_map.counter?(new_x, new_y) # Calculate coordinates of 1 tile further away new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0) new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0) return false if !$game_map.valid?(new_x, new_y) # All event loops $game_map.events.each_value do |event| next if !triggers.include?(event.trigger) # If event coordinates and triggers are consistent next if !event.at_coordinate?(new_x, new_y) # If starting determinant is front event (other than jumping) next if event.jumping? || event.over_trigger? event.start result = true if event.starting end end return result end # Touch Event Starting Determinant def check_event_trigger_touch(dir) result = false return result if $game_system.map_interpreter.running? # All event loops x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0 y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0 $game_map.events.each_value do |event| next if ![1, 2].include?(event.trigger) # Player touch, event touch # If event coordinates and triggers are consistent next if !event.at_coordinate?(@x + x_offset, @y + y_offset) if event.name[/(?:sight|trainer)\((\d+)\)/i] distance = $~[1].to_i next if !pbEventCanReachPlayer?(event, self, distance) elsif event.name[/counter\((\d+)\)/i] distance = $~[1].to_i next if !pbEventFacesPlayer?(event, self, distance) end # If starting determinant is front event (other than jumping) next if event.jumping? || event.over_trigger? event.start result = true if event.starting end return result end #----------------------------------------------------------------------------- def update last_real_x = @real_x last_real_y = @real_y @last_terrain_tag = pbTerrainTag super update_stop if $game_temp.in_menu && @stopped_last_frame update_screen_position(last_real_x, last_real_y) # Update dependent events if (!@moved_last_frame || @stopped_last_frame) && (moving? || jumping?) && !@bumping $game_temp.followers.move_followers end $game_temp.followers.update update_event_triggering end def update_command_new dir = Input.dir4 if $PokemonGlobal.forced_movement? move_forward elsif !pbMapInterpreterRunning? && !$game_temp.message_window_showing && !$game_temp.in_mini_update && !$game_temp.in_menu # Move player in the direction the directional button is being pressed if @moved_last_frame || (dir > 0 && dir == @lastdir && System.uptime - @lastdirframe >= 0.075) case dir when 2 then move_down when 4 then move_left when 6 then move_right when 8 then move_up end elsif dir != @lastdir case dir when 2 then turn_down when 4 then turn_left when 6 then turn_right when 8 then turn_up end end # Record last direction input @lastdirframe = System.uptime if dir != @lastdir @lastdir = dir end end def update_move if !@moved_last_frame || @stopped_last_frame # Started a new step if $PokemonGlobal.ice_sliding || @last_terrain_tag.ice set_movement_type(:ice_sliding) elsif $PokemonGlobal.descending_waterfall set_movement_type(:descending_waterfall) elsif $PokemonGlobal.ascending_waterfall set_movement_type(:ascending_waterfall) else faster = can_run? if $PokemonGlobal&.diving set_movement_type((faster) ? :diving_fast : :diving) elsif $PokemonGlobal&.surfing set_movement_type((faster) ? :surfing_fast : :surfing) elsif $PokemonGlobal&.bicycle set_movement_type((faster) ? :cycling_fast : :cycling) else set_movement_type((faster) ? :running : :walking) end end if jumping? if $PokemonGlobal&.diving set_movement_type(:diving_jumping) elsif $PokemonGlobal&.surfing set_movement_type(:surfing_jumping) elsif $PokemonGlobal&.bicycle set_movement_type(:cycling_jumping) else set_movement_type(:jumping) # Walking speed/charset while jumping end end end was_jumping = jumping? super if was_jumping && !jumping? && !@transparent && (@tile_id > 0 || @character_name != "") if !$PokemonGlobal.surfing || $game_temp.ending_surf spriteset = $scene.spriteset(map_id) spriteset&.addUserAnimation(Settings::DUST_ANIMATION_ID, self.x, self.y, true, 1) end end end def update_stop if @stopped_last_frame if $PokemonGlobal&.diving set_movement_type(:diving_stopped) elsif $PokemonGlobal&.surfing set_movement_type(:surfing_stopped) elsif $PokemonGlobal&.bicycle set_movement_type(:cycling_stopped) else set_movement_type(:walking_stopped) end end super end def update_pattern if $PokemonGlobal&.surfing || $PokemonGlobal&.diving bob_pattern = (4 * System.uptime / SURF_BOB_DURATION).to_i % 4 @pattern = bob_pattern if !@lock_pattern @pattern_surf = bob_pattern @bob_height = (bob_pattern >= 2) ? 2 : 0 @anime_count = 0 else @bob_height = 0 super end end # Track the player on-screen as they move. def update_screen_position(last_real_x, last_real_y) return if self.map.scrolling? || !(@moved_last_frame || @moved_this_frame) if (@real_x < last_real_x && @real_x < $game_map.display_x + SCREEN_CENTER_X) || (@real_x > last_real_x && @real_x > $game_map.display_x + SCREEN_CENTER_X) self.map.display_x += @real_x - last_real_x end if (@real_y < last_real_y && @real_y < $game_map.display_y + SCREEN_CENTER_Y) || (@real_y > last_real_y && @real_y > $game_map.display_y + SCREEN_CENTER_Y) self.map.display_y += @real_y - last_real_y end end def update_event_triggering return if moving? || jumping? || $PokemonGlobal.forced_movement? # Try triggering events upon walking into them/in front of them if @moved_this_frame $game_temp.followers.turn_followers result = pbCheckEventTriggerFromDistance([2]) # Event determinant is via touch of same position event result |= check_event_trigger_here([1, 2]) # No events triggered, try other event triggers upon finishing a step pbOnStepTaken(result) end end end #=============================================================================== # #=============================================================================== def pbGetPlayerCharset(charset, trainer = nil, force = false) trainer = $player if !trainer outfit = (trainer) ? trainer.outfit : 0 return nil if !force && $game_player&.charsetData && $game_player.charsetData[0] == trainer.character_ID && $game_player.charsetData[1] == charset && $game_player.charsetData[2] == outfit $game_player.charsetData = [trainer.character_ID, charset, outfit] if $game_player ret = charset if pbResolveBitmap("Graphics/Characters/" + ret + "_" + outfit.to_s) ret = ret + "_" + outfit.to_s end return ret end def pbUpdateVehicle if $PokemonGlobal&.diving $game_player.set_movement_type(:diving_stopped) elsif $PokemonGlobal&.surfing $game_player.set_movement_type(:surfing_stopped) elsif $PokemonGlobal&.bicycle $game_player.set_movement_type(:cycling_stopped) else $game_player.set_movement_type(:walking_stopped) end end def pbCancelVehicles(destination = nil, cancel_swimming = true) $PokemonGlobal.surfing = false if cancel_swimming $PokemonGlobal.diving = false if cancel_swimming $PokemonGlobal.bicycle = false if !destination || !pbCanUseBike?(destination) pbUpdateVehicle end def pbCanUseBike?(map_id) map_metadata = GameData::MapMetadata.try_get(map_id) return false if !map_metadata return map_metadata.always_bicycle || map_metadata.can_bicycle || map_metadata.outdoor_map end def pbMountBike return if $PokemonGlobal.bicycle $PokemonGlobal.bicycle = true $stats.cycle_count += 1 pbUpdateVehicle bike_bgm = GameData::Metadata.get.bicycle_BGM pbCueBGM(bike_bgm, 0.4) if bike_bgm pbSEPlay("Bicycle") pbPokeRadarCancel end def pbDismountBike return if !$PokemonGlobal.bicycle $PokemonGlobal.bicycle = false pbUpdateVehicle $game_map.autoplayAsCue end