mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-10 22:54:59 +00:00
6.6 update
This commit is contained in:
51
Data/Scripts/053_PIF_Hoenn/DiveGraphics.rb
Normal file
51
Data/Scripts/053_PIF_Hoenn/DiveGraphics.rb
Normal file
@@ -0,0 +1,51 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Game_Temp
|
||||
attr_accessor :water_plane
|
||||
attr_accessor :water_plane2
|
||||
|
||||
end
|
||||
|
||||
alias originalCausticsMethod addWaterCausticsEffect
|
||||
def addWaterCausticsEffect(fog_name = "caustic1", opacity = 16)
|
||||
originalCausticsMethod(fog_name, 8)
|
||||
if Settings::GAME_ID == :IF_HOENN && $PokemonGlobal.diving
|
||||
if $game_temp.water_plane
|
||||
$game_temp.water_plane.bitmap.dispose if $game_temp.water_plane.bitmap
|
||||
$game_temp.water_plane.dispose
|
||||
end
|
||||
if $game_temp.water_plane2
|
||||
$game_temp.water_plane2.bitmap.dispose if $game_temp.water_plane2.bitmap
|
||||
$game_temp.water_plane2.dispose
|
||||
end
|
||||
|
||||
|
||||
$game_temp.water_plane = AnimatedPlane.new(Spriteset_Map.viewport)
|
||||
$game_temp.water_plane.bitmap = RPG::Cache.picture("Dive/ocean_dive")
|
||||
$game_temp.water_plane.z = -2
|
||||
$game_temp.water_plane.opacity = 230
|
||||
|
||||
$game_temp.water_plane2 = AnimatedPlane.new(Spriteset_Map.viewport)
|
||||
$game_temp.water_plane2.bitmap = RPG::Cache.picture("Dive/dive_dark2") # Different image if needed
|
||||
$game_temp.water_plane2.z = 2
|
||||
$game_temp.water_plane2.opacity = 210
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
class Spriteset_Map
|
||||
alias pokemonEssentials_spritesetMap_update update
|
||||
def update
|
||||
pokemonEssentials_spritesetMap_update
|
||||
if Settings::GAME_ID == :IF_HOENN && $PokemonGlobal.diving
|
||||
@fog.z=-1 if @fog
|
||||
@fog2.z=-1 if @fog2
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class PokemonEncounters
|
||||
WEATHER_ENCOUNTER_BASE_CHANCE = 8 #/100 (for weather intensity of 0)
|
||||
alias pokemonEssentials_PokemonEncounter_choose_wild_pokemon choose_wild_pokemon
|
||||
def choose_wild_pokemon(enc_type, *args)
|
||||
return pokemonEssentials_PokemonEncounter_choose_wild_pokemon(enc_type, *args) if !$game_weather
|
||||
current_weather_type = $game_weather.get_map_weather_type($game_map.map_id)
|
||||
current_weather_intensity = $game_weather.get_map_weather_intensity($game_map.map_id)
|
||||
if can_substitute_for_weather_encounter(enc_type, current_weather_type)
|
||||
#Chance to replace the chosen by one in from the weather pool
|
||||
if roll_for_weather_encounter(current_weather_intensity)
|
||||
weather_encounter_type = get_weather_encounter_type(enc_type,current_weather_type)
|
||||
echoln "weather encounter!"
|
||||
echoln weather_encounter_type
|
||||
return pokemonEssentials_PokemonEncounter_choose_wild_pokemon(weather_encounter_type) if(weather_encounter_type)
|
||||
end
|
||||
end
|
||||
return pokemonEssentials_PokemonEncounter_choose_wild_pokemon(enc_type, *args)
|
||||
end
|
||||
|
||||
|
||||
SUBSTITUTABLE_ENCOUNTER_TYPES = [:Land, :Land1, :Land2, :Land3, :Water]
|
||||
def can_substitute_for_weather_encounter(encounter_type,current_weather)
|
||||
return false if Settings::GAME_ID != :IF_HOENN
|
||||
return false if !SUBSTITUTABLE_ENCOUNTER_TYPES.include?(encounter_type)
|
||||
return false if current_weather.nil? || current_weather == :None
|
||||
return true
|
||||
end
|
||||
|
||||
def get_weather_encounter_type(normal_encounter_type, current_weather_type)
|
||||
base_encounter_type = normal_encounter_type == :Water ? :Water : :Land
|
||||
weather_encounter_type = "#{base_encounter_type}#{current_weather_type}".to_sym
|
||||
return weather_encounter_type if GameData::EncounterType.exists?(weather_encounter_type)
|
||||
return nil
|
||||
end
|
||||
def roll_for_weather_encounter(weather_intensity)
|
||||
weather_encounter_chance = (WEATHER_ENCOUNTER_BASE_CHANCE * weather_intensity)+WEATHER_ENCOUNTER_BASE_CHANCE
|
||||
return rand(100) < weather_encounter_chance
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,76 @@
|
||||
GameData::EncounterType.register({
|
||||
:id => :LandRain,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10]
|
||||
})
|
||||
|
||||
GameData::EncounterType.register({
|
||||
:id => :LandSunny,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10],
|
||||
})
|
||||
|
||||
GameData::EncounterType.register({
|
||||
:id => :LandWind,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10],
|
||||
})
|
||||
|
||||
GameData::EncounterType.register({
|
||||
:id => :LandFog,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10],
|
||||
})
|
||||
|
||||
GameData::EncounterType.register({
|
||||
:id => :LandStorm,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10],
|
||||
})
|
||||
|
||||
GameData::EncounterType.register({
|
||||
:id => :LandSnow,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10],
|
||||
})
|
||||
|
||||
GameData::EncounterType.register({
|
||||
:id => :WaterRain,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10],
|
||||
})
|
||||
|
||||
GameData::EncounterType.register({
|
||||
:id => :WaterSunny,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10],
|
||||
})
|
||||
|
||||
GameData::EncounterType.register({
|
||||
:id => :WaterWind,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10],
|
||||
})
|
||||
|
||||
GameData::EncounterType.register({
|
||||
:id => :WaterFog,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10],
|
||||
})
|
||||
|
||||
|
||||
|
||||
GameData::EncounterType.register({
|
||||
:id => :WaterStorm,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10],
|
||||
})
|
||||
|
||||
GameData::EncounterType.register({
|
||||
:id => :WaterSnow,
|
||||
:type => :none,
|
||||
:old_slots => [30,30,10,15,5,10],
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
def update_neighbor_map
|
||||
@neighbors_maps = generate_neighbor_map_from_town_map
|
||||
@neighbors_maps = normalize_neighbors(@neighbors_maps)
|
||||
end
|
||||
|
||||
def normalize_neighbors(map)
|
||||
fixed_map = {}
|
||||
|
||||
map.each do |map_id, neighbors|
|
||||
neighbors.each do |neighbor_id|
|
||||
fixed_map[map_id] ||= []
|
||||
fixed_map[neighbor_id] ||= []
|
||||
fixed_map[map_id] |= [neighbor_id]
|
||||
fixed_map[neighbor_id] |= [map_id]
|
||||
end
|
||||
end
|
||||
|
||||
fixed_map
|
||||
end
|
||||
def generate_neighbor_map_from_town_map
|
||||
mapdata = pbLoadTownMapData
|
||||
neighbor_map = {}
|
||||
name_to_map_id = {}
|
||||
name_grid = {}
|
||||
|
||||
# First, build:
|
||||
# - a grid: [x, y] => location_name
|
||||
# - a lookup: location_name => map_id (if one exists)
|
||||
mapdata.each do |region|
|
||||
maps_array = region[2]
|
||||
maps_array.each do |entry|
|
||||
x, y, name, _showname, map_id = entry
|
||||
next unless name.is_a?(String) && !name.empty?
|
||||
|
||||
name_grid[[x, y]] = name
|
||||
if map_id.is_a?(Integer) #&& !is_indoor_map?(map_id)
|
||||
name_to_map_id[name] ||= map_id # Only keep the first valid one
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Now, check each tile against its neighbors (up/down/left/right)
|
||||
name_grid.each do |(x, y), name|
|
||||
[[0, -1], [0, 1], [-1, 0], [1, 0]].each do |dx, dy|
|
||||
neighbor_coords = [x + dx, y + dy]
|
||||
neighbor_name = name_grid[neighbor_coords]
|
||||
|
||||
map1 = name_to_map_id[name]
|
||||
map2 = name_to_map_id[neighbor_name]
|
||||
next unless map1 && map2
|
||||
next if map1 == map2 # Prevent self-linking
|
||||
|
||||
neighbor_map[map1] ||= []
|
||||
neighbor_map[map2] ||= []
|
||||
|
||||
neighbor_map[map1] << map2 unless neighbor_map[map1].include?(map2)
|
||||
neighbor_map[map2] << map1 unless neighbor_map[map2].include?(map1)
|
||||
end
|
||||
end
|
||||
return neighbor_map
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
def generate_neighbor_map_from_connections
|
||||
raw_connections = MapFactoryHelper.getMapConnections
|
||||
neighbor_map = {}
|
||||
|
||||
raw_connections.each_with_index do |conns, map_id|
|
||||
next if conns.nil? || conns.empty?
|
||||
|
||||
conns.each do |conn|
|
||||
next unless conn.is_a?(Array) && conn.length >= 4
|
||||
map1 = conn[0]
|
||||
map2 = conn[3]
|
||||
|
||||
next unless map1.is_a?(Integer) && map2.is_a?(Integer)
|
||||
#next if is_indoor_map?(map1) || is_indoor_map?(map2)
|
||||
|
||||
neighbor_map[map1] ||= []
|
||||
neighbor_map[map2] ||= []
|
||||
neighbor_map[map1] << map2 unless neighbor_map[map1].include?(map2)
|
||||
neighbor_map[map2] << map1 unless neighbor_map[map2].include?(map1)
|
||||
end
|
||||
end
|
||||
|
||||
return neighbor_map
|
||||
end
|
||||
|
||||
def is_indoor_map?(map_id)
|
||||
return false
|
||||
mapMetadata = GameData::MapMetadata.try_get(map_id)
|
||||
return true if !mapMetadata
|
||||
return !mapMetadata.outdoor_map
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
Events.onMapChange+= proc { |_old_map_id|
|
||||
next if !$game_weather || !$game_weather.current_weather || !$game_weather.last_update_time
|
||||
next if !$game_map
|
||||
echoln pbGetTimeNow.to_i
|
||||
update_overworld_weather($game_map.map_id)
|
||||
next if $game_weather.last_update_time.to_i + GameWeather::TIME_BETWEEN_WEATHER_UPDATES > pbGetTimeNow.to_i
|
||||
|
||||
new_map_id = $game_map.map_id
|
||||
mapMetadata = GameData::MapMetadata.try_get(new_map_id)
|
||||
next if mapMetadata.nil?
|
||||
$game_screen.weather(:None,0,0) if !mapMetadata.outdoor_map
|
||||
next unless mapMetadata.outdoor_map
|
||||
$game_weather.update_weather
|
||||
}
|
||||
|
||||
def update_overworld_weather(current_map)
|
||||
return if current_map.nil?
|
||||
return if !$game_weather.current_weather
|
||||
current_weather_array = $game_weather.current_weather[current_map]
|
||||
return if current_weather_array.nil?
|
||||
current_weather_type = current_weather_array[0]
|
||||
current_weather_intensity = current_weather_array[1]
|
||||
current_weather_type = :None if !current_weather_type
|
||||
current_weather_intensity=0 if !current_weather_intensity
|
||||
current_weather_type = :None if PBDayNight.isNight? && current_weather_type == :Sunny
|
||||
$game_screen.weather(current_weather_type,current_weather_intensity,0)
|
||||
end
|
||||
@@ -0,0 +1,131 @@
|
||||
class BetterRegionMap
|
||||
DEBUG_WEATHER = true
|
||||
def update_weather_icon(location)
|
||||
return
|
||||
return nil if !location
|
||||
map_id = location[4]
|
||||
return nil if !map_id
|
||||
|
||||
weather_at_location = $game_weather.current_weather[map_id]
|
||||
return nil if weather_at_location.nil?
|
||||
|
||||
weather_type = weather_at_location[0]
|
||||
weather_intensity = weather_at_location[1]
|
||||
|
||||
icon = get_weather_icon(weather_type,weather_intensity)
|
||||
return nil if icon.nil?
|
||||
icon_path = "Graphics/Pictures/Weather/Cursor/" + icon
|
||||
|
||||
# @sprites["weather"].visible=true
|
||||
@sprites["cursor"].bmp(icon_path)
|
||||
@sprites["cursor"].src_rect.width = @sprites["cursor"].bmp.height
|
||||
return weather_type
|
||||
|
||||
end
|
||||
|
||||
|
||||
def draw_all_weather
|
||||
processed_locations =[]
|
||||
n=0
|
||||
for x in 0...(@window["map"].bmp.width / TileWidth)
|
||||
for y in 0...(@window["map"].bmp.height / TileHeight)
|
||||
|
||||
for location in @data[2]
|
||||
if location[0] == x && location[1] == y
|
||||
|
||||
map_id = location[4]
|
||||
|
||||
next if !map_id
|
||||
next if processed_locations.include?(map_id)
|
||||
|
||||
weather_at_location = $game_weather.current_weather[map_id]
|
||||
next if weather_at_location.nil?
|
||||
|
||||
weather_type = weather_at_location[0]
|
||||
weather_intensity = weather_at_location[1]
|
||||
|
||||
weather_icon = get_full_weather_icon_name(weather_type,weather_intensity)
|
||||
next if weather_icon.nil?
|
||||
weather_icon_path = "Graphics/Pictures/Weather/" + weather_icon
|
||||
@weatherIcons["weather#{n}"] = Sprite.new(@mapvp)
|
||||
@weatherIcons["weather#{n}"].bmp(weather_icon_path)
|
||||
@weatherIcons["weather#{n}"].src_rect.width = @weatherIcons["weather#{n}"].bmp.height
|
||||
@weatherIcons["weather#{n}"].x = TileWidth * x + (TileWidth / 2)
|
||||
@weatherIcons["weather#{n}"].y = TileHeight * y + (TileHeight / 2)
|
||||
@weatherIcons["weather#{n}"].oy = @weatherIcons["weather#{n}"].bmp.height / 2.0
|
||||
@weatherIcons["weather#{n}"].ox = @weatherIcons["weather#{n}"].oy
|
||||
|
||||
processed_locations << map_id
|
||||
n= n+1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def new_weather_cycle
|
||||
return if !$game_weather
|
||||
@weatherIcons.dispose
|
||||
@weatherIcons = SpriteHash.new
|
||||
$game_weather.update_weather
|
||||
draw_all_weather
|
||||
end
|
||||
|
||||
end
|
||||
def get_current_map_weather_icon
|
||||
return if !$game_weather
|
||||
current_weather= $game_weather.current_weather[$game_map.map_id]
|
||||
weather_type = current_weather[0]
|
||||
weather_intensity = current_weather[1]
|
||||
icon = get_full_weather_icon_name(weather_type,weather_intensity)
|
||||
return "Graphics/Pictures/Weather/" +icon if icon
|
||||
return nil
|
||||
end
|
||||
|
||||
def get_weather_icon(weather_type,intensity)
|
||||
case weather_type
|
||||
when :Sunny #&& !PBDayNight.isNight?
|
||||
icon_name = "mapSun"
|
||||
when :Rain
|
||||
icon_name = "mapRain"
|
||||
when :Fog
|
||||
icon_name = "mapFog"
|
||||
when :Wind
|
||||
icon_name = "mapWind"
|
||||
when :Storm
|
||||
icon_name = "mapStorm"
|
||||
when :Sandstorm
|
||||
icon_name = "mapSand"
|
||||
when :Snow
|
||||
icon_name = "mapSnow"
|
||||
when :HeavyRain
|
||||
icon_name = "mapHeavyRain"
|
||||
when :StrongWinds
|
||||
icon_name = "mapStrongWinds"
|
||||
when :HarshSun
|
||||
icon_name = "mapHarshSun"
|
||||
else
|
||||
icon_name = nil
|
||||
end
|
||||
return icon_name
|
||||
end
|
||||
def get_full_weather_icon_name(weather_type,intensity)
|
||||
return nil if !weather_type
|
||||
return nil if !intensity
|
||||
same_intensity_weather_types = [:Sandstorm,:Snow,:StrongWinds,:HeavyRain,:HarshSun]
|
||||
|
||||
base_weather_icon_name = get_weather_icon(weather_type,intensity)
|
||||
icon_name = base_weather_icon_name
|
||||
return nil if !icon_name
|
||||
return icon_name if same_intensity_weather_types.include?(weather_type)
|
||||
if intensity <= 2
|
||||
icon_name += "_light"
|
||||
elsif intensity <=4
|
||||
icon_name += "_medium"
|
||||
else
|
||||
icon_name += "_heavy"
|
||||
end
|
||||
return icon_name
|
||||
end
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
|
||||
def isRaining?()
|
||||
return isWeatherRain? || isWeatherStorm?
|
||||
end
|
||||
|
||||
def isWeatherRain?()
|
||||
return $game_weather.get_map_weather_type($game_map.map_id) == :Rain || $game_weather.get_map_weather_type($game_map.map_id) == :HeavyRain
|
||||
end
|
||||
|
||||
def isWeatherSunny?()
|
||||
return $game_weather.get_map_weather_type($game_map.map_id) == :Sunny || $game_weather.get_map_weather_type($game_map.map_id) == :HarshSun
|
||||
end
|
||||
|
||||
def isWeatherStorm?()
|
||||
return $game_weather.get_map_weather_type($game_map.map_id) == :Storm
|
||||
end
|
||||
|
||||
def isWeatherWind?()
|
||||
return $game_weather.get_map_weather_type($game_map.map_id) == :Wind || $game_weather.get_map_weather_type($game_map.map_id) == :StrongWinds
|
||||
end
|
||||
|
||||
def isWeatherFog?()
|
||||
return $game_weather.get_map_weather_type($game_map.map_id) == :Fog
|
||||
end
|
||||
|
||||
def isWeatherSnow?()
|
||||
return $game_weather.get_map_weather_type($game_map.map_id) == :Fog
|
||||
end
|
||||
|
||||
|
||||
def changeCurrentWeather(weatherType,intensity)
|
||||
new_map_id = $game_map.map_id
|
||||
mapMetadata = GameData::MapMetadata.try_get(new_map_id)
|
||||
return nil if mapMetadata.nil?
|
||||
return nil if !mapMetadata.outdoor_map
|
||||
if $game_weather
|
||||
$game_weather.set_map_weather($game_map.map_id,weatherType,intensity)
|
||||
$game_weather.update_overworld_weather($game_map.map_id)
|
||||
else
|
||||
$game_screen.weather(weatherType,intensity,5)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,376 @@
|
||||
# Dynamic weather system by Chardub, for Pokemon Infinite Fusion
|
||||
|
||||
if Settings::GAME_ID == :IF_HOENN
|
||||
SaveData.register(:weather) do
|
||||
ensure_class :GameWeather
|
||||
save_value { $game_weather }
|
||||
load_value { |value|
|
||||
if value.is_a?(GameWeather)
|
||||
$game_weather = value
|
||||
else
|
||||
$game_weather = GameWeather.new
|
||||
end
|
||||
$game_weather.update_neighbor_map # reupdate the neighbors map to account for new maps added
|
||||
|
||||
$game_weather.initialize_weather unless $game_weather.current_weather
|
||||
}
|
||||
new_game_value { GameWeather.new }
|
||||
end
|
||||
end
|
||||
class GameWeather
|
||||
attr_accessor :current_weather
|
||||
attr_accessor :last_update_time
|
||||
|
||||
TIME_BETWEEN_WEATHER_UPDATES = 12000 # 180 seconds, only actually changes once the player changes map
|
||||
|
||||
CHANCE_OF_NEW_WEATHER = 2 # /100 spontaneous new weather popping up somewhere
|
||||
CHANCE_OF_RAIN = 40 #/100
|
||||
CHANCE_OF_SUNNY = 30 #/100
|
||||
CHANCE_OF_WINDY = 30 #/100
|
||||
CHANCE_OF_FOG = 30 #/100 Only possible in the morning, otherwise, when rain and sun combine
|
||||
|
||||
MAX_INTENSITY_ON_NEW_WEATHER = 4
|
||||
|
||||
|
||||
CHANCES_OF_INTENSITY_INCREASE = 30 # /100
|
||||
CHANCES_OF_INTENSITY_DECREASE = 20 # /100
|
||||
BASE_CHANCE_OF_WEATHER_SPREAD = 15
|
||||
BASE_CHANCES_OF_WEATHER_END = 10 #/100 - For a weather intensity of 10. Chances should increase the lower the intensity is
|
||||
BASE_CHANCES_OF_WEATHER_MOVE = 10
|
||||
DEBUG_PROPAGATION = false
|
||||
|
||||
COLD_MAPS = [444] # Rain is snow on that map (shoal cave)
|
||||
SNOW_LIMITS = [965,951] # Route 121, Pacifidlog - Snow turns to rain if it reaches these maps
|
||||
|
||||
|
||||
SANDSTORM_MAPS = [555] # Always sandstorm, doesn't spread
|
||||
SOOT_MAPS = [] # Always soot, doesn't spread
|
||||
NO_WIND_MAPS = [989] # Sootopolis, Petalburg Forest
|
||||
|
||||
def set_weather(map_id, weather_type, intensity)
|
||||
@current_weather[map_id] = [weather_type, intensity]
|
||||
update_overworld_weather($game_map.map_id)
|
||||
end
|
||||
|
||||
def map_current_weather_type(map_id)
|
||||
map_weather = @current_weather[map_id]
|
||||
return map_weather[0] if map_weather
|
||||
end
|
||||
|
||||
def initialize
|
||||
@last_update_time = pbGetTimeNow
|
||||
echoln @last_update_time
|
||||
# Similar to roaming legendaries: A hash of all the maps accessible from one map
|
||||
@neighbors_maps = generate_neighbor_map_from_town_map
|
||||
initialize_weather
|
||||
end
|
||||
|
||||
def initialize_weather
|
||||
weather = {}
|
||||
@neighbors_maps.keys.each { |map_id|
|
||||
weather[map_id] = select_new_weather_spawn
|
||||
}
|
||||
@current_weather = weather
|
||||
end
|
||||
|
||||
def set_map_weather(map_id,weather_type,intensity)
|
||||
@current_weather[map_id] = [weather_type,intensity]
|
||||
end
|
||||
|
||||
def get_map_weather_type(map_id)
|
||||
if !@current_weather[map_id]
|
||||
@current_weather[map_id] = [:None,0]
|
||||
end
|
||||
return @current_weather[map_id][0]
|
||||
end
|
||||
|
||||
def get_map_weather_intensity(map_id)
|
||||
if !@current_weather[map_id]
|
||||
@current_weather[map_id] = [:None,0]
|
||||
end
|
||||
return @current_weather[map_id][1]
|
||||
end
|
||||
|
||||
#Legendary weather conditions can't dissapear, so they're treated as their full force counterpart for spreading
|
||||
def normalize_legendary_weather(type, intensity)
|
||||
case type
|
||||
when :HarshSun then [:Sunny, 10]
|
||||
when :HeavyRain then [:Rain, 10]
|
||||
when :StrongWinds then [:Wind, 10]
|
||||
else [type, intensity]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def update_weather()
|
||||
return if !$game_weather
|
||||
new_weather = @current_weather.dup
|
||||
new_weather.each do |map_id, (type, intensity)|
|
||||
try_end_weather(map_id,type, get_map_weather_intensity(map_id))
|
||||
try_spawn_new_weather(map_id,type, intensity)
|
||||
try_propagate_weather_to_neighbors(map_id,type, intensity)
|
||||
echoln @current_weather[954] if @debug_you
|
||||
try_move_weather_to_neighbors(map_id,type, intensity)
|
||||
try_weather_intensity_decrease(map_id,type, intensity)
|
||||
try_weather_intensity_increase(map_id,type, intensity)
|
||||
end
|
||||
update_overworld_weather($game_map.map_id)
|
||||
@last_update_time = pbGetTimeNow
|
||||
end
|
||||
|
||||
def try_propagate_weather_to_neighbors(map_id,propagating_map_weather_type,propagating_map_weather_intensity)
|
||||
propagating_map_neighbors = @neighbors_maps[map_id]
|
||||
|
||||
return if propagating_map_weather_type == :None
|
||||
return unless can_weather_spread(propagating_map_weather_type)
|
||||
propagating_map_weather_type, propagating_map_weather_intensity = normalize_legendary_weather(propagating_map_weather_type, propagating_map_weather_intensity)
|
||||
propagating_map_neighbors.each do |neighbor_id|
|
||||
neighbor_weather_type = get_map_weather_type(neighbor_id)
|
||||
neighbor_weather_intensity = get_map_weather_intensity(neighbor_id)
|
||||
should_propagate = roll_for_weather_propagation(propagating_map_weather_type, propagating_map_weather_intensity, neighbor_weather_type, neighbor_weather_intensity)
|
||||
next if !should_propagate
|
||||
propagated_weather_type = resolve_weather_interaction(propagating_map_weather_type, neighbor_weather_type, propagating_map_weather_intensity, neighbor_weather_intensity)
|
||||
propagated_weather_intensity = [propagating_map_weather_intensity - 1, 1].max
|
||||
new_weather = get_updated_weather(propagated_weather_type, propagated_weather_intensity, neighbor_id)
|
||||
@current_weather[neighbor_id] = new_weather
|
||||
end
|
||||
end
|
||||
|
||||
def try_spawn_new_weather(map_id,map_weather_type,weather_intensity)
|
||||
return if map_weather_type != :None
|
||||
new_weather = select_new_weather_spawn
|
||||
@current_weather[map_id] = adjust_weather_for_map(new_weather,map_id)
|
||||
end
|
||||
|
||||
|
||||
def try_move_weather_to_neighbors(map_id,map_weather_type,weather_intensity)
|
||||
map_neighbors = @neighbors_maps[map_id]
|
||||
return if map_weather_type == :None || weather_intensity <= 1
|
||||
return unless can_weather_spread(map_weather_type)
|
||||
map_weather_type, weather_intensity = normalize_legendary_weather(map_weather_type, weather_intensity)
|
||||
|
||||
map_neighbors.each do |neighbor_id|
|
||||
neighbor_weather_type = get_map_weather_type(neighbor_id)
|
||||
neighbor_weather_intensity = get_map_weather_intensity(neighbor_id)
|
||||
|
||||
should_move_weather = roll_for_weather_move(map_weather_type)
|
||||
next if !should_move_weather
|
||||
next if neighbor_weather_type == map_weather_type && neighbor_weather_intensity >= weather_intensity
|
||||
result_weather_type = resolve_weather_interaction(map_weather_type, neighbor_weather_type, weather_intensity, neighbor_weather_intensity)
|
||||
result_weather_intensity = weather_intensity
|
||||
new_weather = [result_weather_type,result_weather_intensity]
|
||||
@current_weather[neighbor_id] = adjust_weather_for_map(new_weather,map_id)
|
||||
end
|
||||
end
|
||||
|
||||
def try_weather_intensity_decrease(map_id,map_weather_type,weather_intensity)
|
||||
return unless can_weather_decrease(map_weather_type)
|
||||
should_change_intensity = roll_for_weather_decrease(map_weather_type)
|
||||
return if !should_change_intensity
|
||||
new_weather = [map_weather_type,weather_intensity-1]
|
||||
@current_weather[map_id] = adjust_weather_for_map(new_weather,map_id)
|
||||
end
|
||||
|
||||
def try_weather_intensity_increase(map_id,map_weather_type,weather_intensity)
|
||||
return unless can_weather_increase(map_weather_type)
|
||||
should_change_intensity = roll_for_weather_increase(map_weather_type)
|
||||
return if !should_change_intensity
|
||||
new_weather = [map_weather_type,weather_intensity+1]
|
||||
@current_weather[map_id] = adjust_weather_for_map(new_weather,map_id)
|
||||
end
|
||||
|
||||
def try_end_weather(map_id,map_weather_type,weather_intensity)
|
||||
return unless can_weather_end(map_weather_type)
|
||||
|
||||
should_weather_end = roll_for_weather_end(map_weather_type,weather_intensity)
|
||||
return if !should_weather_end
|
||||
if weather_intensity >1
|
||||
map_weather_type = :Rain if map_weather_type == :Storm
|
||||
new_weather = [map_weather_type,0]
|
||||
else
|
||||
new_weather = [:None,0]
|
||||
end
|
||||
@current_weather[map_id] = adjust_weather_for_map(new_weather,map_id)
|
||||
end
|
||||
|
||||
|
||||
def adjust_weather_for_map(map_current_weather,map_id)
|
||||
type = map_current_weather[0]
|
||||
intensity = map_current_weather[1]
|
||||
return get_updated_weather(type,intensity,map_id)
|
||||
end
|
||||
|
||||
def get_updated_weather(type, intensity, map_id)
|
||||
if COLD_MAPS.include?(map_id)
|
||||
type = :Snow if type == :Rain
|
||||
type = :Blizzard if type == :Storm
|
||||
type = :None if type == :Sunny
|
||||
end
|
||||
if SNOW_LIMITS.include?(map_id)
|
||||
type = :Rain if type == :Snow
|
||||
end
|
||||
|
||||
|
||||
if SOOT_MAPS.include?(map_id)
|
||||
type = :SootRain if type == :Rain
|
||||
end
|
||||
if NO_WIND_MAPS.include?(map_id)
|
||||
type = :None if type == :Wind
|
||||
end
|
||||
if SANDSTORM_MAPS.include?(map_id)
|
||||
type = :Sandstorm
|
||||
intensity = 9
|
||||
end
|
||||
if (PBDayNight.isNight? || PBDayNight.isEvening?) && type == :Sunny
|
||||
type = :None
|
||||
intensity = 0
|
||||
end
|
||||
return [type, intensity]
|
||||
end
|
||||
|
||||
def get_map_name(map_id)
|
||||
mapinfos = pbLoadMapInfos
|
||||
if mapinfos[map_id]
|
||||
neighbor_map_name = mapinfos[map_id].name
|
||||
else
|
||||
neighbor_map_name = "Map #{map_id}"
|
||||
end
|
||||
return neighbor_map_name
|
||||
end
|
||||
|
||||
def resolve_weather_interaction(incoming, existing, incoming_intensity, existing_intensity)
|
||||
return existing unless can_weather_end(existing)
|
||||
return incoming if existing == :None
|
||||
return :Fog if incoming == :Rain && existing == :Sunny
|
||||
return :Fog if incoming == :Sunny && existing == :Rain
|
||||
|
||||
if incoming == :Rain && existing == :Wind
|
||||
return :Storm if incoming_intensity >= 5 || existing_intensity >= 5
|
||||
end
|
||||
return incoming
|
||||
end
|
||||
|
||||
def print_current_weather()
|
||||
mapinfos = pbLoadMapInfos
|
||||
echoln "Current weather :"
|
||||
@current_weather.each do |map_id, value|
|
||||
game_map = mapinfos[map_id]
|
||||
if game_map
|
||||
map_name = mapinfos[map_id].name
|
||||
else
|
||||
map_name = map_id
|
||||
end
|
||||
echoln " #{map_name} : #{value}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def can_weather_spread(type)
|
||||
return false if type == :Sandstorm
|
||||
return true
|
||||
end
|
||||
|
||||
def can_weather_move(type)
|
||||
return false if type == :Sandstorm
|
||||
return false if type == :HeavyRain
|
||||
return false if type == :HarshSun
|
||||
return false if type == :StrongWinds
|
||||
return true
|
||||
end
|
||||
|
||||
def can_weather_end(type)
|
||||
return false if type == :Sandstorm
|
||||
return false if type == :HeavyRain
|
||||
return false if type == :HarshSun
|
||||
return false if type == :StrongWinds
|
||||
# Sandstorm and special weathers for kyogre/groudon/rayquaza
|
||||
return true
|
||||
end
|
||||
|
||||
def can_weather_decrease(type)
|
||||
return false if type == :Sandstorm
|
||||
return false if type == :HeavyRain
|
||||
return false if type == :HarshSun
|
||||
return false if type == :StrongWinds
|
||||
# Sandstorm and special weathers for kyogre/groudon/rayquaza
|
||||
return true
|
||||
end
|
||||
|
||||
def can_weather_increase(type)
|
||||
return false if type == :Sandstorm
|
||||
return false if type == :HeavyRain
|
||||
return false if type == :HarshSun
|
||||
return false if type == :StrongWinds
|
||||
# Sandstorm and special weathers for kyogre/groudon/rayquaza
|
||||
return true
|
||||
end
|
||||
|
||||
def roll_for_weather_propagation(propagating_map_weather_type, propagating_map_weather_intensity, destination_map_weather_type, destination_map_weather_intensity)
|
||||
if propagating_map_weather_type == destination_map_weather_type
|
||||
# same weather, use highest intensity
|
||||
intensity_diff = [propagating_map_weather_intensity,destination_map_weather_intensity].max
|
||||
propagation_chance = (intensity_diff * BASE_CHANCE_OF_WEATHER_SPREAD)
|
||||
else
|
||||
intensity_diff = propagating_map_weather_intensity - destination_map_weather_intensity
|
||||
if intensity_diff > 0
|
||||
propagation_chance = (intensity_diff * BASE_CHANCE_OF_WEATHER_SPREAD)
|
||||
else
|
||||
return false# Other map's weather is stronger
|
||||
end
|
||||
end
|
||||
return rand(100) < propagation_chance
|
||||
end
|
||||
|
||||
def roll_for_weather_end(type, current_intensity)
|
||||
return false if !can_weather_end(type)
|
||||
chances = BASE_CHANCES_OF_WEATHER_END
|
||||
chances += (10 - current_intensity) * 5
|
||||
return rand(100) <= chances
|
||||
end
|
||||
|
||||
def roll_for_weather_move(type)
|
||||
return false if !can_weather_spread(type)
|
||||
return rand(100) <= BASE_CHANCES_OF_WEATHER_MOVE
|
||||
end
|
||||
|
||||
def roll_for_weather_increase(type)
|
||||
return false if !can_weather_decrease(type)
|
||||
return rand(100) <= CHANCES_OF_INTENSITY_INCREASE
|
||||
end
|
||||
|
||||
def roll_for_weather_decrease(type)
|
||||
return false if !can_weather_decrease(type)
|
||||
return rand(100) <= CHANCES_OF_INTENSITY_DECREASE
|
||||
end
|
||||
|
||||
def select_new_weather_spawn
|
||||
return [:None, 0] if rand(100) >= CHANCE_OF_NEW_WEATHER
|
||||
|
||||
base_intensity = rand(MAX_INTENSITY_ON_NEW_WEATHER) + 1
|
||||
|
||||
weights = []
|
||||
weights << [:Rain, CHANCE_OF_RAIN]
|
||||
weights << [:Sunny, CHANCE_OF_SUNNY]
|
||||
weights << [:Wind, CHANCE_OF_WINDY]
|
||||
weights << [:Fog, CHANCE_OF_FOG] if PBDayNight.isMorning?
|
||||
|
||||
total = weights.sum { |w| w[1] }
|
||||
roll = rand(total)
|
||||
|
||||
sum = 0
|
||||
weights.each do |type, chance|
|
||||
sum += chance
|
||||
if roll < sum
|
||||
intensity = (type == :Fog) ? base_intensity + 2 : base_intensity
|
||||
return [type, intensity]
|
||||
end
|
||||
end
|
||||
|
||||
return [:None, 0] # Fallback
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
27
Data/Scripts/053_PIF_Hoenn/HoennGameplayUtils.rb
Normal file
27
Data/Scripts/053_PIF_Hoenn/HoennGameplayUtils.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
# available channels
|
||||
# :NEWS
|
||||
# :WEATHER
|
||||
#
|
||||
def showTVText(channel = :NEWS)
|
||||
case channel
|
||||
when :NEWS
|
||||
pbMessage(getTVNewsCaption())
|
||||
end
|
||||
end
|
||||
|
||||
SWITCH_REPORTER_AT_PETALBURG = 2026
|
||||
|
||||
def getTVNewsCaption()
|
||||
if $game_switches[SWITCH_REPORTER_AT_PETALBURG]
|
||||
return _INTL("It's showing the local news. There's a berry-growing contest going on in Petalburg Town!")
|
||||
else
|
||||
return _INTL("It’s a rerun of PokéChef Deluxe. Nothing important on the news right now.")
|
||||
end
|
||||
end
|
||||
|
||||
def hoennSelectStarter
|
||||
starters = [obtainStarter(0), obtainStarter(1), obtainStarter(2)]
|
||||
selected_starter = StartersSelectionScene.new(starters).startScene
|
||||
pbAddPokemonSilent(selected_starter)
|
||||
return selected_starter
|
||||
end
|
||||
248
Data/Scripts/053_PIF_Hoenn/Hoenn_Rival.rb
Normal file
248
Data/Scripts/053_PIF_Hoenn/Hoenn_Rival.rb
Normal file
@@ -0,0 +1,248 @@
|
||||
# frozen_string_literal: true
|
||||
HOENN_RIVAL_EVENT_NAME = "HOENN_RIVAL"
|
||||
TEMPLATE_CHARACTER_FILE = "NPC_template"
|
||||
|
||||
class Player < Trainer
|
||||
attr_accessor :rival_appearance
|
||||
|
||||
alias pokemonEssentials_player_initialize initialize
|
||||
def initialize(*args)
|
||||
pokemonEssentials_player_initialize(*args)
|
||||
@rival_appearance = init_rival_appearance
|
||||
end
|
||||
|
||||
|
||||
|
||||
def init_rival_appearance
|
||||
if isPlayerMale
|
||||
return TrainerAppearance.new(5,
|
||||
HAT_MAY,
|
||||
CLOTHES_MAY,
|
||||
getFullHairId(HAIR_MAY,3) ,
|
||||
0, 0, 0)
|
||||
else
|
||||
return TrainerAppearance.new(5,
|
||||
HAT_BRENDAN,
|
||||
CLOTHES_BRENDAN,
|
||||
getFullHairId(HAIR_BRENDAN,3),
|
||||
0, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
def rival_appearance
|
||||
@rival_appearance = init_rival_appearance if !@rival_appearance
|
||||
return @rival_appearance
|
||||
end
|
||||
|
||||
def rival_appearance=(value)
|
||||
@rival_appearance = value
|
||||
end
|
||||
end
|
||||
|
||||
BATTLED_TRAINER_RIVAL_KEY = "rival"
|
||||
|
||||
def init_rival_name
|
||||
rival_name = "Brendan" if isPlayerFemale
|
||||
rival_name = "May" if isPlayerMale
|
||||
pbSet(VAR_RIVAL_NAME,rival_name)
|
||||
end
|
||||
def set_rival_hat(hat)
|
||||
$Trainer.rival_appearance = TrainerAppearance.new(
|
||||
$Trainer.rival_appearance.skin_color,
|
||||
hat,
|
||||
$Trainer.rival_appearance.clothes,
|
||||
$Trainer.rival_appearance.hair,
|
||||
$Trainer.rival_appearance.hair_color,
|
||||
$Trainer.rival_appearance.clothes_color,
|
||||
$Trainer.rival_appearance.hat_color,
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
class Sprite_Character
|
||||
alias PIF_typeExpert_checkModifySpriteGraphics checkModifySpriteGraphics
|
||||
def checkModifySpriteGraphics(character)
|
||||
PIF_typeExpert_checkModifySpriteGraphics(character)
|
||||
return if character == $game_player
|
||||
setSpriteToAppearance($Trainer.rival_appearance) if isPlayerFemale && character.name == HOENN_RIVAL_EVENT_NAME && character.character_name == TEMPLATE_CHARACTER_FILE
|
||||
setSpriteToAppearance($Trainer.rival_appearance) if isPlayerMale && character.name == HOENN_RIVAL_EVENT_NAME && character.character_name == TEMPLATE_CHARACTER_FILE
|
||||
end
|
||||
end
|
||||
|
||||
def get_rival_starter
|
||||
case get_rival_starter_type()
|
||||
when :GRASS
|
||||
return obtainStarter(0)
|
||||
when :FIRE
|
||||
return obtainStarter(1)
|
||||
when :WATER
|
||||
return obtainStarter(2)
|
||||
else
|
||||
#fallback, should not happen
|
||||
return obtainStarter(0)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def get_rival_starter_type()
|
||||
player_chosen_starter_index = pbGet(VAR_HOENN_CHOSEN_STARTER_INDEX)
|
||||
case player_chosen_starter_index
|
||||
when 0 #GRASS
|
||||
return :FIRE
|
||||
when 1 #FIRE
|
||||
return :WATER
|
||||
when 2 #WATER
|
||||
return :GRASS
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#Rival catches a Pokemon the same type as the player's starter and fuses it with their starter
|
||||
def updateRivalTeamForSecondBattle()
|
||||
rival_trainer = $PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY]
|
||||
rival_starter = rival_trainer.currentTeam[0]
|
||||
rival_starter_species= rival_starter.species
|
||||
|
||||
player_chosen_starter_index = pbGet(VAR_HOENN_CHOSEN_STARTER_INDEX)
|
||||
case player_chosen_starter_index
|
||||
when 0 #GRASS
|
||||
pokemon_species = getFusionSpeciesSymbol(:LOTAD, rival_starter_species) if isPlayerFemale()
|
||||
pokemon_species = getFusionSpeciesSymbol(rival_starter_species,:SHROOMISH) if isPlayerMale()
|
||||
when 1 #FIRE
|
||||
pokemon_species = getFusionSpeciesSymbol(:SLUGMA,rival_starter_species) if isPlayerFemale()
|
||||
pokemon_species = getFusionSpeciesSymbol(rival_starter_species,:NUMEL) if isPlayerMale()
|
||||
when 2 #WATER
|
||||
pokemon_species = getFusionSpeciesSymbol(rival_starter_species,:WINGULL) if isPlayerFemale()
|
||||
pokemon_species = getFusionSpeciesSymbol(:WAILMER,rival_starter_species) if isPlayerMale()
|
||||
end
|
||||
team = []
|
||||
team << Pokemon.new(pokemon_species,15)
|
||||
|
||||
rival_trainer.currentTeam = team
|
||||
$PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY] = rival_trainer
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
# This sets up the rival's main team for the game
|
||||
# Fir further battle, we can just add Pokemon and gain exp the same way as other
|
||||
# trainer rematches
|
||||
#
|
||||
# Basically, rival catches a pokemon the type of their rival's starter - fuses it with their starters
|
||||
# Has a team composed of fire/grass, water/grass, water/fire pokemon
|
||||
def updateRivalTeamForThirdBattle()
|
||||
rival_trainer = $PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY]
|
||||
rival_starter = rival_trainer.currentTeam[0]
|
||||
starter_species= rival_starter.species
|
||||
|
||||
rival_starter.level=20
|
||||
team = []
|
||||
team << rival_starter
|
||||
rival_trainer.currentTeam = team
|
||||
$PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY] = rival_trainer
|
||||
evolveRivalTeam
|
||||
|
||||
evolution_species = rival_starter.check_evolution_on_level_up(false)
|
||||
if evolution_species
|
||||
starter_species = evolution_species
|
||||
end
|
||||
|
||||
player_chosen_starter_index = pbGet(VAR_HOENN_CHOSEN_STARTER_INDEX)
|
||||
case player_chosen_starter_index
|
||||
when 0 #GRASS
|
||||
if isPlayerFemale()
|
||||
fire_grass_pokemon = starter_species
|
||||
water_fire_pokemon = getFusionSpeciesSymbol(:NUMEL,:WINGULL)
|
||||
water_grass_pokemon = getFusionSpeciesSymbol(:WAILMER,:SHROOMISH)
|
||||
end
|
||||
if isPlayerMale()
|
||||
fire_grass_pokemon = starter_species
|
||||
water_fire_pokemon = getFusionSpeciesSymbol(:LOMBRE,:WINGULL)
|
||||
water_grass_pokemon = getFusionSpeciesSymbol(:SLUGMA,:WAILMER)
|
||||
end
|
||||
contains_starter = [fire_grass_pokemon]
|
||||
other_pokemon = [water_fire_pokemon,water_grass_pokemon]
|
||||
|
||||
when 1 #FIRE
|
||||
if isPlayerFemale()
|
||||
fire_grass_pokemon = getFusionSpeciesSymbol(:SHROOMISH,:NUMEL)
|
||||
water_fire_pokemon = getFusionSpeciesSymbol(:LOMBRE,:WAILMER)
|
||||
water_grass_pokemon = starter_species
|
||||
end
|
||||
if isPlayerMale()
|
||||
fire_grass_pokemon = getFusionSpeciesSymbol(:LOMBRE,:SLUGMA,)
|
||||
water_fire_pokemon = getFusionSpeciesSymbol(:SHROOMISH,:WINGULL,)
|
||||
water_grass_pokemon = starter_species
|
||||
end
|
||||
contains_starter = [water_grass_pokemon]
|
||||
other_pokemon = [water_fire_pokemon,fire_grass_pokemon]
|
||||
|
||||
when 2 #WATER
|
||||
if isPlayerFemale()
|
||||
fire_grass_pokemon = getFusionSpeciesSymbol(:SLUGMA,:SHROOMISH)
|
||||
water_fire_pokemon = starter_species
|
||||
water_grass_pokemon = getFusionSpeciesSymbol(:WAILMER,:NUMEL)
|
||||
end
|
||||
if isPlayerMale()
|
||||
fire_grass_pokemon = getFusionSpeciesSymbol(:LOMBRE,:NUMEL,)
|
||||
water_fire_pokemon = starter_species
|
||||
water_grass_pokemon = getFusionSpeciesSymbol(:SLUGMA,:WINGULL)
|
||||
end
|
||||
contains_starter = [water_fire_pokemon]
|
||||
other_pokemon = [water_grass_pokemon,fire_grass_pokemon]
|
||||
end
|
||||
|
||||
team = []
|
||||
team << Pokemon.new(other_pokemon[0],18)
|
||||
team << Pokemon.new(other_pokemon[1],18)
|
||||
team << Pokemon.new(contains_starter[0],20)
|
||||
|
||||
rival_trainer.currentTeam = team
|
||||
$PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY] = rival_trainer
|
||||
end
|
||||
|
||||
def levelUpRivalTeam(experience=0)
|
||||
rival_trainer = $PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY]
|
||||
updated_trainer =makeRebattledTrainerTeamGainExp(rival_trainer,false,experience)
|
||||
$PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY] = updated_trainer
|
||||
end
|
||||
|
||||
def evolveRivalTeam()
|
||||
rival_trainer = $PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY]
|
||||
updated_trainer = evolveRebattledTrainerPokemon(rival_trainer)
|
||||
$PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY] = updated_trainer
|
||||
end
|
||||
|
||||
def addPokemonToRivalTeam(species,level)
|
||||
rival_trainer = $PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY]
|
||||
rival_trainer.currentTeam << Pokemon.new(species,level)
|
||||
$PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY] = rival_trainer
|
||||
end
|
||||
|
||||
def initializeRivalBattledTrainer
|
||||
trainer_type = :RIVAL1
|
||||
trainer_name = isPlayerMale ? "May" : "Brendan"
|
||||
trainer_appearance = $Trainer.rival_appearance
|
||||
rivalBattledTrainer = BattledTrainer.new(trainer_type,trainer_name,0)
|
||||
rivalBattledTrainer.set_custom_appearance(trainer_appearance)
|
||||
echoln rivalBattledTrainer.currentTeam
|
||||
team = []
|
||||
team<<Pokemon.new(get_rival_starter,5)
|
||||
rivalBattledTrainer.currentTeam =team
|
||||
return rivalBattledTrainer
|
||||
end
|
||||
|
||||
def hoennRivalBattle(loseDialog="...")
|
||||
$PokemonGlobal.battledTrainers = {} if !$PokemonGlobal.battledTrainers
|
||||
if !$PokemonGlobal.battledTrainers.has_key?(BATTLED_TRAINER_RIVAL_KEY)
|
||||
rival_trainer = initializeRivalBattledTrainer()
|
||||
$PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY] = rival_trainer
|
||||
else
|
||||
rival_trainer = $PokemonGlobal.battledTrainers[BATTLED_TRAINER_RIVAL_KEY]
|
||||
end
|
||||
echoln rival_trainer
|
||||
echoln rival_trainer.currentTeam
|
||||
return customTrainerBattle(rival_trainer.trainerName,rival_trainer.trainerType, rival_trainer.currentTeam,rival_trainer,loseDialog,nil,rival_trainer.custom_appearance)
|
||||
end
|
||||
15
Data/Scripts/053_PIF_Hoenn/OverworldPokemon.rb
Normal file
15
Data/Scripts/053_PIF_Hoenn/OverworldPokemon.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
def player_near_event?(map_id, event_id, radius)
|
||||
return false if map_id != $game_map.map_id
|
||||
event = $game_map.events[event_id]
|
||||
return false if event.nil?
|
||||
dx = $game_player.x - event.x
|
||||
dy = $game_player.y - event.y
|
||||
distance = Math.sqrt(dx * dx + dy * dy)
|
||||
return distance <= radius
|
||||
end
|
||||
|
||||
def checkOverworldPokemonFlee(radius=4)
|
||||
event = $game_map.event[@event_id]
|
||||
return player_near_event?($game_map.map_id, event.id, radius)
|
||||
end
|
||||
137
Data/Scripts/053_PIF_Hoenn/PokemartMapTransfers.rb
Normal file
137
Data/Scripts/053_PIF_Hoenn/PokemartMapTransfers.rb
Normal file
@@ -0,0 +1,137 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
|
||||
CITIES_MAP_IDS = {
|
||||
:LITTLEROOT => 9,
|
||||
:OLDALE => 8,
|
||||
:PETALBURG =>7,
|
||||
:RUSTBORO => 47,
|
||||
:DEWFORD => 0,
|
||||
:SLATEPORT => 0,
|
||||
:MAUVILLE => 0,
|
||||
:VERDANTURF => 0,
|
||||
:FALLARBOR => 0,
|
||||
:LAVARIDGE => 0,
|
||||
:FORTREE => 0,
|
||||
:LILYCOVE => 0,
|
||||
:MOSSDEEP => 0,
|
||||
:SOOTOPOLIS => 0,
|
||||
:PACIFIDLOG => 0,
|
||||
:EVERGRANDE => 0,
|
||||
:BATTLEFRONTIER => 0,
|
||||
|
||||
}
|
||||
|
||||
|
||||
# Necessary dor setting the various events within the pokemart map, uses the numbers as wondertrade
|
||||
def get_city_numerical_id_hoenn(city_sym)
|
||||
current_city_numerical = {
|
||||
:LITTLEROOT => 1,
|
||||
:OLDALE => 2,
|
||||
:PETALBURG => 3,
|
||||
:RUSTBORO => 4,
|
||||
:DEWFORD => 5,
|
||||
:SLATEPORT => 6,
|
||||
:MAUVILLE => 7,
|
||||
:VERDANTURF => 8,
|
||||
:FALLARBOR => 9,
|
||||
:LAVARIDGE => 10,
|
||||
:FORTREE => 11,
|
||||
:LILYCOVE => 12,
|
||||
:MOSSDEEP => 13,
|
||||
:SOOTOPOLIS => 14,
|
||||
:PACIFIDLOG => 15,
|
||||
:EVERGRANDE => 16
|
||||
}
|
||||
return current_city_numerical[city_sym]
|
||||
end
|
||||
|
||||
if Settings::GAME_ID == :IF_HOENN
|
||||
POKEMART_MAP_ID = 24
|
||||
POKEMART_DOOR_POS = [12, 12]
|
||||
end
|
||||
|
||||
# city -> Symbol
|
||||
# def enter_pokemart(city)
|
||||
# pbSet(VAR_CURRENT_MART, city)
|
||||
# pbSet(VAR_CURRENT_CITY_NUMERICAL_ID, get_city_numerical_id(city))
|
||||
# echoln get_city_numerical_id(city)
|
||||
# pbFadeOutIn {
|
||||
# $game_temp.player_new_map_id = POKEMART_MAP_ID
|
||||
# $game_temp.player_new_x = POKEMART_DOOR_POS[0]
|
||||
# $game_temp.player_new_y = POKEMART_DOOR_POS[1]
|
||||
# $scene.transfer_player(true)
|
||||
# $game_map.autoplay
|
||||
# $game_map.refresh
|
||||
# }
|
||||
# end
|
||||
|
||||
|
||||
HOENN_POKEMART_ENTRANCES = {
|
||||
:LITTLEROOT => [1, 0, 0],
|
||||
:OLDALE => [1, 0, 0],
|
||||
:VERMILLION => [1, 0, 0],
|
||||
:PETALBURG => [7, 32, 19],
|
||||
:RUSTBORO => [1, 0, 0],
|
||||
:DEWFORD => [1, 0, 0],
|
||||
:SLATEPORT => [1, 0, 0],
|
||||
:MAUVILLE => [1, 0, 0],
|
||||
:VERDANTURF => [1, 0, 0],
|
||||
:FALLARBOR => [1, 0, 0],
|
||||
:LAVARIDGE => [1, 0, 0],
|
||||
:FORTREE => [1, 0, 0],
|
||||
:LILYCOVE => [1, 0, 0],
|
||||
:MOSSDEEP => [1, 0, 0],
|
||||
:SOOTOPOLIS => [1, 0, 0],
|
||||
:PACIFIDLOG => [1, 0, 0],
|
||||
:EVERGRANDE => [1, 0, 0],
|
||||
}
|
||||
def exit_pokemart_hoenn()
|
||||
|
||||
current_city = pbGet(VAR_CURRENT_MART)
|
||||
current_city = :PETALBURG if !current_city.is_a?(Symbol)
|
||||
|
||||
entrance_map = HOENN_POKEMART_ENTRANCES[current_city][0]
|
||||
entrance_x = HOENN_POKEMART_ENTRANCES[current_city][1]
|
||||
entrance_y = HOENN_POKEMART_ENTRANCES[current_city][2]
|
||||
|
||||
pbSet(VAR_CURRENT_CITY_NUMERICAL_ID, 0)
|
||||
pbSet(VAR_CURRENT_MART, 0)
|
||||
pbFadeOutIn {
|
||||
$game_temp.player_new_map_id = entrance_map
|
||||
$game_temp.player_new_x = entrance_x
|
||||
$game_temp.player_new_y = entrance_y
|
||||
$scene.transfer_player(true)
|
||||
$game_map.autoplay
|
||||
$game_map.refresh
|
||||
}
|
||||
end
|
||||
|
||||
def get_mart_exclusive_items_hoenn(city)
|
||||
items_list = []
|
||||
return items_list
|
||||
end
|
||||
|
||||
def exit_pokemon_center()
|
||||
if $PokemonGlobal.pokecenterMapId && $PokemonGlobal.pokecenterMapId>=0
|
||||
pbCancelVehicles
|
||||
pbRemoveDependencies
|
||||
$game_temp.player_new_map_id = $PokemonGlobal.pokecenterMapId
|
||||
$game_temp.player_new_x = $PokemonGlobal.pokecenterX
|
||||
$game_temp.player_new_y = $PokemonGlobal.pokecenterY
|
||||
$scene.transfer_player if $scene.is_a?(Scene_Map)
|
||||
$game_map.refresh
|
||||
else#Home
|
||||
$game_temp.player_new_map_id = 9
|
||||
$game_temp.player_new_x = 16
|
||||
$game_temp.player_new_y = 23
|
||||
$scene.transfer_player if $scene.is_a?(Scene_Map)
|
||||
$game_map.refresh
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def inCity?(city)
|
||||
city_map_id = CITIES_MAP_IDS[city]
|
||||
return $PokemonGlobal.pokecenterMapId ==city_map_id
|
||||
end
|
||||
160
Data/Scripts/053_PIF_Hoenn/SurfingSplashes.rb
Normal file
160
Data/Scripts/053_PIF_Hoenn/SurfingSplashes.rb
Normal file
@@ -0,0 +1,160 @@
|
||||
# frozen_string_literal: true
|
||||
SURF_SPLASH_ANIMATION_ID = 30
|
||||
|
||||
class Game_Temp
|
||||
attr_accessor :surf_patches
|
||||
|
||||
def initializeSurfPatches
|
||||
@surf_patches = []
|
||||
end
|
||||
|
||||
def clearSurfSplashPatches
|
||||
return unless $game_temp.surf_patches
|
||||
$game_temp.surf_patches.clear
|
||||
end
|
||||
end
|
||||
|
||||
class Spriteset_Map
|
||||
alias surf_patch_update update
|
||||
def update
|
||||
surf_patch_update
|
||||
return unless $scene.is_a?(Scene_Map)
|
||||
return unless Settings::GAME_ID == :IF_HOENN
|
||||
return unless $PokemonGlobal.surfing
|
||||
return if Graphics.frame_count % 32 != 0
|
||||
animate_surf_water_splashes
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class SurfPatch
|
||||
MAX_NUMBER_SURF_SPLASHES = 6
|
||||
|
||||
attr_accessor :shape #Array of tiles coordinates (ex: [[10,20],[1,5]])
|
||||
|
||||
def initialize(patch_size)
|
||||
x, y = getRandomPositionOnPerimeter(8, 6, $game_player.x, $game_player.y, 2)
|
||||
variance = rand(5..8)
|
||||
@shape =getRandomSplashPatch(patch_size,x,y,variance)
|
||||
end
|
||||
|
||||
def getRandomSplashPatch(tile_count, center_x, center_y, variance = rand(4))
|
||||
return [] if tile_count <= 0
|
||||
|
||||
center_pos = getRandomPositionOnPerimeter(tile_count, tile_count, center_x, center_y, variance)
|
||||
area = [center_pos]
|
||||
visited = { center_pos => true }
|
||||
queue = [center_pos]
|
||||
|
||||
directions = [[1, 0], [-1, 0], [0, 1], [0, -1],
|
||||
[1, 1], [-1, -1], [1, -1], [-1, 1]] # 8 directions
|
||||
|
||||
while area.length < tile_count && !queue.empty?
|
||||
current = queue.sample
|
||||
queue.delete(current)
|
||||
cx, cy = current
|
||||
|
||||
# Randomize how many directions to try (1 to 4)
|
||||
directions.shuffle.take(rand(1..4)).each do |dx, dy|
|
||||
nx, ny = cx + dx, cy + dy
|
||||
new_pos = [nx, ny]
|
||||
next if visited[new_pos]
|
||||
|
||||
visited[new_pos] = true
|
||||
area << new_pos
|
||||
queue << new_pos
|
||||
|
||||
break if area.length >= tile_count
|
||||
end
|
||||
end
|
||||
|
||||
# Filter to keep only water tiles
|
||||
map_id = $game_map.map_id
|
||||
area.select! do |pos|
|
||||
x, y = pos
|
||||
terrain = $MapFactory.getTerrainTag(map_id, x, y, false)
|
||||
next false unless terrain&.can_surf # Only water/surfable tiles
|
||||
$game_map.playerPassable?(x, y, 2) # Direction 2 (down) or any direction for checking passability
|
||||
end
|
||||
return area
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
def animate_surf_water_splashes
|
||||
animation_frequency = 16 #in frames
|
||||
return unless $game_temp.surf_patches
|
||||
return unless Graphics.frame_count % animation_frequency == 0
|
||||
$game_temp.surf_patches.each do |patch|
|
||||
next if patch.nil? || patch.shape.empty?
|
||||
patch.shape.each do |splash_tile|
|
||||
x_position= splash_tile[0]
|
||||
y_position = splash_tile[1]
|
||||
$scene.spriteset.addUserAnimation(SURF_SPLASH_ANIMATION_ID, x_position, y_position, true, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def try_spawn_surf_water_splashes
|
||||
water_splash_chance = 0.1 #Chance each step 10%
|
||||
steps_interval = 5 # Only check once every 5 steps
|
||||
return if $PokemonGlobal.stepcount % steps_interval != 0
|
||||
return unless rand < water_splash_chance
|
||||
spawnSurfSplashPatch
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
Events.onStepTaken += proc { |sender, e|
|
||||
water_encounter_chance = 25
|
||||
|
||||
next unless $scene.is_a?(Scene_Map)
|
||||
next unless Settings::GAME_ID == :IF_HOENN
|
||||
next unless $PokemonGlobal.surfing
|
||||
|
||||
player_x = $game_player.x
|
||||
player_y = $game_player.y
|
||||
if $game_temp.surf_patches
|
||||
$game_temp.surf_patches.each_with_index do |patch,index|
|
||||
next unless patch && patch.shape
|
||||
if patch.shape.include?([player_x, player_y])
|
||||
next if rand(100) > water_encounter_chance
|
||||
$game_temp.surf_patches.delete_at(index)
|
||||
echoln "surf patch encounter!"
|
||||
wild_pokemon = $PokemonEncounters.choose_wild_pokemon(:Water)
|
||||
species = wild_pokemon[0]
|
||||
level = wild_pokemon[1]
|
||||
pbWildBattle(species, level)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
try_spawn_surf_water_splashes
|
||||
}
|
||||
|
||||
|
||||
|
||||
def spawnSurfSplashPatch
|
||||
$game_temp.initializeSurfPatches unless $game_temp.surf_patches
|
||||
|
||||
patch_size = [3,4,5,6].sample
|
||||
splash_patch = SurfPatch.new(patch_size)
|
||||
$game_temp.surf_patches << splash_patch
|
||||
$game_temp.surf_patches.shift if $game_temp.surf_patches.length >= SurfPatch::MAX_NUMBER_SURF_SPLASHES
|
||||
echoln $game_temp.surf_patches
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
|
||||
#eventType
|
||||
# :EVOLVE
|
||||
# :FUSE
|
||||
# :UNFUSE
|
||||
# :REVERSE
|
||||
# :CAUGHT
|
||||
class BattledTrainerRandomEvent
|
||||
attr_accessor :eventType
|
||||
attr_accessor :caught_pokemon #species_sym
|
||||
|
||||
attr_accessor :unevolved_pokemon #species_sym
|
||||
attr_accessor :evolved_pokemon #species_sym
|
||||
|
||||
attr_accessor :fusion_head_pokemon #species_sym
|
||||
attr_accessor :fusion_body_pokemon #species_sym
|
||||
attr_accessor :fusion_fused_pokemon #species_sym
|
||||
|
||||
|
||||
attr_accessor :unreversed_pokemon #species_sym
|
||||
attr_accessor :reversed_pokemon #species_sym
|
||||
|
||||
|
||||
attr_accessor :unfused_pokemon #species_sym
|
||||
|
||||
|
||||
|
||||
def initialize(eventType)
|
||||
@eventType = eventType
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,217 @@
|
||||
class BattledTrainer
|
||||
DELAY_BETWEEN_NPC_TRADES = 180 #In seconds (3 minutes)
|
||||
MAX_FRIENDSHIP = 100
|
||||
|
||||
attr_accessor :trainerType
|
||||
attr_accessor :trainerName
|
||||
|
||||
attr_accessor :currentTeam #list of Pokemon. The game selects in this list for trade offers. They can increase levels & involve as you rebattle them.
|
||||
|
||||
#trainers will randomly find items and add them to this list. When they have the :ITEM status, they will
|
||||
# give one of them at random.
|
||||
#Items equipped to the Pokemon traded by the player will end up in that list.
|
||||
#
|
||||
# If there is an evolution that the trainer can use on one of their Pokemon in that list, they will
|
||||
# instead use it to evolve their Pokemon.
|
||||
#
|
||||
#DNA Splicers/reversers can be used on their Pokemon if they have at least 2 unfused/1 fused
|
||||
#
|
||||
#Healing items that are in that list can be used by the trainer in rematches
|
||||
#
|
||||
attr_accessor :foundItems
|
||||
|
||||
|
||||
attr_accessor :nb_rematches
|
||||
|
||||
#What the trainer currently wants to do
|
||||
# :IDLE -> Nothing. Normal postbattle dialogue
|
||||
# Should prompt the player to register the trainer in their phone.
|
||||
# Or maybe done automatically at the end of the battle?
|
||||
|
||||
# :TRADE -> Trainer wants to trade one of its Pokémon with the player
|
||||
|
||||
# :BATTLE -> Trainer wants to rebattle the player
|
||||
|
||||
# :ITEM -> Trainer has an item they want to give the player
|
||||
attr_accessor :current_status
|
||||
attr_accessor :previous_status
|
||||
attr_accessor :previous_trade_timestamp
|
||||
|
||||
attr_accessor :favorite_type
|
||||
attr_accessor :favorite_pokemon #Used for generating trade offers. Should be set from trainer.txt (todo)
|
||||
#If empty, then trade offers ask for a Pokemon of a type depending on the trainer's class
|
||||
|
||||
attr_accessor :previous_random_events
|
||||
attr_accessor :has_pending_action
|
||||
attr_accessor :custom_appearance
|
||||
|
||||
attr_accessor :friendship #increases the more you interact with them, unlocks more interact options
|
||||
attr_accessor :friendship_level
|
||||
def initialize(trainerType,trainerName,trainerVersion)
|
||||
@trainerType = trainerType
|
||||
@trainerName = trainerName
|
||||
@currentTeam = loadOriginalTrainerTeam(trainerVersion)
|
||||
@foundItems = []
|
||||
@nb_rematches = 0
|
||||
@currentStatus = :IDLE
|
||||
@previous_status = :IDLE
|
||||
@previous_trade_timestamp = Time.now-DELAY_BETWEEN_NPC_TRADES
|
||||
@previous_random_events =[]
|
||||
@has_pending_action=false
|
||||
@favorite_type = pick_favorite_type(trainerType)
|
||||
@friendship = 0
|
||||
@friendship_level = 0
|
||||
end
|
||||
|
||||
def friendship_level
|
||||
@friendship_level =0 if !@friendship_level
|
||||
return @friendship_level
|
||||
end
|
||||
def increase_friendship(amount)
|
||||
@friendship=0 if !@friendship
|
||||
@friendship_level=0 if !@friendship_level
|
||||
gain = amount / ((@friendship + 1) ** 0.4)
|
||||
@friendship += gain
|
||||
@friendship = MAX_FRIENDSHIP if @friendship > MAX_FRIENDSHIP
|
||||
|
||||
echoln "Friendship with #{@trainerName} increased by #{gain.round(2)} (total: #{@friendship.round(2)})"
|
||||
|
||||
thresholds = FRIENDSHIP_LEVELS[@trainerType] || []
|
||||
echoln thresholds
|
||||
|
||||
while @friendship_level < thresholds.length && @friendship >= thresholds[@friendship_level]
|
||||
@friendship_level += 1
|
||||
|
||||
trainerClassName = GameData::TrainerType.get(@trainerType).real_name
|
||||
pbMessage(_INTL("\\C[3]Friendship increased with #{trainerClassName} #{@trainerName}!"))
|
||||
case @friendship_level
|
||||
when 1
|
||||
pbMessage(_INTL("You can now trade with each other!"))
|
||||
when 2
|
||||
pbMessage(_INTL("They will now give you items from time to time!"))
|
||||
when 3
|
||||
pbMessage(_INTL("You can now partner up with them!"))
|
||||
end
|
||||
|
||||
echoln "🎉 #{@trainerName}'s friendship level increased to #{@friendship_level}!"
|
||||
end
|
||||
end
|
||||
|
||||
def set_custom_appearance(trainer_appearance)
|
||||
@custom_appearance = trainer_appearance
|
||||
end
|
||||
|
||||
def pick_favorite_type(trainer_type)
|
||||
if TRAINER_CLASS_FAVORITE_TYPES.has_key?(trainer_type)
|
||||
return TRAINER_CLASS_FAVORITE_TYPES[trainer_type].sample
|
||||
else
|
||||
return :NORMAL
|
||||
end
|
||||
end
|
||||
|
||||
def set_pending_action(value)
|
||||
@has_pending_action=value
|
||||
end
|
||||
|
||||
def log_evolution_event(unevolved_pokemon_species, evolved_pokemon_species)
|
||||
echoln "NPC Trainer #{@trainerName} evolved their #{get_species_readable_internal_name(unevolved_pokemon_species)} to #{get_species_readable_internal_name(evolved_pokemon_species)}!"
|
||||
|
||||
event = BattledTrainerRandomEvent.new(:EVOLVE)
|
||||
event.unevolved_pokemon = unevolved_pokemon_species
|
||||
event.evolved_pokemon = evolved_pokemon_species
|
||||
@previous_random_events = [] unless @previous_random_events
|
||||
@previous_random_events << event
|
||||
end
|
||||
|
||||
def log_fusion_event(body_pokemon_species, head_pokemon_species, fused_pokemon_species)
|
||||
echoln "NPC trainer #{@trainerName} fused #{body_pokemon_species} and #{head_pokemon_species}!"
|
||||
event = BattledTrainerRandomEvent.new(:FUSE)
|
||||
event.fusion_body_pokemon =body_pokemon_species
|
||||
event.fusion_head_pokemon =head_pokemon_species
|
||||
event.fusion_fused_pokemon =fused_pokemon_species
|
||||
@previous_random_events = [] unless @previous_random_events
|
||||
@previous_random_events << event
|
||||
end
|
||||
|
||||
def log_unfusion_event(original_fused_pokemon_species, unfused_body_species, unfused_body_head)
|
||||
echoln "NPC trainer #{@trainerName} unfused #{get_species_readable_internal_name(original_fused_pokemon_species)}!"
|
||||
event = BattledTrainerRandomEvent.new(:UNFUSE)
|
||||
event.unfused_pokemon = original_fused_pokemon_species
|
||||
event.fusion_body_pokemon = unfused_body_species
|
||||
event.fusion_head_pokemon = unfused_body_head
|
||||
@previous_random_events = [] unless @previous_random_events
|
||||
@previous_random_events << event
|
||||
end
|
||||
|
||||
def log_reverse_event(original_fused_pokemon_species, reversed_fusion_species)
|
||||
echoln "NPC trainer #{@trainerName} reversed #{get_species_readable_internal_name(original_fused_pokemon_species)}!"
|
||||
|
||||
event = BattledTrainerRandomEvent.new(:REVERSE)
|
||||
event.unreversed_pokemon = original_fused_pokemon_species
|
||||
event.reversed_pokemon = reversed_fusion_species
|
||||
@previous_random_events = [] unless @previous_random_events
|
||||
@previous_random_events << event
|
||||
end
|
||||
|
||||
def log_catch_event(new_pokemon_species)
|
||||
echoln "NPC Trainer #{@trainerName} caught a #{new_pokemon_species}!"
|
||||
event = BattledTrainerRandomEvent.new(:CATCH)
|
||||
event.caught_pokemon = new_pokemon_species
|
||||
@previous_random_events = [] unless @previous_random_events
|
||||
@previous_random_events << event
|
||||
end
|
||||
|
||||
def clear_previous_random_events()
|
||||
@previous_random_events = []
|
||||
end
|
||||
|
||||
def loadOriginalTrainer(trainerVersion=0)
|
||||
return pbLoadTrainer(@trainerType,@trainerName,trainerVersion)
|
||||
end
|
||||
|
||||
def loadOriginalTrainerTeam(trainerVersion=0)
|
||||
original_trainer = pbLoadTrainer(@trainerType,@trainerName,trainerVersion)
|
||||
return if !original_trainer
|
||||
echoln "Loading Trainer #{@trainerType}"
|
||||
current_party = []
|
||||
original_trainer.party.each do |partyMember|
|
||||
echoln "PartyMember: #{partyMember}"
|
||||
if partyMember.is_a?(Pokemon)
|
||||
current_party << partyMember
|
||||
elsif partyMember.is_a?(Array) #normally always gonna be this
|
||||
pokemon_species = partyMember[0]
|
||||
pokemon_level = partyMember[1]
|
||||
current_party << Pokemon.new(pokemon_species,pokemon_level)
|
||||
else
|
||||
echoln "Could not add Pokemon #{partyMember} to rematchable trainer's party."
|
||||
end
|
||||
end
|
||||
|
||||
return current_party
|
||||
end
|
||||
|
||||
def getTimeSinceLastTrade()
|
||||
@previous_trade_timestamp ||= Time.now - DELAY_BETWEEN_NPC_TRADES
|
||||
return Time.now - @previous_trade_timestamp
|
||||
end
|
||||
|
||||
def isNextTradeReady?()
|
||||
return getTimeSinceLastTrade < DELAY_BETWEEN_NPC_TRADES
|
||||
end
|
||||
|
||||
def list_team_unfused_pokemon
|
||||
list = []
|
||||
@currentTeam.each do |pokemon|
|
||||
list << pokemon if !pokemon.isFusion?
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
def list_team_fused_pokemon
|
||||
list = []
|
||||
@currentTeam.each do |pokemon|
|
||||
list << pokemon if pokemon.isFusion?
|
||||
end
|
||||
return list
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,70 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class PokemonGlobalMetadata
|
||||
#Map that keeps track of all the npc trainers the player has battled
|
||||
# [map_id,event_id] =>BattledTrainer
|
||||
attr_accessor :battledTrainers
|
||||
end
|
||||
|
||||
TIME_FOR_RANDOM_EVENTS = 60#3600 #1 hour
|
||||
|
||||
|
||||
## Extend pbTrainerBattle to call postTrainerBattleAction at the end of every trainer battle
|
||||
alias original_pbTrainerBattle pbTrainerBattle
|
||||
def pbTrainerBattle(trainerID, trainerName,endSpeech=nil,
|
||||
doubleBattle=false, trainerPartyID=0,
|
||||
*args)
|
||||
result = original_pbTrainerBattle(trainerID, trainerName, endSpeech,doubleBattle,trainerPartyID, *args)
|
||||
postTrainerBattleActions(trainerID, trainerName,trainerPartyID) if Settings::GAME_ID == :IF_HOENN
|
||||
return result
|
||||
end
|
||||
def postTrainerBattleActions(trainerID, trainerName,trainerVersion)
|
||||
trainer = registerBattledTrainer(@event_id,$game_map.map_id,trainerID,trainerName,trainerVersion)
|
||||
makeRebattledTrainerTeamGainExp(trainer)
|
||||
end
|
||||
|
||||
|
||||
#Do NOT call this alone. Rebattlable trainers are always intialized after
|
||||
# defeating them.
|
||||
# Having a rematchable trainer that is not registered will cause crashes.
|
||||
def registerBattledTrainer(event_id, mapId, trainerType, trainerName, trainerVersion=0)
|
||||
key = [event_id,mapId]
|
||||
$PokemonGlobal.battledTrainers = {} unless $PokemonGlobal.battledTrainers
|
||||
trainer = BattledTrainer.new(trainerType, trainerName, trainerVersion)
|
||||
$PokemonGlobal.battledTrainers[key] = trainer
|
||||
return trainer
|
||||
end
|
||||
|
||||
def unregisterBattledTrainer(event_id, mapId)
|
||||
key = [event_id,mapId]
|
||||
$PokemonGlobal.battledTrainers = {} unless $PokemonGlobal.battledTrainers
|
||||
if $PokemonGlobal.battledTrainers.has_key?(key)
|
||||
$PokemonGlobal.battledTrainers[key] =nil
|
||||
echoln "Unregistered Battled Trainer #{key}"
|
||||
else
|
||||
echoln "Could not unregister Battled Trainer #{key}"
|
||||
end
|
||||
end
|
||||
|
||||
def resetTrainerRebattle(event_id, map_id)
|
||||
trainer = getRebattledTrainer(event_id,map_id)
|
||||
|
||||
trainerType = trainer.trainerType
|
||||
trainerName = trainer.trainerName
|
||||
|
||||
unregisterBattledTrainer(event_id,map_id)
|
||||
registerBattledTrainer(event_id,map_id,trainerType,trainerName)
|
||||
end
|
||||
|
||||
def updateRebattledTrainer(event_id,map_id,updated_trainer)
|
||||
key = [event_id,map_id]
|
||||
$PokemonGlobal.battledTrainers = {} if !$PokemonGlobal.battledTrainers
|
||||
$PokemonGlobal.battledTrainers[key] = updated_trainer
|
||||
end
|
||||
|
||||
def getRebattledTrainer(event_id,map_id)
|
||||
key = [event_id,map_id]
|
||||
$PokemonGlobal.battledTrainers = {} if !$PokemonGlobal.battledTrainers
|
||||
return $PokemonGlobal.battledTrainers[key]
|
||||
end
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# After each rematch, all of the trainer's Pokémon gain EXP
|
||||
#
|
||||
# Gained Exp is calculated from the Pokemon that is in the first slot in the player's team
|
||||
# so the trainer's levels will scale with the player's.
|
||||
#
|
||||
# e.g. If the player uses a stronger Pokemon in the battle, the NPC will get more experience
|
||||
# as a result
|
||||
#
|
||||
def makeRebattledTrainerTeamGainExp(trainer, playerWon=true, gained_exp=nil)
|
||||
return if !trainer
|
||||
updated_team = []
|
||||
|
||||
trainer_pokemon = $Trainer.party[0]
|
||||
return if !trainer_pokemon
|
||||
for pokemon in trainer.currentTeam
|
||||
if !gained_exp #Set depending on first pokemon in party if not given a specific amount
|
||||
gained_exp = trainer_pokemon.level * trainer_pokemon.base_exp
|
||||
gained_exp /= 2 if playerWon #trainer lost so he's not getting full exp
|
||||
gained_exp /= trainer.currentTeam.length
|
||||
end
|
||||
growth_rate = pokemon.growth_rate
|
||||
new_exp = growth_rate.add_exp(pokemon.exp, gained_exp)
|
||||
pokemon.exp = new_exp
|
||||
updated_team.push(pokemon)
|
||||
end
|
||||
trainer.currentTeam = updated_team
|
||||
return trainer
|
||||
end
|
||||
|
||||
def evolveRebattledTrainerPokemon(trainer)
|
||||
updated_team = []
|
||||
for pokemon in trainer.currentTeam
|
||||
evolution_species = pokemon.check_evolution_on_level_up(false)
|
||||
if evolution_species
|
||||
trainer.log_evolution_event(pokemon.species,evolution_species)
|
||||
trainer.set_pending_action(true)
|
||||
pokemon.species = evolution_species if evolution_species
|
||||
end
|
||||
updated_team.push(pokemon)
|
||||
end
|
||||
trainer.currentTeam = updated_team
|
||||
return trainer
|
||||
end
|
||||
|
||||
def healRebattledTrainerPokemon(trainer)
|
||||
for pokemon in trainer.currentTeam
|
||||
pokemon.calc_stats
|
||||
pokemon.heal
|
||||
end
|
||||
return trainer
|
||||
end
|
||||
|
||||
def doNPCTrainerRematch(trainer)
|
||||
return generateTrainerRematch(trainer)
|
||||
end
|
||||
def generateTrainerRematch(trainer)
|
||||
trainer_data = GameData::Trainer.try_get(trainer.trainerType, trainer.trainerName, 0)
|
||||
|
||||
loseDialog = trainer_data&.loseText_rematch ? trainer_data.loseText_rematch : "..."
|
||||
if customTrainerBattle(trainer.trainerName,trainer.trainerType, trainer.currentTeam,nil,loseDialog)
|
||||
updated_trainer = makeRebattledTrainerTeamGainExp(trainer,true)
|
||||
updated_trainer = healRebattledTrainerPokemon(updated_trainer)
|
||||
else
|
||||
updated_trainer =makeRebattledTrainerTeamGainExp(trainer,false)
|
||||
end
|
||||
updated_trainer.set_pending_action(false)
|
||||
updated_trainer = evolveRebattledTrainerPokemon(updated_trainer)
|
||||
trainer.increase_friendship(5)
|
||||
return updated_trainer
|
||||
end
|
||||
|
||||
def showPrerematchDialog()
|
||||
event = pbMapInterpreter.get_character(0)
|
||||
map_id = $game_map.map_id if map_id.nil?
|
||||
trainer = getRebattledTrainer(event.id,map_id)
|
||||
return "" if trainer.nil?
|
||||
|
||||
trainer_data = GameData::Trainer.try_get(trainer.trainerType, trainer.trainerName, 0)
|
||||
|
||||
all_previous_random_events = trainer.previous_random_events
|
||||
|
||||
if all_previous_random_events
|
||||
previous_random_event = getBestMatchingPreviousRandomEvent(trainer_data, trainer.previous_random_events)
|
||||
|
||||
if previous_random_event
|
||||
event_message_map = {
|
||||
CATCH: trainer_data.preRematchText_caught,
|
||||
EVOLVE: trainer_data.preRematchText_evolved,
|
||||
FUSE: trainer_data.preRematchText_fused,
|
||||
UNFUSE: trainer_data.preRematchText_unfused,
|
||||
REVERSE: trainer_data.preRematchText_reversed
|
||||
}
|
||||
|
||||
message_text = event_message_map[previous_random_event.eventType] || trainer_data.preRematchText
|
||||
else
|
||||
message_text = trainer_data.preRematchText
|
||||
end
|
||||
end
|
||||
|
||||
if previous_random_event
|
||||
message_text = message_text.gsub("<CAUGHT_POKEMON>", getSpeciesRealName(previous_random_event.caught_pokemon).to_s)
|
||||
message_text = message_text.gsub("<UNEVOLVED_POKEMON>", getSpeciesRealName(previous_random_event.unevolved_pokemon).to_s)
|
||||
message_text = message_text.gsub("<EVOLVED_POKEMON>", getSpeciesRealName(previous_random_event.evolved_pokemon).to_s)
|
||||
message_text = message_text.gsub("<HEAD_POKEMON>", getSpeciesRealName(previous_random_event.fusion_head_pokemon).to_s)
|
||||
message_text = message_text.gsub("<BODY_POKEMON>", getSpeciesRealName(previous_random_event.fusion_body_pokemon).to_s)
|
||||
message_text = message_text.gsub("<FUSED_POKEMON>", getSpeciesRealName(previous_random_event.fusion_fused_pokemon).to_s)
|
||||
message_text = message_text.gsub("<UNREVERSED_POKEMON>", getSpeciesRealName(previous_random_event.unreversed_pokemon).to_s)
|
||||
message_text = message_text.gsub("<REVERSED_POKEMON>", getSpeciesRealName(previous_random_event.reversed_pokemon).to_s)
|
||||
message_text = message_text.gsub("<UNFUSED_POKEMON>", getSpeciesRealName(previous_random_event.unfused_pokemon).to_s)
|
||||
else
|
||||
message_text = trainer_data.preRematchText
|
||||
end
|
||||
if message_text
|
||||
split_messages = message_text.split("<br>")
|
||||
split_messages.each do |msg|
|
||||
pbCallBub(2,event.id)
|
||||
pbMessage(msg)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,203 @@
|
||||
class StartersSelectionScene
|
||||
POKEBALL_LEFT_X = -20; POKEBALL_LEFT_Y = 70
|
||||
POKEBALL_MIDDLE_X = 125; POKEBALL_MIDDLE_Y = 100
|
||||
POKEBALL_RIGHT_X = 275; POKEBALL_RIGHT_Y = 70
|
||||
|
||||
TEXT_POSITION_X = 100
|
||||
TEXT_POSITION_Y = 10
|
||||
|
||||
def initialize(starters = [])
|
||||
@starters_species = starters
|
||||
@starter_pokemon = []
|
||||
@starters_species.each do |species|
|
||||
@starter_pokemon.push(Pokemon.new(species,5))
|
||||
end
|
||||
|
||||
@spritesLoader = BattleSpriteLoader.new
|
||||
@shown_starter_species=nil
|
||||
end
|
||||
|
||||
def initializeGraphics()
|
||||
@background = displayPicture("Graphics/Pictures/Trades/hoenn_starter_bag_bg.png", -20, -20)
|
||||
@background.z=0
|
||||
|
||||
@foreground = displayPicture("Graphics/Pictures/Trades/hoenn_starter_bag_foreground.png", -20, -20)
|
||||
@foreground.z=999
|
||||
|
||||
@pokeball_closed_left = displayPicture("Graphics/Pictures/Trades/trade_pokeball_closed_1.png", POKEBALL_LEFT_X, POKEBALL_LEFT_Y)
|
||||
@pokeball_closed_left.z=2
|
||||
|
||||
@pokeball_closed_middle = displayPicture("Graphics/Pictures/Trades/trade_pokeball_closed_2.png", POKEBALL_MIDDLE_X, POKEBALL_MIDDLE_Y)
|
||||
@pokeball_closed_middle.z=100
|
||||
|
||||
@pokeball_closed_right = displayPicture("Graphics/Pictures/Trades/trade_pokeball_closed_3.png", POKEBALL_RIGHT_X, POKEBALL_RIGHT_Y)
|
||||
@pokeball_closed_right.z=2
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
def updateOpenPokeballPosition
|
||||
case @index
|
||||
when 0
|
||||
@shown_pokemon_x = POKEBALL_LEFT_X
|
||||
@shown_pokemon_y = POKEBALL_LEFT_Y
|
||||
when 1
|
||||
@shown_pokemon_x = POKEBALL_MIDDLE_X
|
||||
@shown_pokemon_y = POKEBALL_MIDDLE_Y
|
||||
when 2
|
||||
@shown_pokemon_x = POKEBALL_RIGHT_X
|
||||
@shown_pokemon_y = POKEBALL_RIGHT_Y
|
||||
end
|
||||
end
|
||||
|
||||
def startScene
|
||||
initializeGraphics
|
||||
@index=nil
|
||||
previous_index = nil
|
||||
loop do
|
||||
if @index
|
||||
if Input.trigger?(Input::RIGHT)
|
||||
previous_index = @index
|
||||
@index+=1
|
||||
@index = 0 if @index == @starters_species.length
|
||||
end
|
||||
if Input.trigger?(Input::LEFT)
|
||||
previous_index = @index
|
||||
@index-=1
|
||||
@index = @starters_species.length-1 if @index < 0
|
||||
end
|
||||
if Input.trigger?(Input::UP) || Input.trigger?(Input::DOWN)
|
||||
updateOpenPokeballPosition
|
||||
updateStarterSelectionGraphics
|
||||
end
|
||||
|
||||
if Input.trigger?(Input::USE)
|
||||
if pbConfirmMessage(_INTL("Do you choose this Pokémon?"))
|
||||
chosenPokemon = @starter_pokemon[@index]
|
||||
@spritesLoader.registerSpriteSubstitution(@pif_sprite)
|
||||
disposeGraphics
|
||||
pbSet(VAR_HOENN_CHOSEN_STARTER_INDEX,@index)
|
||||
return chosenPokemon
|
||||
end
|
||||
end
|
||||
else
|
||||
@index = 0 if Input.trigger?(Input::LEFT)
|
||||
@index = 1 if Input.trigger?(Input::DOWN)
|
||||
@index = 2 if Input.trigger?(Input::RIGHT)
|
||||
end
|
||||
|
||||
if previous_index != @index
|
||||
updateOpenPokeballPosition
|
||||
updateStarterSelectionGraphics
|
||||
previous_index = @index
|
||||
end
|
||||
Input.update
|
||||
Graphics.update
|
||||
end
|
||||
end
|
||||
|
||||
def disposeGraphics()
|
||||
@pokeball_closed_left.dispose
|
||||
@pokeball_closed_middle.dispose
|
||||
@pokeball_closed_right.dispose
|
||||
@pokeball_open_back.dispose
|
||||
@pokeball_open_front.dispose
|
||||
@background.dispose
|
||||
@foreground.dispose
|
||||
@pokemon_name_overlay.dispose
|
||||
@pokemon_category_overlay.dispose
|
||||
@pokemonSpriteWindow.dispose
|
||||
end
|
||||
|
||||
def updateClosedBallGraphicsVisibility
|
||||
case @index
|
||||
when 0
|
||||
@pokeball_closed_left.visible=false
|
||||
@pokeball_closed_middle.visible=true
|
||||
@pokeball_closed_right.visible=true
|
||||
when 1
|
||||
@pokeball_closed_left.visible=true
|
||||
@pokeball_closed_middle.visible=false
|
||||
@pokeball_closed_right.visible=true
|
||||
when 2
|
||||
@pokeball_closed_left.visible=true
|
||||
@pokeball_closed_middle.visible=true
|
||||
@pokeball_closed_right.visible=false
|
||||
else
|
||||
@pokeball_closed_left.visible=true
|
||||
@pokeball_closed_middle.visible=true
|
||||
@pokeball_closed_right.visible=true
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
def updateStarterSelectionGraphics()
|
||||
pbSEPlay("GUI storage pick up", 80, 100)
|
||||
updateClosedBallGraphicsVisibility
|
||||
@pokeball_open_back.dispose if @pokeball_open_back
|
||||
@pokeball_open_front.dispose if @pokeball_open_front
|
||||
|
||||
@shown_starter_species = @starters_species[@index]
|
||||
|
||||
updateOpenPokeballPosition
|
||||
@pokeball_open_back = displayPicture("Graphics/Pictures/Trades/trade_pokeball_open_back",@shown_pokemon_x, @shown_pokemon_y,2)
|
||||
@pokeball_open_front = displayPicture("Graphics/Pictures/Trades/trade_pokeball_open_front",@shown_pokemon_x, @shown_pokemon_y,50)
|
||||
|
||||
updatePokemonSprite
|
||||
end
|
||||
|
||||
def updatePokemonSprite()
|
||||
@pif_sprite = @spritesLoader.get_pif_sprite_from_species(@shown_starter_species.species)
|
||||
sprite_bitmap = @spritesLoader.load_pif_sprite_directly(@pif_sprite)
|
||||
pokemon = @starter_pokemon[@index]
|
||||
if pokemon.shiny?
|
||||
sprite_bitmap.bitmap.update_shiny_cache(pokemon.id_number, "")
|
||||
sprite_bitmap.shiftAllColors(pokemon.id_number, pokemon.bodyShiny?, pokemon.headShiny?)
|
||||
end
|
||||
|
||||
@pokemonSpriteWindow.dispose if @pokemonSpriteWindow
|
||||
@pokemonSpriteWindow = PictureWindow.new(sprite_bitmap.bitmap)
|
||||
|
||||
@pokemonSpriteWindow.opacity = 0
|
||||
@pokemonSpriteWindow.z = 2
|
||||
@pokemonSpriteWindow.x = @shown_pokemon_x
|
||||
@pokemonSpriteWindow.y = @shown_pokemon_y-10
|
||||
updateText
|
||||
end
|
||||
|
||||
def updateText
|
||||
@pokemon_name_overlay.dispose if @pokemon_name_overlay
|
||||
@pokemon_category_overlay.dispose if @pokemon_category_overlay
|
||||
|
||||
pokemon_name = "#{@shown_starter_species.real_name}"
|
||||
pokemon_category = "#{@shown_starter_species.real_category} Pokémon"
|
||||
|
||||
title_position_y = TEXT_POSITION_Y
|
||||
subtitle_position_y = TEXT_POSITION_Y + 30
|
||||
|
||||
text_x_offset=-100
|
||||
|
||||
label_base_color = Color.new(88,88,80)
|
||||
label_shadow_color = Color.new(168,184,184)
|
||||
|
||||
title_base_color = Color.new(248, 248, 248)
|
||||
title_shadow_color = Color.new(104, 104, 104)
|
||||
|
||||
@pokemon_name_overlay = BitmapSprite.new(Graphics.width, Graphics.height, @viewport).bitmap
|
||||
@pokemon_category_overlay = BitmapSprite.new(Graphics.width, Graphics.height, @viewport).bitmap
|
||||
|
||||
@pokemon_name_overlay.font.size = 50
|
||||
@pokemon_name_overlay.font.name = MessageConfig.pbGetSmallFontName
|
||||
|
||||
@pokemon_category_overlay.font.size = 36
|
||||
@pokemon_category_overlay.font.name = MessageConfig.pbGetSmallFontName
|
||||
|
||||
pbDrawTextPositions(@pokemon_name_overlay, [[pokemon_name, (Graphics.width/2)+text_x_offset, title_position_y, 2, title_base_color, title_shadow_color]])
|
||||
pbDrawTextPositions(@pokemon_category_overlay,[[pokemon_category, (Graphics.width/2)+text_x_offset, subtitle_position_y, 2, label_base_color, label_shadow_color]])
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,85 @@
|
||||
class BattledTrainer
|
||||
TRAINER_CLASS_FAVORITE_TYPES =
|
||||
{
|
||||
AROMALADY: [:GRASS, :FAIRY],
|
||||
BEAUTY: [:FAIRY, :WATER, :NORMAL, :GRASS],
|
||||
BIKER: [:POISON, :DARK],
|
||||
BIRDKEEPER: [:FLYING, :NORMAL],
|
||||
BUGCATCHER: [:BUG],
|
||||
BURGLAR: [:FIRE, :DARK],
|
||||
CHANNELER: [:GHOST, :PSYCHIC],
|
||||
CUEBALL: [:FIGHTING],
|
||||
ENGINEER: [:ELECTRIC, :STEEL],
|
||||
FISHERMAN: [:WATER],
|
||||
GAMBLER: [:NORMAL, :PSYCHIC],
|
||||
GENTLEMAN: [:NORMAL, :STEEL],
|
||||
HIKER: [:ROCK, :GROUND],
|
||||
JUGGLER: [:PSYCHIC, :GHOST],
|
||||
LADY: [:FAIRY, :NORMAL],
|
||||
PAINTER: [:NORMAL, :PSYCHIC],
|
||||
POKEMANIAC: [:DRAGON, :GROUND],
|
||||
POKEMONBREEDER: [:NORMAL, :GRASS],
|
||||
PROFESSOR: [:NORMAL, :PSYCHIC],
|
||||
ROCKER: [:ELECTRIC, :FIRE],
|
||||
RUINMANIAC: [:GROUND, :ROCK],
|
||||
SAILOR: [:WATER, :FIGHTING],
|
||||
SCIENTIST: [:ELECTRIC, :STEEL, :POISON],
|
||||
SUPERNERD: [:ELECTRIC, :PSYCHIC, :STEEL],
|
||||
TAMER: [:NORMAL, :DARK],
|
||||
BLACKBELT: [:FIGHTING],
|
||||
CRUSHGIRL: [:FIGHTING],
|
||||
CAMPER: [:BUG, :NORMAL, :GRASS],
|
||||
PICNICKER: [:GRASS, :NORMAL],
|
||||
COOLTRAINER_M: [:DRAGON, :STEEL, :FIRE],
|
||||
COOLTRAINER_F: [:ICE, :PSYCHIC, :FAIRY],
|
||||
YOUNGSTER: [:NORMAL, :BUG],
|
||||
LASS: [:NORMAL, :FAIRY],
|
||||
POKEMONRANGER_M: [:GRASS, :GROUND],
|
||||
POKEMONRANGER_F: [:GRASS, :WATER],
|
||||
PSYCHIC_M: [:PSYCHIC, :GHOST],
|
||||
PSYCHIC_F: [:PSYCHIC, :FAIRY],
|
||||
SWIMMER_M: [:WATER],
|
||||
SWIMMER_F: [:WATER, :ICE],
|
||||
SWIMMER2_M: [:WATER],
|
||||
SWIMMER2_F: [:WATER],
|
||||
TUBER_M: [:WATER],
|
||||
TUBER_F: [:WATER],
|
||||
TUBER2_M: [:WATER],
|
||||
TUBER2_F: [:WATER],
|
||||
COOLCOUPLE: [:FIRE, :ICE],
|
||||
CRUSHKIN: [:FIGHTING],
|
||||
SISANDBRO: [:WATER, :GROUND],
|
||||
TWINS: [:FAIRY, :NORMAL],
|
||||
YOUNGCOUPLE: [:NORMAL, :PSYCHIC],
|
||||
SOCIALITE: [:FAIRY, :NORMAL],
|
||||
BUGCATCHER_F: [:BUG],
|
||||
ROUGHNECK: [:DARK, :FIGHTING],
|
||||
TEACHER: [:PSYCHIC, :NORMAL],
|
||||
PRESCHOOLER_M: [:NORMAL],
|
||||
PRESCHOOLER_F: [:FAIRY, :NORMAL],
|
||||
HAUNTEDGIRL_YOUNG: [:GHOST],
|
||||
HAUNTEDGIRL: [:GHOST, :DARK],
|
||||
CLOWN: [:PSYCHIC, :FAIRY],
|
||||
NURSE: [:NORMAL, :FAIRY],
|
||||
WORKER: [:STEEL, :GROUND],
|
||||
COOLTRAINER_M2: [:FIGHTING, :STEEL],
|
||||
COOLTRAINER_F2: [:PSYCHIC, :ICE],
|
||||
FARMER: [:GRASS, :GROUND, :NORMAL],
|
||||
PYROMANIAC: [:FIRE],
|
||||
KIMONOGIRL: [:FAIRY, :PSYCHIC, :GHOST],
|
||||
SAGE: [:PSYCHIC, :GHOST],
|
||||
PLAYER: [:ICE, :FIGHTING],
|
||||
POLICE: [:DARK, :FIGHTING],
|
||||
SKIER_F: [:ICE],
|
||||
DELIVERYMAN: [:NORMAL],
|
||||
RICHBOY: [],
|
||||
SCHOOLBOY: [],
|
||||
SCHOOLGIRL: [],
|
||||
TEAM_AQUA_GRUNT_M: [],
|
||||
TEAM_AQUA_GRUNT_F: [],
|
||||
TEAM_MAGMA_GRUNT_M: [],
|
||||
TEAM_MAGMA_GRUNT_F: [],
|
||||
TEAM_MAGMAQUA_GRUNT_M: [],
|
||||
TEAM_MAGMAQUA_GRUNT_F: [],
|
||||
}
|
||||
end
|
||||
@@ -0,0 +1,85 @@
|
||||
class BattledTrainer
|
||||
FRIENDSHIP_LEVELS = {
|
||||
AROMALADY: [10, 25, 45],
|
||||
BEAUTY: [15, 30, 60],
|
||||
BIKER: [20, 40, 80],
|
||||
BIRDKEEPER: [10, 25, 50],
|
||||
BUGCATCHER: [8, 20, 35],
|
||||
BURGLAR: [20, 45, 90],
|
||||
CHANNELER: [15, 35, 70],
|
||||
CUEBALL: [18, 38, 80],
|
||||
ENGINEER: [15, 30, 65],
|
||||
FISHERMAN: [12, 28, 55],
|
||||
GAMBLER: [15, 30, 60],
|
||||
GENTLEMAN: [12, 30, 70],
|
||||
HIKER: [10, 25, 50],
|
||||
JUGGLER: [15, 30, 65],
|
||||
LADY: [15, 30, 60],
|
||||
PAINTER: [8, 22, 40],
|
||||
POKEMANIAC: [18, 35, 70],
|
||||
POKEMONBREEDER: [8, 18, 35],
|
||||
PROFESSOR: [10, 30, 60],
|
||||
ROCKER: [15, 35, 70],
|
||||
RUINMANIAC: [15, 35, 65],
|
||||
SAILOR: [12, 28, 60],
|
||||
SCIENTIST: [15, 35, 70],
|
||||
SUPERNERD: [14, 30, 65],
|
||||
TAMER: [15, 35, 75],
|
||||
BLACKBELT: [20, 45, 90],
|
||||
CRUSHGIRL: [18, 40, 85],
|
||||
CAMPER: [10, 22, 40],
|
||||
PICNICKER: [10, 22, 40],
|
||||
COOLTRAINER_M: [20, 45, 95],
|
||||
COOLTRAINER_F: [20, 45, 95],
|
||||
YOUNGSTER: [10, 25, 40],
|
||||
LASS: [10, 22, 38],
|
||||
POKEMONRANGER_M:[15, 35, 80],
|
||||
POKEMONRANGER_F:[15, 35, 80],
|
||||
PSYCHIC_M: [15, 35, 70],
|
||||
PSYCHIC_F: [15, 35, 70],
|
||||
SWIMMER_M: [10, 25, 50],
|
||||
SWIMMER_F: [10, 25, 50],
|
||||
SWIMMER2_M: [12, 28, 55],
|
||||
SWIMMER2_F: [12, 28, 55],
|
||||
TUBER_M: [6, 15, 30],
|
||||
TUBER_F: [6, 15, 30],
|
||||
TUBER2_M: [6, 15, 30],
|
||||
TUBER2_F: [6, 15, 30],
|
||||
COOLCOUPLE: [15, 35, 80],
|
||||
CRUSHKIN: [15, 35, 80],
|
||||
SISANDBRO: [10, 25, 50],
|
||||
TWINS: [10, 25, 50],
|
||||
YOUNGCOUPLE: [15, 30, 65],
|
||||
SOCIALITE: [12, 30, 70],
|
||||
BUGCATCHER_F: [8, 20, 35],
|
||||
ROUGHNECK: [18, 38, 85],
|
||||
TEACHER: [12, 28, 60],
|
||||
PRESCHOOLER_M: [5, 12, 25],
|
||||
PRESCHOOLER_F: [5, 12, 25],
|
||||
HAUNTEDGIRL_YOUNG: [10, 25, 55],
|
||||
HAUNTEDGIRL: [12, 30, 65],
|
||||
CLOWN: [10, 25, 50],
|
||||
NURSE: [8, 20, 35],
|
||||
WORKER: [12, 30, 65],
|
||||
COOLTRAINER_M2: [22, 50, 100],
|
||||
COOLTRAINER_F2: [22, 50, 100],
|
||||
FARMER: [10, 25, 50],
|
||||
PYROMANIAC: [20, 45, 90],
|
||||
KIMONOGIRL: [12, 30, 60],
|
||||
SAGE: [15, 30, 65],
|
||||
PLAYER: [12, 30, 60],
|
||||
POLICE: [20, 45, 90],
|
||||
SKIER_F: [12, 28, 55],
|
||||
DELIVERYMAN: [8, 20, 40],
|
||||
RICHBOY: [15, 35, 70],
|
||||
SCHOOLBOY: [10, 22, 40],
|
||||
SCHOOLGIRL: [10, 22, 40],
|
||||
TEAM_AQUA_GRUNT_M: [25, 60, 100],
|
||||
TEAM_AQUA_GRUNT_F: [25, 60, 100],
|
||||
TEAM_MAGMA_GRUNT_M: [25, 60, 100],
|
||||
TEAM_MAGMA_GRUNT_F: [25, 60, 100],
|
||||
TEAM_MAGMAQUA_GRUNT_M: [25, 60, 100],
|
||||
TEAM_MAGMAQUA_GRUNT_F: [25, 60, 100],
|
||||
}
|
||||
|
||||
end
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#####
|
||||
# Util methods
|
||||
#####
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
####
|
||||
# Methods to be called from events
|
||||
####
|
||||
|
||||
|
||||
#actionType :
|
||||
# :BATTLE
|
||||
# :TRADE
|
||||
# :PARTNER
|
||||
def doPostBattleAction(actionType)
|
||||
event = pbMapInterpreter.get_character(0)
|
||||
map_id = $game_map.map_id if map_id.nil?
|
||||
trainer = getRebattledTrainer(event.id,map_id)
|
||||
trainer.clear_previous_random_events()
|
||||
|
||||
return if !trainer
|
||||
case actionType
|
||||
when :BATTLE
|
||||
trainer = doNPCTrainerRematch(trainer)
|
||||
when :TRADE
|
||||
trainer = doNPCTrainerTrade(trainer)
|
||||
when :PARTNER
|
||||
partnerWithTrainer(event.id,map_id,trainer)
|
||||
end
|
||||
updateRebattledTrainer(event.id,map_id,trainer)
|
||||
|
||||
end
|
||||
|
||||
def setTrainerFriendship(trainer)
|
||||
params = ChooseNumberParams.new
|
||||
params.setRange(0,100)
|
||||
params.setDefaultValue($game_map.map_id)
|
||||
number = pbMessageChooseNumber("Frienship (0-100)?",params)
|
||||
trainer.friendship = number
|
||||
trainer.increase_friendship(0)
|
||||
return trainer
|
||||
end
|
||||
|
||||
#party: array of pokemon team
|
||||
# [[:SPECIES,level], ... ]
|
||||
#
|
||||
#def customTrainerBattle(trainerName, trainerType, party_array, default_level=50, endSpeech="", sprite_override=nil,custom_appearance=nil)
|
||||
def postBattleActionsMenu()
|
||||
rematchCommand = "Rematch"
|
||||
tradeCommand = "Trade Offer"
|
||||
partnerCommand = "Partner up"
|
||||
cancelCommand = "See ya!"
|
||||
|
||||
updateTeamDebugCommand = "(Debug) Simulate random event"
|
||||
resetTrainerDebugCommand = "(Debug) Reset trainer"
|
||||
setFriendshipDebugCommand = "(Debug) Set Friendship"
|
||||
printTrainerTeamDebugCommand = "(Debug) Print team"
|
||||
|
||||
|
||||
event = pbMapInterpreter.get_character(0)
|
||||
map_id = $game_map.map_id if map_id.nil?
|
||||
trainer = getRebattledTrainer(event.id,map_id)
|
||||
|
||||
options = []
|
||||
options << rematchCommand
|
||||
options << tradeCommand if trainer.friendship_level >= 1
|
||||
options << partnerCommand if trainer.friendship_level >= 3
|
||||
|
||||
options << updateTeamDebugCommand if $DEBUG
|
||||
options << resetTrainerDebugCommand if $DEBUG
|
||||
options << setFriendshipDebugCommand if $DEBUG
|
||||
options << printTrainerTeamDebugCommand if $DEBUG
|
||||
|
||||
options << cancelCommand
|
||||
|
||||
trainer = applyTrainerRandomEvents(trainer)
|
||||
showPrerematchDialog
|
||||
choice = optionsMenu(options,options.find_index(cancelCommand),options.find_index(cancelCommand))
|
||||
|
||||
case options[choice]
|
||||
when rematchCommand
|
||||
doPostBattleAction(:BATTLE)
|
||||
when tradeCommand
|
||||
doPostBattleAction(:TRADE)
|
||||
when partnerCommand
|
||||
doPostBattleAction(:PARTNER)
|
||||
when updateTeamDebugCommand
|
||||
echoln("")
|
||||
echoln "---------------"
|
||||
makeRebattledTrainerTeamGainExp(trainer,true)
|
||||
evolveRebattledTrainerPokemon(trainer)
|
||||
applyTrainerRandomEvents(trainer)
|
||||
when resetTrainerDebugCommand
|
||||
resetTrainerRebattle(event.id,map_id)
|
||||
when setFriendshipDebugCommand
|
||||
trainer = getRebattledTrainer(event.id,map_id)
|
||||
trainer = setTrainerFriendship(trainer)
|
||||
updateRebattledTrainer(event.id,map_id,trainer)
|
||||
when printTrainerTeamDebugCommand
|
||||
trainer = getRebattledTrainer(event.id,map_id)
|
||||
printNPCTrainerCurrentTeam(trainer)
|
||||
when cancelCommand
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
COMMON_EVENT_TRAINER_REMATCH_PARTNER = 200
|
||||
def partnerWithTrainer(eventId, mapID, trainer)
|
||||
Kernel.pbAddDependency2(eventId,trainer.trainerName,COMMON_EVENT_TRAINER_REMATCH_PARTNER)
|
||||
pbCancelVehicles
|
||||
originalTrainer = pbLoadTrainer(trainer.trainerType, trainer.trainerName, 0)
|
||||
Events.onTrainerPartyLoad.trigger(nil, originalTrainer)
|
||||
for i in trainer.currentTeam
|
||||
i.owner = Pokemon::Owner.new_from_trainer(originalTrainer)
|
||||
i.calc_stats
|
||||
end
|
||||
$PokemonGlobal.partner = [trainer.trainerType, trainer.trainerName, 0, trainer.currentTeam]
|
||||
end
|
||||
@@ -0,0 +1,195 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
def printNPCTrainerCurrentTeam(trainer)
|
||||
team_string = "["
|
||||
trainer.currentTeam.each do |pokemon|
|
||||
name= get_pokemon_readable_internal_name(pokemon)
|
||||
level = pokemon.level
|
||||
formatted_info = "#{name} (lv.#{level}), "
|
||||
team_string += formatted_info
|
||||
end
|
||||
team_string += "]"
|
||||
echoln "Trainer's current team is: #{team_string}"
|
||||
end
|
||||
|
||||
def applyTrainerRandomEvents(trainer)
|
||||
if trainer.has_pending_action
|
||||
echoln "Trainer has pending action"
|
||||
end
|
||||
|
||||
return trainer if trainer.has_pending_action
|
||||
trainer.clear_previous_random_events
|
||||
|
||||
#time_passed = trainer.getTimeSinceLastAction
|
||||
#return trainer if time_passed < TIME_FOR_RANDOM_EVENTS
|
||||
|
||||
# Weighted chances out of 10
|
||||
weighted_events = [
|
||||
[:CATCH, 3],
|
||||
[:FUSE, 6],
|
||||
[:REVERSE, 1],
|
||||
[:UNFUSE, 20]
|
||||
]
|
||||
|
||||
# Create a flat array of events based on weight
|
||||
event_pool = weighted_events.flat_map { |event, weight| [event] * weight }
|
||||
|
||||
selected_event = event_pool.sample
|
||||
|
||||
if selected_event
|
||||
echoln "Trying to do random event: #{selected_event}"
|
||||
end
|
||||
|
||||
|
||||
return trainer if selected_event.nil?
|
||||
|
||||
case selected_event
|
||||
when :CATCH
|
||||
trainer = catch_new_team_pokemon(trainer)
|
||||
when :FUSE
|
||||
trainer = fuse_random_team_pokemon(trainer)
|
||||
when :UNFUSE
|
||||
trainer = unfuse_random_team_pokemon(trainer)
|
||||
when :REVERSE
|
||||
trainer = reverse_random_team_pokemon(trainer)
|
||||
end
|
||||
trainer.set_pending_action(true)
|
||||
printNPCTrainerCurrentTeam(trainer)
|
||||
return trainer
|
||||
end
|
||||
|
||||
|
||||
|
||||
def chooseEncounterType(trainerClass)
|
||||
water_trainer_classes = [:SWIMMER_F, :SWIMMER_M, :FISHERMAN]
|
||||
if water_trainer_classes.include?(trainerClass )
|
||||
chance_of_land_encounter = 1
|
||||
chance_of_surf_encounter= 5
|
||||
chance_of_cave_encounter = 1
|
||||
chance_of_fishing_encounter = 5
|
||||
else
|
||||
chance_of_land_encounter = 5
|
||||
chance_of_surf_encounter= 1
|
||||
chance_of_cave_encounter = 5
|
||||
chance_of_fishing_encounter = 1
|
||||
end
|
||||
|
||||
if pbCheckHiddenMoveBadge(Settings::BADGE_FOR_SURF, false)
|
||||
chance_of_surf_encounter =0
|
||||
chance_of_fishing_encounter = 0
|
||||
end
|
||||
|
||||
possible_encounter_types = []
|
||||
if $PokemonEncounters.has_land_encounters?
|
||||
possible_encounter_types += [:Land] * chance_of_land_encounter
|
||||
end
|
||||
if $PokemonEncounters.has_cave_encounters?
|
||||
possible_encounter_types += [:Cave] * chance_of_cave_encounter
|
||||
end
|
||||
if $PokemonEncounters.has_water_encounters?
|
||||
possible_encounter_types += [:GoodRod] * chance_of_fishing_encounter
|
||||
possible_encounter_types += [:Water] * chance_of_surf_encounter
|
||||
end
|
||||
echoln "possible_encounter_types: #{possible_encounter_types}"
|
||||
return getTimeBasedEncounter(possible_encounter_types.sample)
|
||||
end
|
||||
|
||||
|
||||
def getTimeBasedEncounter(encounter_type)
|
||||
time = pbGetTimeNow
|
||||
return $PokemonEncounters.find_valid_encounter_type_for_time(encounter_type, time)
|
||||
end
|
||||
|
||||
def catch_new_team_pokemon(trainer)
|
||||
return trainer if trainer.currentTeam.length >= 6
|
||||
encounter_type = chooseEncounterType(trainer.trainerType)
|
||||
return trainer if !encounter_type
|
||||
|
||||
echoln "Catching a pokemon via encounter_type #{encounter_type}"
|
||||
wild_pokemon = $PokemonEncounters.choose_wild_pokemon(encounter_type)
|
||||
echoln wild_pokemon
|
||||
if wild_pokemon
|
||||
trainer.currentTeam << Pokemon.new(wild_pokemon[0],wild_pokemon[1])
|
||||
trainer.log_catch_event(wild_pokemon[0])
|
||||
end
|
||||
return trainer
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
def reverse_random_team_pokemon(trainer)
|
||||
eligible_pokemon = trainer.list_team_fused_pokemon
|
||||
return trainer if eligible_pokemon.length < 1
|
||||
return trainer if trainer.currentTeam.length > 5
|
||||
pokemon_to_reverse = eligible_pokemon.sample
|
||||
old_species = pokemon_to_reverse.species
|
||||
trainer.currentTeam.delete(pokemon_to_reverse)
|
||||
|
||||
body_pokemon = get_body_species_from_symbol(pokemon_to_reverse.species)
|
||||
head_pokemon = get_head_species_from_symbol(pokemon_to_reverse.species)
|
||||
|
||||
pokemon_to_reverse.species = getFusedPokemonIdFromSymbols(head_pokemon,body_pokemon)
|
||||
trainer.currentTeam.push(pokemon_to_reverse)
|
||||
trainer.log_reverse_event(old_species,pokemon_to_reverse.species)
|
||||
return trainer
|
||||
end
|
||||
|
||||
|
||||
def unfuse_random_team_pokemon(trainer)
|
||||
eligible_pokemon = trainer.list_team_fused_pokemon
|
||||
return trainer if eligible_pokemon.length < 1
|
||||
return trainer if trainer.currentTeam.length > 5
|
||||
pokemon_to_unfuse = eligible_pokemon.sample
|
||||
|
||||
echoln pokemon_to_unfuse.owner.name
|
||||
echoln trainer.trainerName
|
||||
return trainer if pokemon_to_unfuse.owner.name != trainer.trainerName
|
||||
|
||||
body_pokemon = get_body_id_from_symbol(pokemon_to_unfuse.species)
|
||||
head_pokemon = get_head_id_from_symbol(pokemon_to_unfuse.species)
|
||||
|
||||
level = calculateUnfuseLevelOldMethod(pokemon_to_unfuse,false)
|
||||
|
||||
trainer.currentTeam.delete(pokemon_to_unfuse)
|
||||
trainer.currentTeam.push(Pokemon.new(body_pokemon,level))
|
||||
trainer.currentTeam.push(Pokemon.new(head_pokemon,level))
|
||||
trainer.log_unfusion_event(pokemon_to_unfuse.species, body_pokemon, head_pokemon)
|
||||
return trainer
|
||||
end
|
||||
|
||||
def fuse_random_team_pokemon(trainer)
|
||||
eligible_pokemon = trainer.list_team_unfused_pokemon
|
||||
return trainer if eligible_pokemon.length < 2
|
||||
|
||||
pokemon_to_fuse = eligible_pokemon.sample(2)
|
||||
body_pokemon = pokemon_to_fuse[0]
|
||||
head_pokemon = pokemon_to_fuse[1]
|
||||
fusion_species = getFusedPokemonIdFromSymbols(body_pokemon.species,head_pokemon.species)
|
||||
level = (body_pokemon.level + head_pokemon.level)/2
|
||||
fused_pokemon = Pokemon.new(fusion_species,level)
|
||||
|
||||
trainer.currentTeam.delete(body_pokemon)
|
||||
trainer.currentTeam.delete(head_pokemon)
|
||||
trainer.currentTeam.push(fused_pokemon)
|
||||
trainer.log_fusion_event(body_pokemon.species,head_pokemon.species,fusion_species)
|
||||
return trainer
|
||||
end
|
||||
|
||||
def getBestMatchingPreviousRandomEvent(trainer_data, previous_events)
|
||||
return nil if trainer_data.nil? || previous_events.nil?
|
||||
|
||||
priority = [:CATCH, :EVOLVE, :FUSE, :UNFUSE, :REVERSE]
|
||||
event_message_map = {
|
||||
CATCH: trainer_data.preRematchText_caught,
|
||||
EVOLVE: trainer_data.preRematchText_evolved,
|
||||
FUSE: trainer_data.preRematchText_fused,
|
||||
UNFUSE: trainer_data.preRematchText_unfused,
|
||||
REVERSE: trainer_data.preRematchText_reversed
|
||||
}
|
||||
sorted_events = previous_events.sort_by do |event|
|
||||
priority.index(event.eventType) || Float::INFINITY
|
||||
end
|
||||
|
||||
sorted_events.find { |event| event_message_map[event.eventType] }
|
||||
end
|
||||
@@ -0,0 +1,273 @@
|
||||
|
||||
TRAINER_CLASS_FAVORITE_TYPES =
|
||||
{
|
||||
AROMALADY: [:GRASS, :FAIRY],
|
||||
BEAUTY: [:FAIRY, :WATER, :NORMAL, :GRASS],
|
||||
BIKER: [:POISON, :DARK],
|
||||
BIRDKEEPER: [:FLYING, :NORMAL],
|
||||
BUGCATCHER: [:BUG],
|
||||
BURGLAR: [:FIRE, :DARK],
|
||||
CHANNELER: [:GHOST, :PSYCHIC],
|
||||
CUEBALL: [:FIGHTING, :STEEL],
|
||||
ENGINEER: [:ELECTRIC, :STEEL],
|
||||
FISHERMAN: [:WATER],
|
||||
GAMBLER: [:NORMAL, :PSYCHIC],
|
||||
GENTLEMAN: [:NORMAL, :STEEL],
|
||||
HIKER: [:ROCK, :GROUND],
|
||||
JUGGLER: [:PSYCHIC, :GHOST, :NORMAL, :POISON],
|
||||
LADY: [:FAIRY, :NORMAL],
|
||||
PAINTER: [:NORMAL, :PSYCHIC, :GRASS],
|
||||
POKEMANIAC: [:DRAGON, :GROUND],
|
||||
POKEMONBREEDER: [:NORMAL, :GRASS],
|
||||
PROFESSOR: [:NORMAL, :PSYCHIC],
|
||||
ROCKER: [:ELECTRIC, :FIRE],
|
||||
RUINMANIAC: [:GROUND, :ROCK, :PSYCHIC],
|
||||
SAILOR: [:WATER, :FIGHTING],
|
||||
SCIENTIST: [:ELECTRIC, :STEEL, :POISON],
|
||||
SUPERNERD: [:ELECTRIC, :PSYCHIC, :STEEL],
|
||||
TAMER: [:NORMAL, :DARK],
|
||||
BLACKBELT: [:FIGHTING],
|
||||
CRUSHGIRL: [:FIGHTING],
|
||||
CAMPER: [:BUG, :NORMAL, :GRASS],
|
||||
PICNICKER: [:GRASS, :NORMAL],
|
||||
COOLTRAINER_M: [:DRAGON, :STEEL, :FIRE],
|
||||
COOLTRAINER_F: [:ICE, :PSYCHIC, :FAIRY],
|
||||
YOUNGSTER: [:NORMAL, :BUG, :GRASS, :FLYING],
|
||||
LASS: [:NORMAL, :FAIRY],
|
||||
POKEMONRANGER_M: [:GRASS, :GROUND],
|
||||
POKEMONRANGER_F: [:GRASS, :WATER],
|
||||
PSYCHIC_M: [:PSYCHIC, :GHOST],
|
||||
PSYCHIC_F: [:PSYCHIC, :FAIRY],
|
||||
SWIMMER_M: [:WATER, :ICE],
|
||||
SWIMMER_F: [:WATER, :ICE],
|
||||
SWIMMER2_M: [:WATER],
|
||||
SWIMMER2_F: [:WATER],
|
||||
TUBER_M: [:WATER],
|
||||
TUBER_F: [:WATER],
|
||||
TUBER2_M: [:WATER],
|
||||
TUBER2_F: [:WATER],
|
||||
COOLCOUPLE: [:FIRE, :ICE],
|
||||
CRUSHKIN: [:FIGHTING],
|
||||
SISANDBRO: [:WATER, :GROUND],
|
||||
TWINS: [:FAIRY, :NORMAL],
|
||||
YOUNGCOUPLE: [:NORMAL, :PSYCHIC],
|
||||
SOCIALITE: [:FAIRY, :NORMAL],
|
||||
BUGCATCHER_F: [:BUG],
|
||||
ROUGHNECK: [:DARK, :FIGHTING],
|
||||
TEACHER: [:PSYCHIC, :NORMAL],
|
||||
PRESCHOOLER_M: [:NORMAL, :BUG],
|
||||
PRESCHOOLER_F: [:FAIRY, :NORMAL],
|
||||
HAUNTEDGIRL_YOUNG: [:GHOST],
|
||||
HAUNTEDGIRL: [:GHOST, :DARK],
|
||||
CLOWN: [:PSYCHIC, :FAIRY],
|
||||
NURSE: [:NORMAL, :FAIRY],
|
||||
WORKER: [:STEEL, :GROUND],
|
||||
COOLTRAINER_M2: [:FIGHTING, :STEEL],
|
||||
COOLTRAINER_F2: [:PSYCHIC, :ICE],
|
||||
FARMER: [:GRASS, :GROUND, :NORMAL],
|
||||
PYROMANIAC: [:FIRE],
|
||||
KIMONOGIRL: [:FAIRY, :PSYCHIC, :GHOST],
|
||||
SAGE: [:PSYCHIC, :GHOST],
|
||||
PLAYER: [:ICE, :FIGHTING],
|
||||
POLICE: [:DARK, :FIGHTING],
|
||||
SKIER_F: [:ICE],
|
||||
DELIVERYMAN: [:NORMAL],
|
||||
}
|
||||
|
||||
#Higher values: pickier
|
||||
TRAINER_CLASS_PICKINESS = {
|
||||
AROMALADY: 1.8,
|
||||
BEAUTY: 2.2,
|
||||
BIKER: 1.2,
|
||||
BIRDKEEPER: 1.4,
|
||||
BUGCATCHER: 1.1,
|
||||
BURGLAR: 1.3,
|
||||
CHANNELER: 1.7,
|
||||
CUEBALL: 1.3,
|
||||
ENGINEER: 2.0,
|
||||
FISHERMAN: 1.4,
|
||||
GAMBLER: 1.5,
|
||||
GENTLEMAN: 2.3,
|
||||
HIKER: 1.5,
|
||||
JUGGLER: 1.8,
|
||||
LADY: 2.4,
|
||||
PAINTER: 2.0,
|
||||
POKEMANIAC: 1.6,
|
||||
POKEMONBREEDER: 1.9,
|
||||
PROFESSOR: 2.5,
|
||||
ROCKER: 1.4,
|
||||
RUINMANIAC: 1.5,
|
||||
SAILOR: 1.3,
|
||||
SCIENTIST: 2.0,
|
||||
SUPERNERD: 1.9,
|
||||
TAMER: 1.5,
|
||||
BLACKBELT: 1.7,
|
||||
CRUSHGIRL: 1.6,
|
||||
CAMPER: 1.2,
|
||||
PICNICKER: 1.2,
|
||||
COOLTRAINER_M: 2.4,
|
||||
COOLTRAINER_F: 2.4,
|
||||
YOUNGSTER: 0.9,
|
||||
LASS: 1.0,
|
||||
POKEMONRANGER_M: 2.0,
|
||||
POKEMONRANGER_F: 2.0,
|
||||
PSYCHIC_M: 2.0,
|
||||
PSYCHIC_F: 2.0,
|
||||
SWIMMER_M: 1.0,
|
||||
SWIMMER_F: 1.0,
|
||||
SWIMMER2_M: 1.0,
|
||||
SWIMMER2_F: 1.0,
|
||||
TUBER_M: 0.8,
|
||||
TUBER_F: 0.8,
|
||||
TUBER2_M: 0.8,
|
||||
TUBER2_F: 0.8,
|
||||
COOLCOUPLE: 2.1,
|
||||
CRUSHKIN: 1.7,
|
||||
SISANDBRO: 1.3,
|
||||
TWINS: 1.0,
|
||||
YOUNGCOUPLE: 1.6,
|
||||
SOCIALITE: 2.3,
|
||||
BUGCATCHER_F: 1.1,
|
||||
ROUGHNECK: 1.4,
|
||||
TEACHER: 2.0,
|
||||
PRESCHOOLER_M: 0.6,
|
||||
PRESCHOOLER_F: 0.6,
|
||||
HAUNTEDGIRL_YOUNG: 1.3,
|
||||
HAUNTEDGIRL: 1.7,
|
||||
CLOWN: 1.5,
|
||||
NURSE: 2.0,
|
||||
WORKER: 1.6,
|
||||
COOLTRAINER_M2: 2.4,
|
||||
COOLTRAINER_F2: 2.4,
|
||||
FARMER: 1.5,
|
||||
PYROMANIAC: 1.6,
|
||||
KIMONOGIRL: 2.2,
|
||||
SAGE: 2.1,
|
||||
PLAYER: 1.0,
|
||||
POLICE: 1.8,
|
||||
SKIER_F: 1.6,
|
||||
DELIVERYMAN: 1.3
|
||||
}
|
||||
|
||||
|
||||
def evaluate_pokemon_worth(pkmn, compare_level: nil)
|
||||
species_data = pkmn.species_data
|
||||
return 0 unless species_data
|
||||
|
||||
level = pkmn.level
|
||||
level_diff = compare_level ? (level - compare_level) : 0
|
||||
level_score = level * 2 + [level_diff, 0].max * 1.5 # bonus if player's level is higher
|
||||
|
||||
base_stats_score = species_data.base_stats.values.sum / 10.0
|
||||
rarity_score = (255 - species_data.catch_rate) / 5.0
|
||||
iv_score = (pkmn.iv&.values&.sum || 0) / 4.0
|
||||
shiny_score = pkmn.shiny? ? 50 : 0
|
||||
fusion_bonus = pkmn.isFusion? ? 40 : 0
|
||||
|
||||
score = level_score +
|
||||
base_stats_score +
|
||||
rarity_score +
|
||||
iv_score +
|
||||
shiny_score +
|
||||
fusion_bonus
|
||||
|
||||
echoln("#{pkmn.name} - Score : #{score}")
|
||||
return score
|
||||
end
|
||||
|
||||
|
||||
|
||||
def offerPokemonForTrade(player_pokemon, npc_party, trainer_class)
|
||||
player_score = evaluate_pokemon_worth(player_pokemon)
|
||||
pickiness = TRAINER_CLASS_PICKINESS[trainer_class] || 1.0
|
||||
|
||||
# Evaluate all NPC Pokémon scores
|
||||
npc_scores = npc_party.map do |npc_pkmn|
|
||||
[npc_pkmn, evaluate_pokemon_worth(npc_pkmn, compare_level: player_pokemon.level)]
|
||||
end
|
||||
best_npc_pokemon, best_score = npc_scores.max_by { |_, score| score }
|
||||
return best_npc_pokemon if player_score > best_score
|
||||
|
||||
max_difference = [player_score, 100].min * pickiness
|
||||
candidates = npc_scores.select do |npc_pkmn, npc_score|
|
||||
(npc_score - player_score).abs <= max_difference
|
||||
end
|
||||
|
||||
return nil if candidates.empty?
|
||||
candidates.min_by do |_, npc_score|
|
||||
(npc_score - player_score).abs
|
||||
end.first
|
||||
end
|
||||
|
||||
def doNPCTrainerTrade(trainer)
|
||||
echoln trainer.getTimeSinceLastTrade
|
||||
if trainer.isNextTradeReady?
|
||||
pbMessage(_INTL("The trainer is not ready to trade yet. Wait a little bit before you make your offer."))
|
||||
return trainer
|
||||
end
|
||||
return generateTrainerTradeOffer(trainer)
|
||||
end
|
||||
|
||||
#prefered type depends on the trainer class
|
||||
#
|
||||
def generateTrainerTradeOffer(trainer)
|
||||
bg_image_id=20
|
||||
wanted_type = trainer.favorite_type
|
||||
wanted_type = :NORMAL if !wanted_type
|
||||
|
||||
wanted_type_name = GameData::Type.get(wanted_type).real_name
|
||||
trainerClassName = GameData::TrainerType.get(trainer.trainerType).real_name
|
||||
pbMessage(_INTL("#{trainerClassName} #{trainer.trainerName} is looking for \\C[1]#{wanted_type_name}-type Pokémon\\C[0]. Which Pokémon do you want to trade?."),)
|
||||
pbChoosePokemon(1,2,
|
||||
proc {|pokemon|
|
||||
pokemon.hasType?(wanted_type)
|
||||
})
|
||||
|
||||
chosen_index = pbGet(1)
|
||||
echoln pbGet(1)
|
||||
if chosen_index && chosen_index >= 0
|
||||
chosen_pokemon = $Trainer.party[chosen_index]
|
||||
offered_pokemon = offerPokemonForTrade(chosen_pokemon,trainer.currentTeam,trainer.trainerType)
|
||||
if !offered_pokemon
|
||||
pbMessage(_INTL("#{trainerClassName} #{trainer.trainerName} does not want to trade..."))
|
||||
return trainer
|
||||
end
|
||||
|
||||
pif_sprite = BattleSpriteLoader.new.get_pif_sprite_from_species(offered_pokemon.species)
|
||||
pif_sprite.dump_info()
|
||||
|
||||
message = _INTL("#{trainerClassName} #{trainer.trainerName} is offering #{offered_pokemon.name} (Level #{offered_pokemon.level}) for your #{chosen_pokemon.name}.")
|
||||
showPokemonInPokeballWithMessage(pif_sprite, message)
|
||||
|
||||
if pbConfirmMessage(_INTL("Trade away #{chosen_pokemon.name} for #{trainerClassName} #{trainer.trainerName}'s #{offered_pokemon.name}?"))
|
||||
pbStartTrade(chosen_index, offered_pokemon,offered_pokemon.name,trainer.trainerName,0)
|
||||
updated_party = trainer.currentTeam
|
||||
updated_party.delete(offered_pokemon)
|
||||
updated_party << chosen_pokemon.clone
|
||||
trainer.previous_trade_timestamp= Time.now
|
||||
trainer.increase_friendship(20)
|
||||
return trainer
|
||||
end
|
||||
end
|
||||
return trainer
|
||||
|
||||
#todo
|
||||
#
|
||||
# NPC says "I'm looking for X or Y tyflpe Pokemon (prefered Pokemon can be determined when initializing from a pool of types that depends on the trainer class)
|
||||
# Also possible to pass a list of specific Pokemon in trainers.txt that the trainer will ask for instead if it's defined
|
||||
#
|
||||
# you select one of your Pokemon and he gives you one for it
|
||||
# prioritize recently caught pokemon
|
||||
# prioritive weaker Pokemon
|
||||
#
|
||||
#Assign a score to each Pokemon in trainer's team. calculate the same score for trainer's pokemon - select which
|
||||
# one is closer
|
||||
#
|
||||
# NPC says "I can offer A in exchange for your B.
|
||||
# -Yes -> Trade, update trainer team to put the player's pokemon in there
|
||||
# Cannot trade again with the same trainer for 5 minutes
|
||||
# "You just traded with this trainer. Wait a bit before you make another offer
|
||||
# -No
|
||||
trainer.set_pending_action(false) if trainer
|
||||
return trainer
|
||||
end
|
||||
162
Data/Scripts/053_PIF_Hoenn/WeatherSystem/Configuration.rb
Normal file
162
Data/Scripts/053_PIF_Hoenn/WeatherSystem/Configuration.rb
Normal file
@@ -0,0 +1,162 @@
|
||||
# #===============================================================================
|
||||
# # * Weather System Configuration
|
||||
# #===============================================================================
|
||||
#
|
||||
# module WeatherConfig
|
||||
# # Set to false to use the Weather System.
|
||||
# NO_WEATHER = false # Default: false
|
||||
#
|
||||
# # Set to true to show the weather on the Town Map.
|
||||
# SHOW_WEATHER_ON_MAP = true # Default: true
|
||||
#
|
||||
# # Set to true to use the computer's time. Will not work without Unreal Time System.
|
||||
# USE_REAL_TIME = true # Default: true
|
||||
#
|
||||
# # Set to true to have the weather change at midnight.
|
||||
# CHANGE_MIDNIGHT = true # Default: true
|
||||
#
|
||||
# # Define the min and max amount of time (in hours) before the weather changes.
|
||||
# # Set the same number to not randomize the amount of time before the weather changes.
|
||||
# CHANGE_TIME_MIN = 1 # Default: 1
|
||||
# CHANGE_TIME_MAX = 4 # Default: 4
|
||||
#
|
||||
# # Set to true to if you want to force the weather to change when interacting with certain events.
|
||||
# # Use pbForceUpdateWeather in an event to update all zone weathers.
|
||||
# # Use pbForceUpdateZoneWeather(zone) in an event to update the weather of a zone.
|
||||
# FORCE_UPDATE = true # Default: false
|
||||
#
|
||||
# # Set to true to have the outdoor maps change with seasons.
|
||||
# # The map's appearance will update when leaving an indoor map.
|
||||
# SEASON_CHANGE = false # Default: false
|
||||
#
|
||||
# # Set to true if your game starts outdoors and want to show the season splash when going somewhere indoors.
|
||||
# # Set to false if your game starts indoors and want to show the season splash when going somewhere outdoors.
|
||||
# OUTDOOR = false # Default: false
|
||||
#
|
||||
# # Array with the ID of outside tilesets that will change with seasons.
|
||||
# OUTDOOR_TILESETS = []
|
||||
#
|
||||
# # The difference between the ID of the tileset defined for an outdoor map and it's season version.
|
||||
# # The difference has to be the same for any tileset defined in OUTDOOR_TILESETS.
|
||||
# # Use the same season tileset as the default outdoor map tileset and define the diference for that season as 0.
|
||||
# SUMMER_TILESET = 22
|
||||
# AUTUMN_TILESET = 24
|
||||
# WINTER_TILESET = 26
|
||||
# SPRING_TILESET = 0
|
||||
#
|
||||
# #===============================================================================
|
||||
# # * Weather Substitute
|
||||
# #===============================================================================
|
||||
# # A hash with the ID of the maps that will have or not have certain weathers.
|
||||
# # The ID of the weather has to be of the main one you want to change with WEATHER_SUBSTITUTE.
|
||||
# # Use "exclude" to define a list of maps that will not use that weather when it's the main one.
|
||||
# # Any maps of a zone not added on the "exclude" list will use the main weather.
|
||||
# # Use "include" to define a list of maps that will use that weather when it's the main one.
|
||||
# # Any maps of a zone not added on the "include" list will use the secondary weather.
|
||||
# MAPS_SUBSTITUTE = {
|
||||
# :Snow => ["exclude", 1, 4],
|
||||
# :Blizzard => ["exclude", 1, 4],
|
||||
# :Sandstorm => ["include", 5]
|
||||
# }
|
||||
#
|
||||
# # The ID of the weathers that will substitute the main when appropiate (conditions defined in MAPS_SUBSTITUTE).
|
||||
# # There has to be a hash (defined between {}) for each defined zone with weather to substitute.
|
||||
# # Any weather not defined in the hash for a zone will use the main weather instead.
|
||||
# WEATHER_SUBSTITUTE = [
|
||||
# {:None => :None, :Rain => :Rain, :Storm => :Storm, :Snow => :Rain, :Blizzard => :Storm, :Sandstorm => :None, :HeavyRain => :HeavyRain, :Sun => :Sun, :Fog => :Fog},
|
||||
# {:Snow => :Rain, :Blizzard => :Storm, :Sandstorm => :None},
|
||||
# {:Snow => :Rain, :Blizzard => :HeavyRain}
|
||||
# ]
|
||||
#
|
||||
# #===============================================================================
|
||||
# # * Weather Names
|
||||
# #===============================================================================
|
||||
# # A hash that contains the ID of weather and the name to display for each one.
|
||||
# # Using .downcase will make them lowercase.
|
||||
# def self.weather_names
|
||||
# return {
|
||||
# :None => _INTL("None"),
|
||||
# :Rain => _INTL("Rain"),
|
||||
# :Storm => _INTL("Storm"),
|
||||
# :Snow => _INTL("Snow"),
|
||||
# :Blizzard => _INTL("Blizzard"),
|
||||
# :Sandstorm => _INTL("Sandstorm"),
|
||||
# :HeavyRain => _INTL("Heavy rain"),
|
||||
# :Sun => _INTL("Sun"),
|
||||
# :Fog => _INTL("Fog")
|
||||
# }
|
||||
# end
|
||||
# #===============================================================================
|
||||
# # * Zones Configuration
|
||||
# #===============================================================================
|
||||
# # Arrays of id of the maps of each zone. Each array within the main array is a zone.
|
||||
# # The maps within each zone will have the same weather at the same time.
|
||||
# # Each zone may have a different weather than the others.
|
||||
# ZONE_MAPS = [
|
||||
# [9, 5, 8, 11],#Littleroot-Oldale
|
||||
# [10, 2, 12], #Petalburg
|
||||
# ]
|
||||
# #===============================================================================
|
||||
# # * Map Display
|
||||
# #===============================================================================
|
||||
# # Array of hashes to get each map's position in the Town Map. Each hash corresponds to a zone in ZONE_MAPS.
|
||||
# # In "Map Name" you have to put the name the Town Map displays for that point.
|
||||
# # In Map ID you have to put the ID of the map the name corresponds to, like in ZONE_MAPS.
|
||||
# MAPS_POSITIONS = [
|
||||
# #{"Map Name" => Map ID},
|
||||
# {"Littleroot Town" => 9, "Route 101" => 5, "Oldale Town" => 8, "Route 103" => 11},
|
||||
# {"Route 102" => 10, "Petalburg Town" => 2, "Route 103" => 12},
|
||||
# ]
|
||||
#
|
||||
# # A hash for the plugin to display the proper weather image on the map.
|
||||
# # They have to be on Graphics/Pictures/Weather (in 20+) or Graphics/UI/Weather (in 21+).
|
||||
# WEATHER_IMAGE = {
|
||||
# :Rain => "mapRain",
|
||||
# :Storm => "mapStorm",
|
||||
# :Snow => "mapSnow",
|
||||
# :Blizzard => "mapBlizzard",
|
||||
# :Sandstorm => "mapSand",
|
||||
# :HeavyRain => "mapRain",
|
||||
# :Sun => "mapSun",
|
||||
# :Fog => "mapFog"
|
||||
# }
|
||||
# #===============================================================================
|
||||
# # * Season Probability Configuration
|
||||
# #===============================================================================
|
||||
# # Arrays of probability of weather for each zone in the different seasons.
|
||||
# # Each array within the main array corresponds to a zone in ZONE_MAPS.
|
||||
# # Put 0 to weather you don't want if you define a probability after it.
|
||||
# # If your game doesn't use seasons, edit the probabilities of one season and copy it to the others.
|
||||
#
|
||||
# # Probability of weather in summer.
|
||||
# # Order: None, Rain, Storm, Snow, Blizzard, Sandstorm, HeavyRain, Sun/Sunny, Fog
|
||||
# ZONE_WEATHER_SUMMER = [
|
||||
# [50, 20, 3, 0, 0, 0, 5, 30],
|
||||
# [40, 50],
|
||||
# [60]
|
||||
# ]
|
||||
#
|
||||
# # Probability of weather in autumn.
|
||||
# # Order: None, Rain, Storm, Snow, Blizzard, Sandstorm, HeavyRain, Sun/Sunny, Fog
|
||||
# ZONE_WEATHER_AUTUMN = [
|
||||
# [50, 20, 3, 0, 0, 0, 5, 30],
|
||||
# [40, 50],
|
||||
# [60]
|
||||
# ]
|
||||
#
|
||||
# # Probability of weather in winter.
|
||||
# # Order: None, Rain, Storm, Snow, Blizzard, Sandstorm, HeavyRain, Sun/Sunny, Fog
|
||||
# ZONE_WEATHER_WINTER = [
|
||||
# [50, 20, 3, 0, 0, 0, 5, 30],
|
||||
# [40, 50],
|
||||
# [60]
|
||||
# ]
|
||||
#
|
||||
# # Probability of weather in spring.
|
||||
# # Order: None, Rain, Storm, Snow, Blizzard, Sandstorm, HeavyRain, Sun/Sunny, Fog
|
||||
# ZONE_WEATHER_SPRING = [
|
||||
# [50, 20, 3, 0, 0, 0, 5, 30],
|
||||
# [40, 50],
|
||||
# [60]
|
||||
# ]
|
||||
# end
|
||||
Reference in New Issue
Block a user