mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2026-07-22 15:47:00 +00:00
521 lines
15 KiB
Ruby
521 lines
15 KiB
Ruby
# todo:
|
||
# When all pokemon in the route are seen, can "scan" for species
|
||
# - spawns a pokemon of that species nearby with notice behavior to flee
|
||
class PokeRadarAppScene < PokeNavAppScene
|
||
INFO_TEXT_Y = 270
|
||
|
||
def header_name
|
||
return _INTL("PokéRadar")
|
||
end
|
||
|
||
def cursor_path
|
||
return "Graphics/Pictures/Pokeradar/icon_button"
|
||
end
|
||
|
||
def header_path
|
||
return "Graphics/Pictures/Pokeradar/bg_header"
|
||
end
|
||
|
||
def display_mode
|
||
return :GRID
|
||
end
|
||
|
||
def x_gap
|
||
return 75;
|
||
end
|
||
|
||
def y_gap
|
||
return 50;
|
||
end
|
||
|
||
def columns
|
||
return 6
|
||
end
|
||
|
||
def visible_rows
|
||
return 3
|
||
end
|
||
|
||
def start_x
|
||
return 40;
|
||
end
|
||
|
||
def start_y
|
||
return 80;
|
||
end
|
||
|
||
def pbStartScene(main_menu_scene)
|
||
@unseenPokemon = [] unless @unseenPokemon
|
||
@seenPokemon = [] unless @seenPokemon
|
||
@pokenav_main_menu_scene = main_menu_scene
|
||
if $PokemonTemp.pokeradar
|
||
buttons = showCurrentScanningTarget
|
||
super(buttons)
|
||
else
|
||
buttons = showWildPokemonList
|
||
super(buttons)
|
||
showSelectedPokemonInfo
|
||
end
|
||
showHeaderInfo
|
||
end
|
||
|
||
def showSelectedPokemonInfo
|
||
hover(@buttons[@index]&.id)
|
||
if @unseenPokemon.empty? && @seenPokemon.empty?
|
||
showEmpty
|
||
end
|
||
end
|
||
|
||
def showHeaderInfo
|
||
showBattery
|
||
showHeaderName
|
||
showAreaName
|
||
showWeatherIcon
|
||
end
|
||
|
||
def showWildPokemonList
|
||
@encounter_type = $PokemonEncounters.encounter_type
|
||
@weatherEncounters = $PokemonEncounters.list_weather_encounters_species(@encounter_type)
|
||
|
||
@unseenPokemon = listPokemonInCurrentRoute(@encounter_type, false, true, true)
|
||
@seenPokemon = listPokemonInCurrentRoute(@encounter_type, true, false, true)
|
||
buttons = []
|
||
@seenPokemon.each do |pokemon_species|
|
||
icon_path = pbCheckPokemonIconFiles(pokemon_species)
|
||
bmp = load_bitmap(icon_path, false)
|
||
button = PokenavButton.new(pokemon_species, bmp)
|
||
button.crop_width = button.icon_bitmap.bitmap.width / 2
|
||
button.refresh
|
||
buttons << button if button
|
||
end
|
||
@unseenPokemon.each do |pokemon_species|
|
||
icon_path = pbCheckPokemonIconFiles(pokemon_species)
|
||
bmp = load_bitmap(icon_path, true)
|
||
button = PokenavButton.new(pokemon_species, bmp)
|
||
button.crop_width = button.icon_bitmap.bitmap.width / 2
|
||
button.refresh
|
||
buttons << button
|
||
end
|
||
return buttons
|
||
end
|
||
|
||
def createCursor
|
||
return if $PokemonTemp.pokeradar
|
||
super
|
||
end
|
||
|
||
def showEmpty
|
||
Kernel.pbDisplayText(_INTL("No wild Pokémon found nearby."), Graphics.width / 2, Graphics.height / 2, nil, @text_color_base, @text_color_shadow)
|
||
Kernel.pbDisplayText(_INTL("Stand in tall grass to start scanning."), Graphics.width / 2,( Graphics.height / 2)+32, nil, @text_color_base, @text_color_shadow)
|
||
|
||
end
|
||
|
||
def showCurrentScanningTarget
|
||
scanningPokemon = $PokemonTemp.pokeradar[0]
|
||
icon_path = pbCheckPokemonIconFiles(scanningPokemon)
|
||
bmp = load_bitmap(icon_path, false)
|
||
button = PokenavButton.new(scanningPokemon, bmp)
|
||
button.refresh
|
||
species_name = GameData::Species.get(scanningPokemon).name
|
||
Kernel.pbDisplayText(_INTL("Currently scanning for {1}.", species_name), Graphics.width / 2, 200, 500000, @text_color_base, @text_color_shadow)
|
||
Kernel.pbDisplayText(_INTL("Current chain: {1}.", $PokemonTemp.pokeradar[2]), Graphics.width / 2, 230, 500000, @text_color_base, @text_color_shadow)
|
||
return [button]
|
||
end
|
||
|
||
def load_bitmap(path, dark = false)
|
||
return nil unless path && path != ""
|
||
bmp = Bitmap.new(path)
|
||
|
||
if dark
|
||
darken_bitmap(bmp, 220) # strength 0–255
|
||
end
|
||
|
||
return AnimatedBitmap.from_bitmap(bmp)
|
||
end
|
||
|
||
def darken_bitmap(bmp, amount)
|
||
for x in 0...bmp.width
|
||
for y in 0...bmp.height
|
||
pixel = bmp.get_pixel(x, y)
|
||
next if pixel.alpha == 0
|
||
|
||
factor = (255 - amount) / 255.0
|
||
r = (pixel.red * factor).to_i
|
||
g = (pixel.green * factor).to_i
|
||
b = (pixel.blue * factor).to_i
|
||
|
||
bmp.set_pixel(x, y, Color.new(r, g, b, pixel.alpha))
|
||
end
|
||
end
|
||
end
|
||
|
||
#[rareness, species, minLevel, maxLevel]
|
||
def get_encounter(species,include_weather=true)
|
||
for encounter in $PokemonEncounters.listPossibleEncounters(@encounter_type, include_weather)
|
||
if encounter[1] == species
|
||
return encounter
|
||
end
|
||
end
|
||
return nil
|
||
end
|
||
|
||
def get_weather_encounter(species)
|
||
for encounter in $PokemonEncounters.list_weather_encounters(@encounter_type)
|
||
if encounter[1] == species
|
||
return encounter
|
||
end
|
||
end
|
||
return nil
|
||
end
|
||
|
||
|
||
def get_energy_for_scan(species)
|
||
encounter = get_encounter(species)
|
||
if @weatherEncounters.include?(species)
|
||
base_rareness = encounter[0]
|
||
rareness =calculate_weather_encounter_rareness(encounter,base_rareness)
|
||
else
|
||
rareness = encounter[0]
|
||
end
|
||
energy = (110 - rareness) * 5
|
||
(energy / 50.0).round * 50
|
||
end
|
||
|
||
def get_rarity_flavor_text(species)
|
||
encounter = get_encounter(species,false)
|
||
weather_encounter = get_weather_encounter(species)
|
||
|
||
return unless encounter || weather_encounter
|
||
if (encounter && encounter[1] == species) || (weather_encounter && weather_encounter[1] == species)
|
||
base_rareness =0
|
||
base_rareness = encounter[0] if encounter
|
||
base_rareness = weather_encounter[0] if weather_encounter
|
||
if @weatherEncounters.include?(species)
|
||
rareness = calculate_weather_encounter_rareness(weather_encounter,base_rareness)
|
||
else
|
||
rareness = base_rareness
|
||
end
|
||
if rareness < 5
|
||
text = _INTL("Very rare")
|
||
elsif rareness < 10
|
||
text = _INTL("Rare")
|
||
elsif rareness < 25
|
||
text = _INTL("Uncommon")
|
||
elsif rareness < 40
|
||
text = _INTL("Common")
|
||
else
|
||
text = _INTL("Very Common")
|
||
end
|
||
return text
|
||
end
|
||
end
|
||
|
||
def calculate_weather_encounter_rareness(encounter,base_rareness)
|
||
map_weather = $game_weather.current_weather[$game_map.map_id]
|
||
if map_weather
|
||
weather_intensity = map_weather[1]
|
||
weather_intensity = 0 if !weather_intensity
|
||
chance_of_weather_encounter = $PokemonEncounters.weather_encounter_chance(weather_intensity)
|
||
weather_rareness = encounter[0]
|
||
return weather_rareness * (chance_of_weather_encounter.to_f / 100) * (base_rareness/100)
|
||
end
|
||
return 0
|
||
end
|
||
|
||
def click(button_id)
|
||
species = button_id
|
||
if $PokemonTemp.pokeradar
|
||
click_stop_scan(species)
|
||
else
|
||
if @seenPokemon.include?(species)
|
||
click_seen(species)
|
||
else
|
||
click_unseen
|
||
end
|
||
|
||
end
|
||
super
|
||
end
|
||
|
||
def hover(button_id)
|
||
return if $PokemonTemp.pokeradar
|
||
if @seenPokemon.include?(button_id)
|
||
hover_seen(button_id)
|
||
else
|
||
hover_unseen
|
||
end
|
||
super
|
||
end
|
||
|
||
def click_stop_scan(species)
|
||
species_name = GameData::Species.get(species).name
|
||
options = []
|
||
cmd_stop_scan = _INTL("Stop Scanning")
|
||
cmd_cancel = _INTL("Cancel")
|
||
options << cmd_stop_scan
|
||
options << cmd_cancel
|
||
Kernel.pbClearText()
|
||
showHeaderInfo
|
||
chosen = pbMessage(_INTL("You are currently scanning for {1}.", species_name), options, options.length)
|
||
case options[chosen]
|
||
when cmd_stop_scan
|
||
$PokemonTemp.pokeradar = nil
|
||
pbEndScene
|
||
pbStartScene(@pokenav_main_menu_scene)
|
||
else
|
||
showCurrentScanningTarget
|
||
return
|
||
end
|
||
|
||
end
|
||
|
||
def click_seen(species)
|
||
options = []
|
||
cmd_scan = _INTL("Scan")
|
||
cmd_cancel = _INTL("Cancel")
|
||
options << cmd_scan
|
||
options << cmd_cancel
|
||
Kernel.pbClearText()
|
||
showHeaderInfo
|
||
chosen = pbMessage(_INTL("What would you like to do?"), options, options.length)
|
||
case options[chosen]
|
||
when cmd_scan
|
||
energy_needed = get_energy_for_scan(species)
|
||
if Settings::POKERADAR_BATTERY_STEPS - $PokemonGlobal.pokeradarBattery >= energy_needed
|
||
$PokemonGlobal.pokeradarBattery += energy_needed
|
||
displayTextElements
|
||
@exiting = true
|
||
|
||
pbEndScene
|
||
@pokenav_main_menu_scene.exiting = true
|
||
@pokenav_main_menu_scene.pbEndScene
|
||
|
||
encounter = get_encounter(species)
|
||
min_level = encounter[2]
|
||
max_level = encounter[3]
|
||
level = rand(min_level..max_level)
|
||
pbWait(16)
|
||
pbMessage(_INTL("Scanning for {1}...\\wtnp[5]", GameData::Species.get(species).name))
|
||
possible_tiles = getTerrainTilesNearPlayer(getTerrainType, 3)
|
||
position = possible_tiles.sample
|
||
if position
|
||
set_pokeradar_data(species, level, position)
|
||
spawn_pokeradar_pokemon(species, level)
|
||
else
|
||
pbPokeRadarCancel
|
||
pbMessage(_INTL("The Pokéradar scan failed... Try again somewhere else"))
|
||
end
|
||
else
|
||
pbPokeRadarCancel
|
||
Kernel.pbClearText()
|
||
showHeaderInfo
|
||
pbMessage(_INTL("The battery is not charged enough for this scan!"))
|
||
showSelectedPokemonInfo
|
||
end
|
||
else
|
||
showSelectedPokemonInfo
|
||
return
|
||
end
|
||
end
|
||
|
||
|
||
|
||
def click_unseen
|
||
return unless @unseenPokemon.any?
|
||
Kernel.pbClearText()
|
||
showHeaderInfo
|
||
pbMessage(_INTL("You need to encounter the Pokémon before you can scan for it."))
|
||
hover_unseen
|
||
end
|
||
|
||
def hover_seen(species)
|
||
displayTextElements
|
||
pokemon_name = GameData::Species.get(species).name
|
||
Kernel.pbDisplayText(pokemon_name, Graphics.width / 2, INFO_TEXT_Y, 99999, @text_color_base, @text_color_shadow)
|
||
Kernel.pbDisplayText(get_rarity_flavor_text(species), Graphics.width / 2, INFO_TEXT_Y + 30, 99999, @text_color_base, @text_color_shadow)
|
||
Kernel.pbDisplayText(_INTL("Battery for scan: {1}", get_energy_for_scan(species)), Graphics.width / 2, INFO_TEXT_Y + 60, 99999, @text_color_base, @text_color_shadow)
|
||
end
|
||
|
||
def hover_unseen()
|
||
return unless @unseenPokemon.any?
|
||
displayTextElements
|
||
pokemon_name = _INTL("Unknown Pokémon")
|
||
Kernel.pbDisplayText(pokemon_name, Graphics.width / 2, INFO_TEXT_Y, 999999, @text_color_base, @text_color_shadow)
|
||
end
|
||
|
||
def displayTextElements
|
||
super
|
||
showBattery
|
||
showAreaName
|
||
|
||
end
|
||
|
||
def showBattery
|
||
$PokemonGlobal.pokeradarBattery = Settings::POKERADAR_BATTERY_STEPS unless $PokemonGlobal.pokeradarBattery
|
||
battery_power = Settings::POKERADAR_BATTERY_STEPS - $PokemonGlobal.pokeradarBattery
|
||
Kernel.pbDisplayText(_INTL("{1}/1000", battery_power), 450, HEADER_HEIGHT,nil, @text_color_base, @text_color_shadow)
|
||
end
|
||
|
||
def showAreaName
|
||
map_name = getMapName($game_map.map_id)
|
||
text = _INTL("{1}", map_name)
|
||
encounter_type = get_encounter_type_name
|
||
if encounter_type && !encounter_type.empty?
|
||
text += _INTL(" ({1})", encounter_type)
|
||
end
|
||
Kernel.pbDisplayText(text, Graphics.width / 2, 40,nil, @text_color_base, @text_color_shadow)
|
||
end
|
||
|
||
def showWeatherIcon
|
||
icon_path = get_current_weather_icon
|
||
return unless icon_path
|
||
@sprites["weather"] = IconSprite.new(400, 48, @viewport)
|
||
@sprites["weather"].setBitmap(icon_path)
|
||
@sprites["weather"].z = 100000
|
||
end
|
||
|
||
def get_encounter_type_name
|
||
encounter_type = $PokemonEncounters.encounter_type
|
||
case encounter_type
|
||
when :Land
|
||
return _INTL("Grass")
|
||
when :Land1
|
||
return _INTL("Clovers")
|
||
when :Land2
|
||
return _INTL("Dry Grass")
|
||
when :Land3
|
||
return _INTL("Flowers")
|
||
when :LandMorning, :LandDay, :LandNight
|
||
return _INTL("Grass")
|
||
when :WaterMorning, :WaterDay, :WaterNight
|
||
return _INTL("Water")
|
||
when :TallGrass
|
||
return _INTL("Tall Grass")
|
||
else
|
||
return encounter_type.to_s
|
||
end
|
||
end
|
||
|
||
end
|
||
|
||
def getTerrainType
|
||
encounter_type = $PokemonEncounters.encounter_type
|
||
case encounter_type
|
||
when :Land, :Land1, :Land2, :Land3, :LandMorning, :LandDay, :LandNight, :TallGrass
|
||
return :Grass
|
||
else
|
||
return encounter_type
|
||
end
|
||
end
|
||
|
||
def continue_pokeradar_app_chain()
|
||
pbWait(12)
|
||
species = $PokemonTemp.pokeradar[0]
|
||
level = $PokemonTemp.pokeradar[1]
|
||
possible_tiles = getTerrainTilesNearPlayer(getTerrainType, 3)
|
||
position = possible_tiles.sample
|
||
if position
|
||
set_pokeradar_data(species, level, position)
|
||
spawn_pokeradar_pokemon(species, level)
|
||
else
|
||
pbPokeRadarCancel
|
||
pbMessage(_INTL("The Pokéradar scan failed... Try again somewhere else"))
|
||
end
|
||
end
|
||
|
||
def update_pokeradar_overworld_ui
|
||
if $PokemonTemp.pokeradar
|
||
current_chain = $PokemonTemp.pokeradar[2]
|
||
return unless current_chain >= 1
|
||
species = $PokemonTemp.pokeradar[0]
|
||
$PokemonTemp.pokeradar_ui.dispose if $PokemonTemp.pokeradar_ui
|
||
$PokemonTemp.pokeradar_ui = PokeRadar_UI.new([species], [], [])
|
||
if current_chain >= 40
|
||
$PokemonTemp.pokeradar_ui.set_text(_INTL("PokéRadar Chain: {1}", current_chain), 72, 12, pbColor(:GREEN), pbColor(:DARKGREEN))
|
||
else
|
||
$PokemonTemp.pokeradar_ui.set_text(_INTL("PokéRadar Chain: {1}", current_chain), 72, 12)
|
||
end
|
||
else
|
||
$PokemonTemp.pokeradar_ui.dispose if $PokemonTemp.pokeradar_ui
|
||
end
|
||
|
||
end
|
||
|
||
def spawn_pokeradar_pokemon(species, level)
|
||
max_attempts = 50
|
||
return unless species && level
|
||
|
||
pbWait(20)
|
||
playAnimation(Settings::POKERADAR_LIGHT_ANIMATION_RED_ID, $game_player.x, $game_player.y)
|
||
pbWait(10)
|
||
|
||
spawned_events = nil
|
||
radius = 4
|
||
max_radius = 8
|
||
max_attempts.times do |current_attempt|
|
||
radius += 1 if current_attempt > 0 && current_attempt % 10 == 0
|
||
radius += (current_attempt / 10).floor
|
||
radius = [radius, max_radius].min
|
||
spawned_events = spawn_ow_pokemon(species, level, 1, radius)
|
||
break if spawned_events&.length.to_i > 0
|
||
end
|
||
|
||
if spawned_events&.length.to_i > 0
|
||
event = spawned_events[0]
|
||
grass = $PokemonTemp&.pokeradar[3]
|
||
|
||
if grass && grass[3] == 2
|
||
pbSEPlay("shiny", 60)
|
||
playAnimation(Settings::SPARKLE_SHORT_ANIMATION_ID, event.x, event.y)
|
||
event.make_shiny
|
||
end
|
||
|
||
#todo: MAYBE increase the move frequency past a certain chain number (50?) to make it more difficult
|
||
event.behavior_roaming = :look_around_player
|
||
event.behavior_noticed = event.pokemon.shiny? ? :curious : :flee
|
||
event.update_movement_type
|
||
event.turn_away_from_player
|
||
playAnimation(Settings::POKERADAR_LIGHT_ANIMATION_RED_ID, event.x, event.y)
|
||
else
|
||
echoln "failed to spawn after #{max_attempts} attempts"
|
||
pbPokeRadarCancel
|
||
pbMessage(_INTL("The Pokéradar scan failed... Try again somewhere else"))
|
||
end
|
||
|
||
update_pokeradar_overworld_ui
|
||
end
|
||
|
||
# Reusing the old pokeradar mechanics for chaining
|
||
def set_pokeradar_data(species, level, position)
|
||
x = position[0]
|
||
y = position[1]
|
||
|
||
existing_chain = ($PokemonTemp.pokeradar && $PokemonTemp.pokeradar[2]) ? $PokemonTemp.pokeradar[2] : 0
|
||
|
||
$PokemonTemp.pokeradar = [0, 0, 0, []] unless $PokemonTemp.pokeradar
|
||
$PokemonTemp.pokeradar[0] = species
|
||
$PokemonTemp.pokeradar[1] = level
|
||
$PokemonTemp.pokeradar[2] = existing_chain
|
||
$PokemonTemp.pokeradar[3] = [x, y, 0, determine_shininess]
|
||
end
|
||
|
||
def determine_shininess
|
||
chain_length = ($PokemonTemp.pokeradar && $PokemonTemp.pokeradar[2]) ? $PokemonTemp.pokeradar[2] : 0
|
||
rarity = (rand(100) < 25) ? 1 : 0
|
||
if chain_length > 0
|
||
capped_chain = [chain_length, 40].min
|
||
shiny_threshold = [(65536 / Settings::SHINY_POKEMON_CHANCE) - capped_chain * 200, 200].max
|
||
shiny_divisor = 0xFFFF / shiny_threshold
|
||
shiny_roll = rand(65536) / shiny_divisor
|
||
rarity = 2 if shiny_roll == 0
|
||
end
|
||
return rarity
|
||
end
|
||
|
||
|
||
Events.onMapChange += proc { |_sender, e|
|
||
pbPokeRadarCancel
|
||
}
|
||
|
||
|