diff --git a/Data/Scripts/010_Data/001_GameData.rb b/Data/Scripts/010_Data/001_GameData.rb index eacfaf053..209cec07c 100644 --- a/Data/Scripts/010_Data/001_GameData.rb +++ b/Data/Scripts/010_Data/001_GameData.rb @@ -246,24 +246,34 @@ module GameData # A bulk loader method for all data stored in .dat files in the Data folder. #============================================================================= def self.load_all - TownMap.load - Type.load - Ability.load - Move.load - Item.load - BerryPlant.load - Species.load - SpeciesMetrics.load - ShadowPokemon.load - Ribbon.load - Encounter.load - TrainerType.load - Trainer.load - Metadata.load - PlayerMetadata.load - MapMetadata.load - DungeonTileset.load - DungeonParameters.load - PhoneMessage.load + self.constants.each do |c| + next if !self.const_get(c).is_a?(Class) + self.const_get(c).load if self.const_get(c).const_defined?(:DATA_FILENAME) + end + end + + def self.get_all_data_filenames + ret = [] + self.constants.each do |c| + next if !self.const_get(c).is_a?(Class) + ret.push(self.const_get(c)::DATA_FILENAME) if self.const_get(c).const_defined?(:DATA_FILENAME) + end + return ret + end + + def self.get_all_pbs_base_filenames + ret = {} + self.constants.each do |c| + next if !self.const_get(c).is_a?(Class) + ret[c] = self.const_get(c)::PBS_BASE_FILENAME if self.const_get(c).const_defined?(:PBS_BASE_FILENAME) + if ret[c].is_a?(Array) + ret[c].length.times do |i| + next if i == 0 + ret[(c.to_s + i.to_s).to_sym] = ret[c][i] # :Species1 => "pokemon_forms" + end + ret[c] = ret[c][0] # :Species => "pokemon" + end + end + return ret end end diff --git a/Data/Scripts/010_Data/002_PBS data/002_TownMap.rb b/Data/Scripts/010_Data/002_PBS data/002_TownMap.rb index a11d850a1..53b1996ae 100644 --- a/Data/Scripts/010_Data/002_PBS data/002_TownMap.rb +++ b/Data/Scripts/010_Data/002_PBS data/002_TownMap.rb @@ -5,9 +5,11 @@ module GameData attr_reader :filename attr_reader :point attr_reader :flags + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "town_map.dat" + PBS_BASE_FILENAME = "town_map" SCHEMA = { "SectionName" => [:id, "u"], @@ -21,11 +23,12 @@ module GameData include InstanceMethods def initialize(hash) - @id = hash[:id] - @real_name = hash[:real_name] || "???" - @filename = hash[:filename] - @point = hash[:point] || [] - @flags = hash[:flags] || [] + @id = hash[:id] + @real_name = hash[:real_name] || "???" + @filename = hash[:filename] + @point = hash[:point] || [] + @flags = hash[:flags] || [] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end # @return [String] the translated name of this region diff --git a/Data/Scripts/010_Data/002_PBS data/003_Type.rb b/Data/Scripts/010_Data/002_PBS data/003_Type.rb index 0270b9c16..7ea0662c1 100644 --- a/Data/Scripts/010_Data/002_PBS data/003_Type.rb +++ b/Data/Scripts/010_Data/002_PBS data/003_Type.rb @@ -9,9 +9,11 @@ module GameData attr_reader :resistances attr_reader :immunities attr_reader :flags + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "types.dat" + PBS_BASE_FILENAME = "types" SCHEMA = { "SectionName" => [:id, "m"], @@ -29,18 +31,19 @@ module GameData include InstanceMethods def initialize(hash) - @id = hash[:id] - @real_name = hash[:real_name] || "Unnamed" - @icon_position = hash[:icon_position] || 0 - @special_type = hash[:special_type] || false - @pseudo_type = hash[:pseudo_type] || false - @weaknesses = hash[:weaknesses] || [] - @weaknesses = [@weaknesses] if !@weaknesses.is_a?(Array) - @resistances = hash[:resistances] || [] - @resistances = [@resistances] if !@resistances.is_a?(Array) - @immunities = hash[:immunities] || [] - @immunities = [@immunities] if !@immunities.is_a?(Array) - @flags = hash[:flags] || [] + @id = hash[:id] + @real_name = hash[:real_name] || "Unnamed" + @icon_position = hash[:icon_position] || 0 + @special_type = hash[:special_type] || false + @pseudo_type = hash[:pseudo_type] || false + @weaknesses = hash[:weaknesses] || [] + @weaknesses = [@weaknesses] if !@weaknesses.is_a?(Array) + @resistances = hash[:resistances] || [] + @resistances = [@resistances] if !@resistances.is_a?(Array) + @immunities = hash[:immunities] || [] + @immunities = [@immunities] if !@immunities.is_a?(Array) + @flags = hash[:flags] || [] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end # @return [String] the translated name of this item diff --git a/Data/Scripts/010_Data/002_PBS data/004_Ability.rb b/Data/Scripts/010_Data/002_PBS data/004_Ability.rb index 182ea2deb..3ac438a41 100644 --- a/Data/Scripts/010_Data/002_PBS data/004_Ability.rb +++ b/Data/Scripts/010_Data/002_PBS data/004_Ability.rb @@ -4,9 +4,11 @@ module GameData attr_reader :real_name attr_reader :real_description attr_reader :flags + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "abilities.dat" + PBS_BASE_FILENAME = "abilities" extend ClassMethodsSymbols include InstanceMethods @@ -23,6 +25,7 @@ module GameData @real_name = hash[:real_name] || "Unnamed" @real_description = hash[:real_description] || "???" @flags = hash[:flags] || [] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end # @return [String] the translated name of this ability diff --git a/Data/Scripts/010_Data/002_PBS data/005_Move.rb b/Data/Scripts/010_Data/002_PBS data/005_Move.rb index 7e0417a28..5a79f4e0a 100644 --- a/Data/Scripts/010_Data/002_PBS data/005_Move.rb +++ b/Data/Scripts/010_Data/002_PBS data/005_Move.rb @@ -14,9 +14,11 @@ module GameData attr_reader :flags attr_reader :effect_chance attr_reader :real_description + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "moves.dat" + PBS_BASE_FILENAME = "moves" SCHEMA = { "SectionName" => [:id, "m"], @@ -53,6 +55,7 @@ module GameData @flags = [@flags] if !@flags.is_a?(Array) @effect_chance = hash[:effect_chance] || 0 @real_description = hash[:real_description] || "???" + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end # @return [String] the translated name of this move diff --git a/Data/Scripts/010_Data/002_PBS data/006_Item.rb b/Data/Scripts/010_Data/002_PBS data/006_Item.rb index a46b52055..e5796a4b5 100644 --- a/Data/Scripts/010_Data/002_PBS data/006_Item.rb +++ b/Data/Scripts/010_Data/002_PBS data/006_Item.rb @@ -12,9 +12,11 @@ module GameData attr_reader :consumable attr_reader :move attr_reader :real_description + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "items.dat" + PBS_BASE_FILENAME = "items" SCHEMA = { "SectionName" => [:id, "m"], @@ -95,6 +97,7 @@ module GameData @consumable = !is_important? if @consumable.nil? @move = hash[:move] @real_description = hash[:real_description] || "???" + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end # @return [String] the translated name of this item diff --git a/Data/Scripts/010_Data/002_PBS data/007_BerryPlant.rb b/Data/Scripts/010_Data/002_PBS data/007_BerryPlant.rb index 47490f4ad..365dc2f7c 100644 --- a/Data/Scripts/010_Data/002_PBS data/007_BerryPlant.rb +++ b/Data/Scripts/010_Data/002_PBS data/007_BerryPlant.rb @@ -4,9 +4,11 @@ module GameData attr_reader :hours_per_stage attr_reader :drying_per_hour attr_reader :yield + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "berry_plants.dat" + PBS_BASE_FILENAME = "berry_plants" SCHEMA = { "SectionName" => [:id, "m"], @@ -29,6 +31,7 @@ module GameData @drying_per_hour = hash[:drying_per_hour] || 15 @yield = hash[:yield] || [2, 5] @yield.reverse! if @yield[1] < @yield[0] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end def minimum_yield diff --git a/Data/Scripts/010_Data/002_PBS data/008_Species.rb b/Data/Scripts/010_Data/002_PBS data/008_Species.rb index 4c0b00998..7777a3a23 100644 --- a/Data/Scripts/010_Data/002_PBS data/008_Species.rb +++ b/Data/Scripts/010_Data/002_PBS data/008_Species.rb @@ -40,9 +40,11 @@ module GameData attr_reader :mega_move attr_reader :unmega_form attr_reader :mega_message + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "species.dat" + PBS_BASE_FILENAME = ["pokemon", "pokemon_forms"] extend ClassMethodsSymbols include InstanceMethods @@ -175,6 +177,7 @@ module GameData @mega_move = hash[:mega_move] @unmega_form = hash[:unmega_form] || 0 @mega_message = hash[:mega_message] || 0 + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end # @return [String] the translated name of this species diff --git a/Data/Scripts/010_Data/002_PBS data/010_SpeciesMetrics.rb b/Data/Scripts/010_Data/002_PBS data/010_SpeciesMetrics.rb index dc915efbe..87428a7fe 100644 --- a/Data/Scripts/010_Data/002_PBS data/010_SpeciesMetrics.rb +++ b/Data/Scripts/010_Data/002_PBS data/010_SpeciesMetrics.rb @@ -8,9 +8,11 @@ module GameData attr_accessor :front_sprite_altitude attr_accessor :shadow_x attr_accessor :shadow_size + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "species_metrics.dat" + PBS_BASE_FILENAME = "pokemon_metrics" SCHEMA = { "SectionName" => [:id, "eV", :Species], @@ -63,6 +65,7 @@ module GameData @front_sprite_altitude = hash[:front_sprite_altitude] || 0 @shadow_x = hash[:shadow_x] || 0 @shadow_size = hash[:shadow_size] || 2 + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end def apply_metrics_to_sprite(sprite, index, shadow = false) diff --git a/Data/Scripts/010_Data/002_PBS data/011_ShadowPokemon.rb b/Data/Scripts/010_Data/002_PBS data/011_ShadowPokemon.rb index 8cfe28db9..98891e119 100644 --- a/Data/Scripts/010_Data/002_PBS data/011_ShadowPokemon.rb +++ b/Data/Scripts/010_Data/002_PBS data/011_ShadowPokemon.rb @@ -4,9 +4,11 @@ module GameData attr_reader :moves attr_reader :gauge_size attr_reader :flags + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "shadow_pokemon.dat" + PBS_BASE_FILENAME = "shadow_pokemon" SCHEMA = { "SectionName" => [:id, "e", :Species], @@ -20,10 +22,11 @@ module GameData include InstanceMethods def initialize(hash) - @id = hash[:id] - @gauge_size = hash[:gauge_size] || HEART_GAUGE_SIZE - @moves = hash[:moves] || [] - @flags = hash[:flags] || [] + @id = hash[:id] + @gauge_size = hash[:gauge_size] || HEART_GAUGE_SIZE + @moves = hash[:moves] || [] + @flags = hash[:flags] || [] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end def has_flag?(flag) diff --git a/Data/Scripts/010_Data/002_PBS data/012_Ribbon.rb b/Data/Scripts/010_Data/002_PBS data/012_Ribbon.rb index d153c9cdc..90c0f058c 100644 --- a/Data/Scripts/010_Data/002_PBS data/012_Ribbon.rb +++ b/Data/Scripts/010_Data/002_PBS data/012_Ribbon.rb @@ -5,9 +5,11 @@ module GameData attr_reader :icon_position # Where this ribbon's graphic is within ribbons.png attr_reader :real_description attr_reader :flags + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "ribbons.dat" + PBS_BASE_FILENAME = "ribbons" SCHEMA = { "SectionName" => [:id, "m"], @@ -26,6 +28,7 @@ module GameData @icon_position = hash[:icon_position] || 0 @real_description = hash[:real_description] || "???" @flags = hash[:flags] || [] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end # @return [String] the translated name of this ribbon diff --git a/Data/Scripts/010_Data/002_PBS data/013_Encounter.rb b/Data/Scripts/010_Data/002_PBS data/013_Encounter.rb index 157ba26e8..e69d300dd 100644 --- a/Data/Scripts/010_Data/002_PBS data/013_Encounter.rb +++ b/Data/Scripts/010_Data/002_PBS data/013_Encounter.rb @@ -3,11 +3,13 @@ module GameData attr_accessor :id attr_accessor :map attr_accessor :version - attr_reader :step_chances - attr_reader :types + attr_reader :step_chances + attr_reader :types + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "encounters.dat" + PBS_BASE_FILENAME = "encounters" extend ClassMethodsSymbols include InstanceMethods @@ -58,11 +60,12 @@ module GameData end def initialize(hash) - @id = hash[:id] - @map = hash[:map] - @version = hash[:version] || 0 - @step_chances = hash[:step_chances] - @types = hash[:types] || {} + @id = hash[:id] + @map = hash[:map] + @version = hash[:version] || 0 + @step_chances = hash[:step_chances] + @types = hash[:types] || {} + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end end end diff --git a/Data/Scripts/010_Data/002_PBS data/014_TrainerType.rb b/Data/Scripts/010_Data/002_PBS data/014_TrainerType.rb index 1c2adca37..6254e03d7 100644 --- a/Data/Scripts/010_Data/002_PBS data/014_TrainerType.rb +++ b/Data/Scripts/010_Data/002_PBS data/014_TrainerType.rb @@ -9,9 +9,11 @@ module GameData attr_reader :intro_BGM attr_reader :battle_BGM attr_reader :victory_BGM + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "trainer_types.dat" + PBS_BASE_FILENAME = "trainer_types" SCHEMA = { "SectionName" => [:id, "m"], @@ -81,15 +83,16 @@ module GameData end def initialize(hash) - @id = hash[:id] - @real_name = hash[:real_name] || "Unnamed" - @gender = hash[:gender] || 2 - @base_money = hash[:base_money] || 30 - @skill_level = hash[:skill_level] || @base_money - @flags = hash[:flags] || [] - @intro_BGM = hash[:intro_BGM] - @battle_BGM = hash[:battle_BGM] - @victory_BGM = hash[:victory_BGM] + @id = hash[:id] + @real_name = hash[:real_name] || "Unnamed" + @gender = hash[:gender] || 2 + @base_money = hash[:base_money] || 30 + @skill_level = hash[:skill_level] || @base_money + @flags = hash[:flags] || [] + @intro_BGM = hash[:intro_BGM] + @battle_BGM = hash[:battle_BGM] + @victory_BGM = hash[:victory_BGM] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end # @return [String] the translated name of this trainer type diff --git a/Data/Scripts/010_Data/002_PBS data/015_Trainer.rb b/Data/Scripts/010_Data/002_PBS data/015_Trainer.rb index 82cce006a..ceebb4044 100644 --- a/Data/Scripts/010_Data/002_PBS data/015_Trainer.rb +++ b/Data/Scripts/010_Data/002_PBS data/015_Trainer.rb @@ -7,9 +7,11 @@ module GameData attr_reader :items attr_reader :real_lose_text attr_reader :pokemon + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "trainers.dat" + PBS_BASE_FILENAME = "trainers" SCHEMA = { "Items" => [:items, "*e", :Item], @@ -71,19 +73,20 @@ module GameData end def initialize(hash) - @id = hash[:id] - @trainer_type = hash[:trainer_type] - @real_name = hash[:name] || "Unnamed" - @version = hash[:version] || 0 - @items = hash[:items] || [] - @real_lose_text = hash[:lose_text] || "..." - @pokemon = hash[:pokemon] || [] + @id = hash[:id] + @trainer_type = hash[:trainer_type] + @real_name = hash[:name] || "Unnamed" + @version = hash[:version] || 0 + @items = hash[:items] || [] + @real_lose_text = hash[:lose_text] || "..." + @pokemon = hash[:pokemon] || [] @pokemon.each do |pkmn| GameData::Stat.each_main do |s| pkmn[:iv][s.id] ||= 0 if pkmn[:iv] pkmn[:ev][s.id] ||= 0 if pkmn[:ev] end end + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end # @return [String] the translated name of this trainer diff --git a/Data/Scripts/010_Data/002_PBS data/016_Metadata.rb b/Data/Scripts/010_Data/002_PBS data/016_Metadata.rb index 5f02f86df..b5afe9ea2 100644 --- a/Data/Scripts/010_Data/002_PBS data/016_Metadata.rb +++ b/Data/Scripts/010_Data/002_PBS data/016_Metadata.rb @@ -12,9 +12,11 @@ module GameData attr_reader :wild_capture_ME attr_reader :surf_BGM attr_reader :bicycle_BGM + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "metadata.dat" + PBS_BASE_FILENAME = "metadata" SCHEMA = { "SectionName" => [:id, "u"], @@ -67,11 +69,12 @@ module GameData @wild_capture_ME = hash[:wild_capture_ME] @surf_BGM = hash[:surf_BGM] @bicycle_BGM = hash[:bicycle_BGM] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end # @return [String] the translated name of the Pokémon Storage creator def storage_creator - ret = pbGetMessage(MessageTypes::StorageCreator, 0) + ret = pbGetMessageFromHash(MessageTypes::StorageCreator, @real_storage_creator) return nil_or_empty?(ret) ? _INTL("Bill") : ret end end diff --git a/Data/Scripts/010_Data/002_PBS data/017_PlayerMetadata.rb b/Data/Scripts/010_Data/002_PBS data/017_PlayerMetadata.rb index 6d2844d82..e6fa4df6d 100644 --- a/Data/Scripts/010_Data/002_PBS data/017_PlayerMetadata.rb +++ b/Data/Scripts/010_Data/002_PBS data/017_PlayerMetadata.rb @@ -4,6 +4,7 @@ module GameData attr_reader :trainer_type attr_reader :walk_charset attr_reader :home + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "player_metadata.dat" @@ -57,6 +58,7 @@ module GameData @fish_charset = hash[:fish_charset] @surf_fish_charset = hash[:surf_fish_charset] @home = hash[:home] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end def run_charset diff --git a/Data/Scripts/010_Data/002_PBS data/018_MapMetadata.rb b/Data/Scripts/010_Data/002_PBS data/018_MapMetadata.rb index 8ccba189e..96b3ebf28 100644 --- a/Data/Scripts/010_Data/002_PBS data/018_MapMetadata.rb +++ b/Data/Scripts/010_Data/002_PBS data/018_MapMetadata.rb @@ -23,9 +23,11 @@ module GameData attr_reader :town_map_size attr_reader :battle_environment attr_reader :flags + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "map_metadata.dat" + PBS_BASE_FILENAME = "map_metadata" SCHEMA = { "SectionName" => [:id, "u"], @@ -106,7 +108,8 @@ module GameData @wild_capture_ME = hash[:wild_capture_ME] @town_map_size = hash[:town_map_size] @battle_environment = hash[:battle_environment] - @flags = hash[:flags] || [] + @flags = hash[:flags] || [] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end # @return [String] the translated name of this map diff --git a/Data/Scripts/010_Data/002_PBS data/019_DungeonTileset.rb b/Data/Scripts/010_Data/002_PBS data/019_DungeonTileset.rb index 854a0d50d..4e0a511b8 100644 --- a/Data/Scripts/010_Data/002_PBS data/019_DungeonTileset.rb +++ b/Data/Scripts/010_Data/002_PBS data/019_DungeonTileset.rb @@ -10,9 +10,11 @@ module GameData attr_reader :floor_patch_under_walls attr_reader :thin_north_wall_offset attr_reader :flags + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "dungeon_tilesets.dat" + PBS_BASE_FILENAME = "dungeon_tilesets" SCHEMA = { "SectionName" => [:id, "u"], @@ -51,6 +53,7 @@ module GameData @flags = hash[:flags] || [] @tile_type_ids = {} set_tile_type_ids(hash) + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end def set_tile_type_ids(hash) diff --git a/Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb b/Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb index 91723de05..2da02c2b1 100644 --- a/Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb +++ b/Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb @@ -25,9 +25,11 @@ module GameData attr_reader :void_decoration_density, :void_decoration_large_density attr_reader :rng_seed attr_reader :flags + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "dungeon_parameters.dat" + PBS_BASE_FILENAME = "dungeon_parameters" SCHEMA = { "SectionName" => [:id, "mV"], @@ -67,7 +69,7 @@ module GameData def initialize(hash) @id = hash[:id] @area = hash[:area] - @version = hash[:version] || 0 + @version = hash[:version] || 0 @cell_count_x = (hash[:dungeon_size]) ? hash[:dungeon_size][0] : 5 @cell_count_y = (hash[:dungeon_size]) ? hash[:dungeon_size][1] : 5 @cell_width = (hash[:cell_size]) ? hash[:cell_size][0] : 10 @@ -76,11 +78,11 @@ module GameData @room_min_height = (hash[:min_room_size]) ? hash[:min_room_size][1] : 5 @room_max_width = (hash[:max_room_size]) ? hash[:max_room_size][0] : @cell_width - 1 @room_max_height = (hash[:max_room_size]) ? hash[:max_room_size][1] : @cell_height - 1 - @corridor_width = hash[:corridor_width] || 2 + @corridor_width = hash[:corridor_width] || 2 @random_corridor_shift = hash[:random_corridor_shift] - @node_layout = hash[:node_layout] || :full - @room_layout = hash[:room_layout] || :full - @room_chance = hash[:room_chance] || 70 + @node_layout = hash[:node_layout] || :full + @room_layout = hash[:room_layout] || :full + @room_chance = hash[:room_chance] || 70 @extra_connections_count = hash[:extra_connections_count] || 2 @floor_patch_radius = (hash[:floor_patches]) ? hash[:floor_patches][0] : 3 @floor_patch_chance = (hash[:floor_patches]) ? hash[:floor_patches][1] : 75 @@ -90,7 +92,8 @@ module GameData @void_decoration_density = (hash[:void_decorations]) ? hash[:void_decorations][0] : 50 @void_decoration_large_density = (hash[:void_decorations]) ? hash[:void_decorations][1] : 200 @rng_seed = hash[:rng_seed] - @flags = hash[:flags] || [] + @flags = hash[:flags] || [] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end def has_flag?(flag) diff --git a/Data/Scripts/010_Data/002_PBS data/021_PhoneMessage.rb b/Data/Scripts/010_Data/002_PBS data/021_PhoneMessage.rb index 2a5dcb27d..5c1b7bda1 100644 --- a/Data/Scripts/010_Data/002_PBS data/021_PhoneMessage.rb +++ b/Data/Scripts/010_Data/002_PBS data/021_PhoneMessage.rb @@ -6,9 +6,11 @@ module GameData attr_reader :body, :body1, :body2 attr_reader :battle_request, :battle_remind attr_reader :end + attr_reader :pbs_file_suffix DATA = {} DATA_FILENAME = "phone.dat" + PBS_BASE_FILENAME = "phone" SCHEMA = { "SectionName" => [:id, "q"], @@ -16,9 +18,9 @@ module GameData "IntroMorning" => [:intro_morning, "^q"], "IntroAfternoon" => [:intro_afternoon, "^q"], "IntroEvening" => [:intro_evening, "^q"], + "Body" => [:body, "^q"], "Body1" => [:body1, "^q"], "Body2" => [:body2, "^q"], - "Body" => [:body, "^q"], "BattleRequest" => [:battle_request, "^q"], "BattleRemind" => [:battle_remind, "^q"], "End" => [:end, "^q"] @@ -71,7 +73,7 @@ module GameData @id = hash[:id] @trainer_type = hash[:trainer_type] @real_name = hash[:real_name] - @version = hash[:version] || 0 + @version = hash[:version] || 0 @intro = hash[:intro] @intro_morning = hash[:intro_morning] @intro_afternoon = hash[:intro_afternoon] @@ -82,6 +84,7 @@ module GameData @battle_request = hash[:battle_request] @battle_remind = hash[:battle_remind] @end = hash[:end] + @pbs_file_suffix = hash[:pbs_file_suffix] || "" end alias __orig__get_property_for_PBS get_property_for_PBS unless method_defined?(:__orig__get_property_for_PBS) diff --git a/Data/Scripts/020_Debug/001_Editor screens/001_EditorScreens.rb b/Data/Scripts/020_Debug/001_Editor screens/001_EditorScreens.rb index fbfe37d17..5f3cbf0a5 100644 --- a/Data/Scripts/020_Debug/001_Editor screens/001_EditorScreens.rb +++ b/Data/Scripts/020_Debug/001_Editor screens/001_EditorScreens.rb @@ -77,11 +77,12 @@ def pbEncountersEditor # Construct encounter hash key = sprintf("%s_%d", new_map_ID, new_version).to_sym encounter_hash = { - :id => key, - :map => new_map_ID, - :version => new_version, - :step_chances => {}, - :types => {} + :id => key, + :map => new_map_ID, + :version => new_version, + :step_chances => {}, + :types => {}, + :pbs_file_suffix => GameData::Encounter.get(this_set[0], this_set[1]).pbs_file_suffix } GameData::Encounter.get(this_set[0], this_set[1]).step_chances.each do |type, value| encounter_hash[:step_chances][type] = value @@ -384,15 +385,16 @@ def pbTrainerTypeEditor if pbPropertyList(t_data.id.to_s, data, trainer_type_properties, true) # Construct trainer type hash type_hash = { - :id => t_data.id, - :name => data[1], - :gender => data[2], - :base_money => data[3], - :skill_level => data[4], - :flags => data[5], - :intro_BGM => data[6], - :battle_BGM => data[7], - :victory_BGM => data[8] + :id => t_data.id, + :name => data[1], + :gender => data[2], + :base_money => data[3], + :skill_level => data[4], + :flags => data[5], + :intro_BGM => data[6], + :battle_BGM => data[7], + :victory_BGM => data[8], + :pbs_file_suffix => t_data.pbs_file_suffix } # Add trainer type's data to records GameData::TrainerType.register(type_hash) @@ -543,12 +545,13 @@ def pbTrainerBattleEditor pbMessage(_INTL("Can't save. The Pokémon list is empty.")) else trainer_hash = { - :trainer_type => data[0], - :name => data[1], - :version => data[2], - :lose_text => data[3], - :pokemon => party, - :items => items + :trainer_type => data[0], + :name => data[1], + :version => data[2], + :lose_text => data[3], + :pokemon => party, + :items => items, + :pbs_file_suffix => tr_data.pbs_file_suffix } # Add trainer type's data to records trainer_hash[:id] = [trainer_hash[:trainer_type], trainer_hash[:name], trainer_hash[:version]] @@ -750,7 +753,8 @@ def pbEditMetadata :trainer_victory_BGM => data[7], :wild_capture_ME => data[8], :surf_BGM => data[9], - :bicycle_BGM => data[10] + :bicycle_BGM => data[10], + :pbs_file_suffix => metadata.pbs_file_suffix } # Add metadata's data to records GameData::Metadata.register(metadata_hash) @@ -794,7 +798,8 @@ def pbEditPlayerMetadata(player_id = 1) :dive_charset => data[5], :fish_charset => data[6], :surf_fish_charset => data[7], - :home => data[8] + :home => data[8], + :pbs_file_suffix => metadata.pbs_file_suffix } # Add player metadata's data to records GameData::PlayerMetadata.register(metadata_hash) @@ -853,7 +858,8 @@ def pbEditMapMetadata(map_id) :wild_capture_ME => data[18], :town_map_size => data[19], :battle_environment => data[20], - :flags => data[21] + :flags => data[21], + :pbs_file_suffix => metadata.pbs_file_suffix } # Add map metadata's data to records GameData::MapMetadata.register(metadata_hash) @@ -916,18 +922,19 @@ def pbItemEditor if pbPropertyList(itm.id.to_s, data, item_properties, true) # Construct item hash item_hash = { - :id => itm.id, - :name => data[1], - :name_plural => data[2], - :pocket => data[3], - :price => data[4], - :sell_price => data[5], - :description => data[6], - :field_use => data[7], - :battle_use => data[8], - :consumable => data[9], - :flags => data[10], - :move => data[11] + :id => itm.id, + :name => data[1], + :name_plural => data[2], + :pocket => data[3], + :price => data[4], + :sell_price => data[5], + :description => data[6], + :field_use => data[7], + :battle_use => data[8], + :consumable => data[9], + :flags => data[10], + :move => data[11], + :pbs_file_suffix => itm.pbs_file_suffix } # Add item's data to records GameData::Item.register(item_hash) @@ -1146,7 +1153,8 @@ def pbPokemonEditor :shape => data[35], :habitat => data[36], :generation => data[37], - :flags => data[38] + :flags => data[38], + :pbs_file_suffix => spec.pbs_file_suffix } # Add species' data to records GameData::Species.register(species_hash) diff --git a/Data/Scripts/021_Compiler/001_Compiler.rb b/Data/Scripts/021_Compiler/001_Compiler.rb index 0f415c84e..ef4596a67 100644 --- a/Data/Scripts/021_Compiler/001_Compiler.rb +++ b/Data/Scripts/021_Compiler/001_Compiler.rb @@ -780,30 +780,57 @@ module Compiler Graphics.update end + def get_all_pbs_files_to_compile + # Get the GameData classes and their respective base PBS filenames + ret = GameData.get_all_pbs_base_filenames + ret.merge!({ + :BattleFacility => "battle_facility_lists", + :Connection => "map_connections", + :RegionalDex => "regional_dexes" + }) + ret.each { |key, val| ret[key] = [val] } # [base_filename, ["PBS/file.txt", etc.]] + # Look through all PBS files and match them to a GameData class based on + # their base filenames + text_files_keys = ret.keys.sort! { |a, b| ret[b][0].length <=> ret[a][0].length } + Dir.chdir("PBS/") do + Dir.glob("*.txt") do |f| + base_name = File.basename(f, ".txt") + text_files_keys.each do |key| + next if base_name != ret[key][0] && !f.start_with?(ret[key][0] + "_") + ret[key][1] ||= [] + ret[key][1].push("PBS/" + f) + break + end + end + end + return ret + end + def compile_pbs_files + text_files = get_all_pbs_files_to_compile modify_pbs_file_contents_before_compiling - compile_town_map - compile_connections - compile_types - compile_abilities - compile_moves # Depends on Type - compile_items # Depends on Move - compile_berry_plants # Depends on Item - compile_pokemon # Depends on Move, Item, Type, Ability - compile_pokemon_forms # Depends on Species, Move, Item, Type, Ability - compile_pokemon_metrics # Depends on Species - compile_shadow_pokemon # Depends on Species - compile_regional_dexes # Depends on Species - compile_ribbons - compile_encounters # Depends on Species - compile_trainer_types - compile_trainers # Depends on Species, Item, Move - compile_trainer_lists # Depends on TrainerType - compile_metadata # Depends on TrainerType - compile_map_metadata - compile_dungeon_tilesets - compile_dungeon_parameters - compile_phone # Depends on TrainerType + compile_town_map(*text_files[:TownMap][1]) + compile_connections(*text_files[:Connection][1]) + compile_types(*text_files[:Type][1]) + compile_abilities(*text_files[:Ability][1]) + compile_moves(*text_files[:Move][1]) # Depends on Type + compile_items(*text_files[:Item][1]) # Depends on Move + compile_berry_plants(*text_files[:BerryPlant][1]) # Depends on Item + compile_pokemon(*text_files[:Species][1]) # Depends on Move, Item, Type, Ability + compile_pokemon_forms(*text_files[:Species1][1]) # Depends on Species, Move, Item, Type, Ability + compile_pokemon_metrics(*text_files[:SpeciesMetrics][1]) # Depends on Species + compile_shadow_pokemon(*text_files[:ShadowPokemon][1]) # Depends on Species + compile_regional_dexes(*text_files[:RegionalDex][1]) # Depends on Species + compile_ribbons(*text_files[:Ribbon][1]) + compile_encounters(*text_files[:Encounter][1]) # Depends on Species + compile_trainer_types(*text_files[:TrainerType][1]) + compile_trainers(*text_files[:Trainer][1]) # Depends on Species, Item, Move + compile_trainer_lists # Depends on TrainerType + compile_metadata(*text_files[:Metadata][1]) # Depends on TrainerType + compile_map_metadata(*text_files[:MapMetadata][1]) + compile_dungeon_tilesets(*text_files[:DungeonTileset][1]) + compile_dungeon_parameters(*text_files[:DungeonParameters][1]) + compile_phone(*text_files[:PhoneMessage][1]) # Depends on TrainerType end def compile_all(mustCompile) @@ -831,54 +858,14 @@ module Compiler def main return if !$DEBUG begin - dataFiles = [ - "abilities.dat", - "berry_plants.dat", - "dungeon_parameters.dat", - "dungeon_tilesets.dat", - "encounters.dat", - "items.dat", + # Get all data files and PBS files to be checked for their last modified times + data_files = GameData.get_all_data_filenames + data_files += [ # Extra .dat files for data that isn't a GameData class "map_connections.dat", - "map_metadata.dat", - "metadata.dat", - "moves.dat", - "phone.dat", - "player_metadata.dat", "regional_dexes.dat", - "ribbons.dat", - "shadow_pokemon.dat", - "species.dat", - "species_metrics.dat", - "town_map.dat", - "trainer_lists.dat", - "trainer_types.dat", - "trainers.dat", - "types.dat" - ] - textFiles = [ - "abilities.txt", - "battle_facility_lists.txt", - "berry_plants.txt", - "dungeon_parameters.txt", - "dungeon_tilesets.txt", - "encounters.txt", - "items.txt", - "map_connections.txt", - "map_metadata.txt", - "metadata.txt", - "moves.txt", - "phone.txt", - "pokemon.txt", - "pokemon_forms.txt", - "pokemon_metrics.txt", - "regional_dexes.txt", - "ribbons.txt", - "shadow_pokemon.txt", - "town_map.txt", - "trainer_types.txt", - "trainers.txt", - "types.txt" + "trainer_lists.dat" ] + text_files = get_all_pbs_files_to_compile latestDataTime = 0 latestTextTime = 0 mustCompile = false @@ -891,9 +878,8 @@ module Compiler write_all mustCompile = true end - # Check data files and PBS files, and recompile if any PBS file was edited - # more recently than the data files were last created - dataFiles.each do |filename| + # Check data files for their latest modify time + data_files.each do |filename| if safeExists?("Data/" + filename) begin File.open("Data/#{filename}") { |file| @@ -907,24 +893,26 @@ module Compiler break end end - textFiles.each do |filename| - next if !safeExists?("PBS/" + filename) - begin - File.open("PBS/#{filename}") { |file| - latestTextTime = [latestTextTime, file.mtime.to_i].max - } - rescue SystemCallError + # Check PBS files for their latest modify time + text_files.each do |key, value| + next if !value || !value[1].is_a?(Array) + value[1].each do |filepath| + begin + File.open(filepath) { |file| latestTextTime = [latestTextTime, file.mtime.to_i].max } + rescue SystemCallError + end end end + # Decide to compile if a PBS file was edited more recently than any .dat files mustCompile |= (latestTextTime >= latestDataTime) # Should recompile if holding Ctrl Input.update mustCompile = true if Input.press?(Input::CTRL) # Delete old data files in preparation for recompiling if mustCompile - dataFiles.length.times do |i| + data_files.length.times do |i| begin - File.delete("Data/#{dataFiles[i]}") if safeExists?("Data/#{dataFiles[i]}") + File.delete("Data/#{data_files[i]}") if safeExists?("Data/#{data_files[i]}") rescue SystemCallError end end @@ -935,9 +923,9 @@ module Compiler e = $! raise e if e.class.to_s == "Reset" || e.is_a?(Reset) || e.is_a?(SystemExit) pbPrintException(e) - dataFiles.length.times do |i| + data_files.length.times do |i| begin - File.delete("Data/#{dataFiles[i]}") + File.delete("Data/#{data_files[i]}") rescue SystemCallError end end diff --git a/Data/Scripts/021_Compiler/002_Compiler_CompilePBS.rb b/Data/Scripts/021_Compiler/002_Compiler_CompilePBS.rb index 9dd7d2da1..168a590d8 100644 --- a/Data/Scripts/021_Compiler/002_Compiler_CompilePBS.rb +++ b/Data/Scripts/021_Compiler/002_Compiler_CompilePBS.rb @@ -1,66 +1,74 @@ module Compiler module_function - def compile_PBS_file_generic(game_data, path) - compile_pbs_file_message_start(path) + def compile_PBS_file_generic(game_data, *paths) game_data::DATA.clear - # Read from PBS file - File.open(path, "rb") { |f| - FileLineData.file = path # For error reporting - # Read a whole section's lines at once, then run through this code. - # contents is a hash containing all the XXX=YYY lines in that section, where - # the keys are the XXX and the values are the YYY (as unprocessed strings). - schema = game_data.schema - idx = 0 - pbEachFileSection(f, schema) { |contents, section_name| - echo "." if idx % 50 == 0 - Graphics.update if idx % 250 == 0 - idx += 1 - data_hash = {:id => section_name.to_sym} - # Go through schema hash of compilable data and compile this section - schema.each_key do |key| - FileLineData.setSection(section_name, key, contents[key]) # For error reporting - if key == "SectionName" - data_hash[schema[key][0]] = pbGetCsvRecord(section_name, key, schema[key]) - next - end - # Skip empty properties - next if contents[key].nil? - # Compile value for key - if schema[key][1][0] == "^" - contents[key].each do |val| - value = pbGetCsvRecord(val, key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] ||= [] - data_hash[schema[key][0]].push(value) + schema = game_data.schema + # Read from PBS file(s) + paths.each do |path| + compile_pbs_file_message_start(path) + base_filename = game_data::PBS_BASE_FILENAME + base_filename = base_filename[0] if base_filename.is_a?(Array) # For Species + file_suffix = File.basename(path, ".txt")[base_filename.length + 1, path.length] || "" + File.open(path, "rb") { |f| + FileLineData.file = path # For error reporting + # Read a whole section's lines at once, then run through this code. + # contents is a hash containing all the XXX=YYY lines in that section, where + # the keys are the XXX and the values are the YYY (as unprocessed strings). + idx = 0 + pbEachFileSection(f, schema) { |contents, section_name| + echo "." if idx % 50 == 0 + Graphics.update if idx % 250 == 0 + idx += 1 + data_hash = { + :id => section_name.to_sym, + :pbs_file_suffix => file_suffix + } + # Go through schema hash of compilable data and compile this section + schema.each_key do |key| + FileLineData.setSection(section_name, key, contents[key]) # For error reporting + if key == "SectionName" + data_hash[schema[key][0]] = pbGetCsvRecord(section_name, key, schema[key]) + next + end + # Skip empty properties + next if contents[key].nil? + # Compile value for key + if schema[key][1][0] == "^" + contents[key].each do |val| + value = pbGetCsvRecord(val, key, schema[key]) + value = nil if value.is_a?(Array) && value.empty? + data_hash[schema[key][0]] ||= [] + data_hash[schema[key][0]].push(value) + end + data_hash[schema[key][0]].compact! + else + value = pbGetCsvRecord(contents[key], key, schema[key]) + value = nil if value.is_a?(Array) && value.empty? + data_hash[schema[key][0]] = value end - data_hash[schema[key][0]].compact! - else - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value end - end - # Validate and modify the compiled data - yield false, data_hash if block_given? - if game_data.exists?(data_hash[:id]) - raise _INTL("Section name '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add section's data to records - game_data.register(data_hash) + # Validate and modify the compiled data + yield false, data_hash if block_given? + if game_data.exists?(data_hash[:id]) + raise _INTL("Section name '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) + end + # Add section's data to records + game_data.register(data_hash) + } } - } + process_pbs_file_message_end + end yield true, nil if block_given? # Save all data game_data.save - process_pbs_file_message_end end #============================================================================= # Compile Town Map data #============================================================================= - def compile_town_map(path = "PBS/town_map.txt") - compile_PBS_file_generic(GameData::TownMap, path) do |final_validate, hash| + def compile_town_map(*paths) + compile_PBS_file_generic(GameData::TownMap, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_town_maps : validate_compiled_town_map(hash) end end @@ -90,51 +98,53 @@ module Compiler #============================================================================= # Compile map connections #============================================================================= - def compile_connections(path = "PBS/map_connections.txt") - compile_pbs_file_message_start(path) + def compile_connections(*paths) records = [] - pbCompilerEachPreppedLine(path) { |line, lineno| - hashenum = { - "N" => "N", "North" => "N", - "E" => "E", "East" => "E", - "S" => "S", "South" => "S", - "W" => "W", "West" => "W" + paths.each do |path| + compile_pbs_file_message_start(path) + pbCompilerEachPreppedLine(path) { |line, lineno| + hashenum = { + "N" => "N", "North" => "N", + "E" => "E", "East" => "E", + "S" => "S", "South" => "S", + "W" => "W", "West" => "W" + } + record = [] + thisline = line.dup + record.push(csvInt!(thisline, lineno)) + record.push(csvEnumFieldOrInt!(thisline, hashenum, "", sprintf("(line %d)", lineno))) + record.push(csvInt!(thisline, lineno)) + record.push(csvInt!(thisline, lineno)) + record.push(csvEnumFieldOrInt!(thisline, hashenum, "", sprintf("(line %d)", lineno))) + record.push(csvInt!(thisline, lineno)) + if !pbRgssExists?(sprintf("Data/Map%03d.rxdata", record[0])) + print _INTL("Warning: Map {1}, as mentioned in the map connection data, was not found.\r\n{2}", record[0], FileLineData.linereport) + end + if !pbRgssExists?(sprintf("Data/Map%03d.rxdata", record[3])) + print _INTL("Warning: Map {1}, as mentioned in the map connection data, was not found.\r\n{2}", record[3], FileLineData.linereport) + end + case record[1] + when "N" + raise _INTL("North side of first map must connect with south side of second map\r\n{1}", FileLineData.linereport) if record[4] != "S" + when "S" + raise _INTL("South side of first map must connect with north side of second map\r\n{1}", FileLineData.linereport) if record[4] != "N" + when "E" + raise _INTL("East side of first map must connect with west side of second map\r\n{1}", FileLineData.linereport) if record[4] != "W" + when "W" + raise _INTL("West side of first map must connect with east side of second map\r\n{1}", FileLineData.linereport) if record[4] != "E" + end + records.push(record) } - record = [] - thisline = line.dup - record.push(csvInt!(thisline, lineno)) - record.push(csvEnumFieldOrInt!(thisline, hashenum, "", sprintf("(line %d)", lineno))) - record.push(csvInt!(thisline, lineno)) - record.push(csvInt!(thisline, lineno)) - record.push(csvEnumFieldOrInt!(thisline, hashenum, "", sprintf("(line %d)", lineno))) - record.push(csvInt!(thisline, lineno)) - if !pbRgssExists?(sprintf("Data/Map%03d.rxdata", record[0])) - print _INTL("Warning: Map {1}, as mentioned in the map connection data, was not found.\r\n{2}", record[0], FileLineData.linereport) - end - if !pbRgssExists?(sprintf("Data/Map%03d.rxdata", record[3])) - print _INTL("Warning: Map {1}, as mentioned in the map connection data, was not found.\r\n{2}", record[3], FileLineData.linereport) - end - case record[1] - when "N" - raise _INTL("North side of first map must connect with south side of second map\r\n{1}", FileLineData.linereport) if record[4] != "S" - when "S" - raise _INTL("South side of first map must connect with north side of second map\r\n{1}", FileLineData.linereport) if record[4] != "N" - when "E" - raise _INTL("East side of first map must connect with west side of second map\r\n{1}", FileLineData.linereport) if record[4] != "W" - when "W" - raise _INTL("West side of first map must connect with east side of second map\r\n{1}", FileLineData.linereport) if record[4] != "E" - end - records.push(record) - } + process_pbs_file_message_end + end save_data(records, "Data/map_connections.dat") - process_pbs_file_message_end end #============================================================================= # Compile type data #============================================================================= - def compile_types(path = "PBS/types.txt") - compile_PBS_file_generic(GameData::Type, path) do |final_validate, hash| + def compile_types(*paths) + compile_PBS_file_generic(GameData::Type, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_types : validate_compiled_type(hash) end end @@ -171,8 +181,8 @@ module Compiler #============================================================================= # Compile ability data #============================================================================= - def compile_abilities(path = "PBS/abilities.txt") - compile_PBS_file_generic(GameData::Ability, path) do |final_validate, hash| + def compile_abilities(*paths) + compile_PBS_file_generic(GameData::Ability, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_abilities : validate_compiled_ability(hash) end end @@ -195,8 +205,8 @@ module Compiler #============================================================================= # Compile move data #============================================================================= - def compile_moves(path = "PBS/moves.txt") - compile_PBS_file_generic(GameData::Move, path) do |final_validate, hash| + def compile_moves(*paths) + compile_PBS_file_generic(GameData::Move, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_moves : validate_compiled_move(hash) end end @@ -227,8 +237,8 @@ module Compiler #============================================================================= # Compile item data #============================================================================= - def compile_items(path = "PBS/items.txt") - compile_PBS_file_generic(GameData::Item, path) do |final_validate, hash| + def compile_items(*paths) + compile_PBS_file_generic(GameData::Item, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_items : validate_compiled_item(hash) end end @@ -254,8 +264,8 @@ module Compiler #============================================================================= # Compile berry plant data #============================================================================= - def compile_berry_plants(path = "PBS/berry_plants.txt") - compile_PBS_file_generic(GameData::BerryPlant, path) do |final_validate, hash| + def compile_berry_plants(*paths) + compile_PBS_file_generic(GameData::BerryPlant, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_berry_plants : validate_compiled_berry_plant(hash) end end @@ -269,8 +279,8 @@ module Compiler #============================================================================= # Compile Pokémon data #============================================================================= - def compile_pokemon(path = "PBS/pokemon.txt") - compile_PBS_file_generic(GameData::Species, path) do |final_validate, hash| + def compile_pokemon(*paths) + compile_PBS_file_generic(GameData::Species, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_pokemon : validate_compiled_pokemon(hash) end end @@ -361,58 +371,64 @@ module Compiler # NOTE: Doesn't use compile_PBS_file_generic because it needs its own schema # and shouldn't clear GameData::Species at the start. #============================================================================= - def compile_pokemon_forms(path = "PBS/pokemon_forms.txt") - compile_pbs_file_message_start(path) - # Read from PBS file - File.open(path, "rb") { |f| - FileLineData.file = path # For error reporting - # Read a whole section's lines at once, then run through this code. - # contents is a hash containing all the XXX=YYY lines in that section, where - # the keys are the XXX and the values are the YYY (as unprocessed strings). - schema = GameData::Species.schema(true) - idx = 0 - pbEachFileSection(f, schema) { |contents, section_name| - echo "." if idx % 50 == 0 - Graphics.update if idx % 250 == 0 - idx += 1 - data_hash = {:id => section_name.to_sym} - # Go through schema hash of compilable data and compile this section - schema.each_key do |key| - FileLineData.setSection(section_name, key, contents[key]) # For error reporting - if key == "SectionName" - data_hash[schema[key][0]] = pbGetCsvRecord(section_name, key, schema[key]) - next - end - # Skip empty properties - next if contents[key].nil? - # Compile value for key - if schema[key][1][0] == "^" - contents[key].each do |val| - value = pbGetCsvRecord(val, key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] ||= [] - data_hash[schema[key][0]].push(value) + def compile_pokemon_forms(*paths) + schema = GameData::Species.schema(true) + # Read from PBS file(s) + paths.each do |path| + compile_pbs_file_message_start(path) + file_suffix = File.basename(path, ".txt")[GameData::Species::PBS_BASE_FILENAME[1].length + 1, path.length] || "" + File.open(path, "rb") { |f| + FileLineData.file = path # For error reporting + # Read a whole section's lines at once, then run through this code. + # contents is a hash containing all the XXX=YYY lines in that section, where + # the keys are the XXX and the values are the YYY (as unprocessed strings). + idx = 0 + pbEachFileSection(f, schema) { |contents, section_name| + echo "." if idx % 50 == 0 + Graphics.update if idx % 250 == 0 + idx += 1 + data_hash = { + :id => section_name.to_sym, + :pbs_file_suffix => file_suffix + } + # Go through schema hash of compilable data and compile this section + schema.each_key do |key| + FileLineData.setSection(section_name, key, contents[key]) # For error reporting + if key == "SectionName" + data_hash[schema[key][0]] = pbGetCsvRecord(section_name, key, schema[key]) + next + end + # Skip empty properties + next if contents[key].nil? + # Compile value for key + if schema[key][1][0] == "^" + contents[key].each do |val| + value = pbGetCsvRecord(val, key, schema[key]) + value = nil if value.is_a?(Array) && value.empty? + data_hash[schema[key][0]] ||= [] + data_hash[schema[key][0]].push(value) + end + data_hash[schema[key][0]].compact! + else + value = pbGetCsvRecord(contents[key], key, schema[key]) + value = nil if value.is_a?(Array) && value.empty? + data_hash[schema[key][0]] = value end - data_hash[schema[key][0]].compact! - else - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value end - end - # Validate and modify the compiled data - validate_compiled_pokemon_form(data_hash) - if GameData::Species.exists?(data_hash[:id]) - raise _INTL("Section name '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add section's data to records - GameData::Species.register(data_hash) + # Validate and modify the compiled data + validate_compiled_pokemon_form(data_hash) + if GameData::Species.exists?(data_hash[:id]) + raise _INTL("Section name '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) + end + # Add section's data to records + GameData::Species.register(data_hash) + } } - } + process_pbs_file_message_end + end validate_all_compiled_pokemon_forms # Save all data GameData::Species.save - process_pbs_file_message_end end def validate_compiled_pokemon_form(hash) @@ -491,8 +507,8 @@ module Compiler #============================================================================= # Compile Pokémon metrics data #============================================================================= - def compile_pokemon_metrics(path = "PBS/pokemon_metrics.txt") - compile_PBS_file_generic(GameData::SpeciesMetrics, path) do |final_validate, hash| + def compile_pokemon_metrics(*paths) + compile_PBS_file_generic(GameData::SpeciesMetrics, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_pokemon_metrics : validate_compiled_pokemon_metrics(hash) end end @@ -516,8 +532,8 @@ module Compiler #============================================================================= # Compile Shadow Pokémon data #============================================================================= - def compile_shadow_pokemon(path = "PBS/shadow_pokemon.txt") - compile_PBS_file_generic(GameData::ShadowPokemon, path) do |final_validate, hash| + def compile_shadow_pokemon(*paths) + compile_PBS_file_generic(GameData::ShadowPokemon, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_shadow_pokemon : validate_compiled_shadow_pokemon(hash) end end @@ -531,28 +547,31 @@ module Compiler #============================================================================= # Compile Regional Dexes #============================================================================= - def compile_regional_dexes(path = "PBS/regional_dexes.txt") - compile_pbs_file_message_start(path) + def compile_regional_dexes(*paths) dex_lists = [] - section = nil - pbCompilerEachPreppedLine(path) { |line, line_no| - Graphics.update if line_no % 200 == 0 - if line[/^\s*\[\s*(\d+)\s*\]\s*$/] - section = $~[1].to_i - if dex_lists[section] - raise _INTL("Dex list number {1} is defined at least twice.\r\n{2}", section, FileLineData.linereport) + paths.each do |path| + compile_pbs_file_message_start(path) + section = nil + pbCompilerEachPreppedLine(path) { |line, line_no| + Graphics.update if line_no % 200 == 0 + if line[/^\s*\[\s*(\d+)\s*\]\s*$/] + section = $~[1].to_i + if dex_lists[section] + raise _INTL("Dex list number {1} is defined at least twice.\r\n{2}", section, FileLineData.linereport) + end + dex_lists[section] = [] + else + raise _INTL("Expected a section at the beginning of the file.\r\n{1}", FileLineData.linereport) if !section + species_list = line.split(",") + species_list.each do |species| + next if !species || species.empty? + s = parseSpecies(species) + dex_lists[section].push(s) + end end - dex_lists[section] = [] - else - raise _INTL("Expected a section at the beginning of the file.\r\n{1}", FileLineData.linereport) if !section - species_list = line.split(",") - species_list.each do |species| - next if !species || species.empty? - s = parseSpecies(species) - dex_lists[section].push(s) - end - end - } + } + process_pbs_file_message_end + end # Check for duplicate species in a Regional Dex dex_lists.each_with_index do |list, index| unique_list = list.uniq @@ -564,14 +583,13 @@ module Compiler end # Save all data save_data(dex_lists, "Data/regional_dexes.dat") - process_pbs_file_message_end end #============================================================================= # Compile ribbon data #============================================================================= - def compile_ribbons(path = "PBS/ribbons.txt") - compile_PBS_file_generic(GameData::Ribbon, path) do |final_validate, hash| + def compile_ribbons(*paths) + compile_PBS_file_generic(GameData::Ribbon, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_ribbons : validate_compiled_ribbon(hash) end end @@ -594,117 +612,121 @@ module Compiler #============================================================================= # Compile wild encounter data #============================================================================= - def compile_encounters(path = "PBS/encounters.txt") - compile_pbs_file_message_start(path) + def compile_encounters(*paths) GameData::Encounter::DATA.clear - encounter_hash = nil - step_chances = nil - current_type = nil max_level = GameData::GrowthRate.max_level - idx = 0 - pbCompilerEachPreppedLine(path) { |line, line_no| - echo "." if idx % 50 == 0 - idx += 1 - Graphics.update if idx % 250 == 0 - next if line.length == 0 - if current_type && line[/^\d+,/] # Species line - values = line.split(",").collect! { |v| v.strip } - if !values || values.length < 3 - raise _INTL("Expected a species entry line for encounter type {1} for map '{2}', got \"{3}\" instead.\r\n{4}", - GameData::EncounterType.get(current_type).real_name, encounter_hash[:map], line, FileLineData.linereport) - end - values = pbGetCsvRecord(line, line_no, [0, "vevV", nil, :Species]) - values[3] = values[2] if !values[3] - if values[2] > max_level - raise _INTL("Level number {1} is not valid (max. {2}).\r\n{3}", values[2], max_level, FileLineData.linereport) - elsif values[3] > max_level - raise _INTL("Level number {1} is not valid (max. {2}).\r\n{3}", values[3], max_level, FileLineData.linereport) - elsif values[2] > values[3] - raise _INTL("Minimum level is greater than maximum level: {1}\r\n{2}", line, FileLineData.linereport) - end - encounter_hash[:types][current_type].push(values) - elsif line[/^\[\s*(.+)\s*\]$/] # Map ID line - values = $~[1].split(",").collect! { |v| v.strip.to_i } - values[1] = 0 if !values[1] - map_number = values[0] - map_version = values[1] - # Add map encounter's data to records - if encounter_hash - encounter_hash[:types].each_value do |slots| - next if !slots || slots.length == 0 - slots.each_with_index do |slot, i| - next if !slot - slots.each_with_index do |other_slot, j| - next if i == j || !other_slot - next if slot[1] != other_slot[1] || slot[2] != other_slot[2] || slot[3] != other_slot[3] - slot[0] += other_slot[0] - slots[j] = nil + paths.each do |path| + compile_pbs_file_message_start(path) + file_suffix = File.basename(path, ".txt")[GameData::Encounter::PBS_BASE_FILENAME.length + 1, path.length] || "" + encounter_hash = nil + step_chances = nil + current_type = nil + idx = 0 + pbCompilerEachPreppedLine(path) { |line, line_no| + echo "." if idx % 50 == 0 + idx += 1 + Graphics.update if idx % 250 == 0 + next if line.length == 0 + if current_type && line[/^\d+,/] # Species line + values = line.split(",").collect! { |v| v.strip } + if !values || values.length < 3 + raise _INTL("Expected a species entry line for encounter type {1} for map '{2}', got \"{3}\" instead.\r\n{4}", + GameData::EncounterType.get(current_type).real_name, encounter_hash[:map], line, FileLineData.linereport) + end + values = pbGetCsvRecord(line, line_no, [0, "vevV", nil, :Species]) + values[3] = values[2] if !values[3] + if values[2] > max_level + raise _INTL("Level number {1} is not valid (max. {2}).\r\n{3}", values[2], max_level, FileLineData.linereport) + elsif values[3] > max_level + raise _INTL("Level number {1} is not valid (max. {2}).\r\n{3}", values[3], max_level, FileLineData.linereport) + elsif values[2] > values[3] + raise _INTL("Minimum level is greater than maximum level: {1}\r\n{2}", line, FileLineData.linereport) + end + encounter_hash[:types][current_type].push(values) + elsif line[/^\[\s*(.+)\s*\]$/] # Map ID line + values = $~[1].split(",").collect! { |v| v.strip.to_i } + values[1] = 0 if !values[1] + map_number = values[0] + map_version = values[1] + # Add map encounter's data to records + if encounter_hash + encounter_hash[:types].each_value do |slots| + next if !slots || slots.length == 0 + slots.each_with_index do |slot, i| + next if !slot + slots.each_with_index do |other_slot, j| + next if i == j || !other_slot + next if slot[1] != other_slot[1] || slot[2] != other_slot[2] || slot[3] != other_slot[3] + slot[0] += other_slot[0] + slots[j] = nil + end end + slots.compact! + slots.sort! { |a, b| (a[0] == b[0]) ? a[1].to_s <=> b[1].to_s : b[0] <=> a[0] } end - slots.compact! - slots.sort! { |a, b| (a[0] == b[0]) ? a[1].to_s <=> b[1].to_s : b[0] <=> a[0] } + GameData::Encounter.register(encounter_hash) end - GameData::Encounter.register(encounter_hash) - end - # Raise an error if a map/version combo is used twice - key = sprintf("%s_%d", map_number, map_version).to_sym - if GameData::Encounter::DATA[key] - raise _INTL("Encounters for map '{1}' are defined twice.\r\n{2}", map_number, FileLineData.linereport) - end - step_chances = {} - # Construct encounter hash - encounter_hash = { - :id => key, - :map => map_number, - :version => map_version, - :step_chances => step_chances, - :types => {} - } - current_type = nil - elsif !encounter_hash # File began with something other than a map ID line - raise _INTL("Expected a map number, got \"{1}\" instead.\r\n{2}", line, FileLineData.linereport) - else - # Check if line is an encounter method name or not - values = line.split(",").collect! { |v| v.strip } - current_type = (values[0] && !values[0].empty?) ? values[0].to_sym : nil - if current_type && GameData::EncounterType.exists?(current_type) # Start of a new encounter method - step_chances[current_type] = values[1].to_i if values[1] && !values[1].empty? - step_chances[current_type] ||= GameData::EncounterType.get(current_type).trigger_chance - encounter_hash[:types][current_type] = [] + # Raise an error if a map/version combo is used twice + key = sprintf("%s_%d", map_number, map_version).to_sym + if GameData::Encounter::DATA[key] + raise _INTL("Encounters for map '{1}' are defined twice.\r\n{2}", map_number, FileLineData.linereport) + end + step_chances = {} + # Construct encounter hash + encounter_hash = { + :id => key, + :map => map_number, + :version => map_version, + :step_chances => step_chances, + :types => {}, + :pbs_file_suffix => file_suffix + } + current_type = nil + elsif !encounter_hash # File began with something other than a map ID line + raise _INTL("Expected a map number, got \"{1}\" instead.\r\n{2}", line, FileLineData.linereport) else - raise _INTL("Undefined encounter type \"{1}\" for map '{2}'.\r\n{3}", - line, encounter_hash[:map], FileLineData.linereport) - end - end - } - # Add last map's encounter data to records - if encounter_hash - encounter_hash[:types].each_value do |slots| - next if !slots || slots.length == 0 - slots.each_with_index do |slot, i| - next if !slot - slots.each_with_index do |other_slot, j| - next if i == j || !other_slot - next if slot[1] != other_slot[1] || slot[2] != other_slot[2] || slot[3] != other_slot[3] - slot[0] += other_slot[0] - slots[j] = nil + # Check if line is an encounter method name or not + values = line.split(",").collect! { |v| v.strip } + current_type = (values[0] && !values[0].empty?) ? values[0].to_sym : nil + if current_type && GameData::EncounterType.exists?(current_type) # Start of a new encounter method + step_chances[current_type] = values[1].to_i if values[1] && !values[1].empty? + step_chances[current_type] ||= GameData::EncounterType.get(current_type).trigger_chance + encounter_hash[:types][current_type] = [] + else + raise _INTL("Undefined encounter type \"{1}\" for map '{2}'.\r\n{3}", + line, encounter_hash[:map], FileLineData.linereport) end end - slots.compact! - slots.sort! { |a, b| (a[0] == b[0]) ? a[1].to_s <=> b[1].to_s : b[0] <=> a[0] } + } + # Add last map's encounter data to records + if encounter_hash + encounter_hash[:types].each_value do |slots| + next if !slots || slots.length == 0 + slots.each_with_index do |slot, i| + next if !slot + slots.each_with_index do |other_slot, j| + next if i == j || !other_slot + next if slot[1] != other_slot[1] || slot[2] != other_slot[2] || slot[3] != other_slot[3] + slot[0] += other_slot[0] + slots[j] = nil + end + end + slots.compact! + slots.sort! { |a, b| (a[0] == b[0]) ? a[1].to_s <=> b[1].to_s : b[0] <=> a[0] } + end + GameData::Encounter.register(encounter_hash) end - GameData::Encounter.register(encounter_hash) + process_pbs_file_message_end end # Save all data GameData::Encounter.save - process_pbs_file_message_end end #============================================================================= # Compile trainer type data #============================================================================= - def compile_trainer_types(path = "PBS/trainer_types.txt") - compile_PBS_file_generic(GameData::TrainerType, path) do |final_validate, hash| + def compile_trainer_types(*paths) + compile_PBS_file_generic(GameData::TrainerType, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_trainer_types : validate_compiled_trainer_type(hash) end end @@ -724,131 +746,135 @@ module Compiler #============================================================================= # Compile individual trainer data #============================================================================= - def compile_trainers(path = "PBS/trainers.txt") - compile_pbs_file_message_start(path) + def compile_trainers(*paths) GameData::Trainer::DATA.clear schema = GameData::Trainer.schema max_level = GameData::GrowthRate.max_level trainer_names = [] trainer_lose_texts = [] - trainer_hash = nil - current_pkmn = nil - # Read each line of trainers.txt at a time and compile it as a trainer property - idx = 0 - pbCompilerEachPreppedLine(path) { |line, line_no| - echo "." if idx % 50 == 0 - idx += 1 - Graphics.update if idx % 250 == 0 - if line[/^\s*\[\s*(.+)\s*\]\s*$/] - # New section [trainer_type, name] or [trainer_type, name, version] - if trainer_hash - if !current_pkmn - raise _INTL("Started new trainer while previous trainer has no Pokémon.\r\n{1}", FileLineData.linereport) + paths.each do |path| + compile_pbs_file_message_start(path) + file_suffix = File.basename(path, ".txt")[GameData::Trainer::PBS_BASE_FILENAME.length + 1, path.length] || "" + trainer_hash = nil + current_pkmn = nil + # Read each line of trainers.txt at a time and compile it as a trainer property + idx = 0 + pbCompilerEachPreppedLine(path) { |line, line_no| + echo "." if idx % 50 == 0 + idx += 1 + Graphics.update if idx % 250 == 0 + if line[/^\s*\[\s*(.+)\s*\]\s*$/] + # New section [trainer_type, name] or [trainer_type, name, version] + if trainer_hash + if !current_pkmn + raise _INTL("Started new trainer while previous trainer has no Pokémon.\r\n{1}", FileLineData.linereport) + end + # Add trainer's data to records + trainer_hash[:id] = [trainer_hash[:trainer_type], trainer_hash[:name], trainer_hash[:version]] + GameData::Trainer.register(trainer_hash) end - # Add trainer's data to records - trainer_hash[:id] = [trainer_hash[:trainer_type], trainer_hash[:name], trainer_hash[:version]] - GameData::Trainer.register(trainer_hash) - end - line_data = pbGetCsvRecord($~[1], line_no, [0, "esU", :TrainerType]) - # Construct trainer hash - trainer_hash = { - :trainer_type => line_data[0], - :name => line_data[1], - :version => line_data[2] || 0, - :pokemon => [] - } - current_pkmn = nil - trainer_names.push(trainer_hash[:name]) - elsif line[/^\s*(\w+)\s*=\s*(.*)$/] - # XXX=YYY lines - if !trainer_hash - raise _INTL("Expected a section at the beginning of the file.\r\n{1}", FileLineData.linereport) - end - property_name = $~[1] - line_schema = schema[property_name] - next if !line_schema - property_value = pbGetCsvRecord($~[2], line_no, line_schema) - # Error checking in XXX=YYY lines - case property_name - when "Pokemon" - if property_value[1] > max_level - raise _INTL("Bad level: {1} (must be 1-{2}).\r\n{3}", property_value[1], max_level, FileLineData.linereport) - end - when "Name" - if property_value.length > Pokemon::MAX_NAME_SIZE - raise _INTL("Bad nickname: {1} (must be 1-{2} characters).\r\n{3}", property_value, Pokemon::MAX_NAME_SIZE, FileLineData.linereport) - end - when "Moves" - property_value.uniq! - when "IV" - property_value.each do |iv| - next if iv <= Pokemon::IV_STAT_LIMIT - raise _INTL("Bad IV: {1} (must be 0-{2}).\r\n{3}", iv, Pokemon::IV_STAT_LIMIT, FileLineData.linereport) - end - when "EV" - property_value.each do |ev| - next if ev <= Pokemon::EV_STAT_LIMIT - raise _INTL("Bad EV: {1} (must be 0-{2}).\r\n{3}", ev, Pokemon::EV_STAT_LIMIT, FileLineData.linereport) - end - ev_total = 0 - GameData::Stat.each_main do |s| - next if s.pbs_order < 0 - ev_total += (property_value[s.pbs_order] || property_value[0]) - end - if ev_total > Pokemon::EV_LIMIT - raise _INTL("Total EVs are greater than allowed ({1}).\r\n{2}", Pokemon::EV_LIMIT, FileLineData.linereport) - end - when "Happiness" - if property_value > 255 - raise _INTL("Bad happiness: {1} (must be 0-255).\r\n{2}", property_value, FileLineData.linereport) - end - when "Ball" - if !GameData::Item.get(property_value).is_poke_ball? - raise _INTL("Value {1} isn't a defined Poké Ball.\r\n{2}", property_value, FileLineData.linereport) - end - end - # Record XXX=YYY setting - case property_name - when "Items", "LoseText" - trainer_hash[line_schema[0]] = property_value - trainer_lose_texts.push(property_value) if property_name == "LoseText" - when "Pokemon" - current_pkmn = { - :species => property_value[0], - :level => property_value[1] + line_data = pbGetCsvRecord($~[1], line_no, [0, "esU", :TrainerType]) + # Construct trainer hash + trainer_hash = { + :trainer_type => line_data[0], + :name => line_data[1], + :version => line_data[2] || 0, + :pokemon => [], + :pbs_file_suffix => file_suffix } - trainer_hash[line_schema[0]].push(current_pkmn) - else - if !current_pkmn - raise _INTL("Pokémon hasn't been defined yet!\r\n{1}", FileLineData.linereport) + current_pkmn = nil + trainer_names.push(trainer_hash[:name]) + elsif line[/^\s*(\w+)\s*=\s*(.*)$/] + # XXX=YYY lines + if !trainer_hash + raise _INTL("Expected a section at the beginning of the file.\r\n{1}", FileLineData.linereport) end + property_name = $~[1] + line_schema = schema[property_name] + next if !line_schema + property_value = pbGetCsvRecord($~[2], line_no, line_schema) + # Error checking in XXX=YYY lines case property_name - when "IV", "EV" - value_hash = {} + when "Pokemon" + if property_value[1] > max_level + raise _INTL("Bad level: {1} (must be 1-{2}).\r\n{3}", property_value[1], max_level, FileLineData.linereport) + end + when "Name" + if property_value.length > Pokemon::MAX_NAME_SIZE + raise _INTL("Bad nickname: {1} (must be 1-{2} characters).\r\n{3}", property_value, Pokemon::MAX_NAME_SIZE, FileLineData.linereport) + end + when "Moves" + property_value.uniq! + when "IV" + property_value.each do |iv| + next if iv <= Pokemon::IV_STAT_LIMIT + raise _INTL("Bad IV: {1} (must be 0-{2}).\r\n{3}", iv, Pokemon::IV_STAT_LIMIT, FileLineData.linereport) + end + when "EV" + property_value.each do |ev| + next if ev <= Pokemon::EV_STAT_LIMIT + raise _INTL("Bad EV: {1} (must be 0-{2}).\r\n{3}", ev, Pokemon::EV_STAT_LIMIT, FileLineData.linereport) + end + ev_total = 0 GameData::Stat.each_main do |s| next if s.pbs_order < 0 - value_hash[s.id] = property_value[s.pbs_order] || property_value[0] + ev_total += (property_value[s.pbs_order] || property_value[0]) end - current_pkmn[line_schema[0]] = value_hash + if ev_total > Pokemon::EV_LIMIT + raise _INTL("Total EVs are greater than allowed ({1}).\r\n{2}", Pokemon::EV_LIMIT, FileLineData.linereport) + end + when "Happiness" + if property_value > 255 + raise _INTL("Bad happiness: {1} (must be 0-255).\r\n{2}", property_value, FileLineData.linereport) + end + when "Ball" + if !GameData::Item.get(property_value).is_poke_ball? + raise _INTL("Value {1} isn't a defined Poké Ball.\r\n{2}", property_value, FileLineData.linereport) + end + end + # Record XXX=YYY setting + case property_name + when "Items", "LoseText" + trainer_hash[line_schema[0]] = property_value + trainer_lose_texts.push(property_value) if property_name == "LoseText" + when "Pokemon" + current_pkmn = { + :species => property_value[0], + :level => property_value[1] + } + trainer_hash[line_schema[0]].push(current_pkmn) else - current_pkmn[line_schema[0]] = property_value + if !current_pkmn + raise _INTL("Pokémon hasn't been defined yet!\r\n{1}", FileLineData.linereport) + end + case property_name + when "IV", "EV" + value_hash = {} + GameData::Stat.each_main do |s| + next if s.pbs_order < 0 + value_hash[s.id] = property_value[s.pbs_order] || property_value[0] + end + current_pkmn[line_schema[0]] = value_hash + else + current_pkmn[line_schema[0]] = property_value + end end end + } + # Add last trainer's data to records + if trainer_hash + if !current_pkmn + raise _INTL("End of file reached while last trainer has no Pokémon.\r\n{1}", FileLineData.linereport) + end + trainer_hash[:id] = [trainer_hash[:trainer_type], trainer_hash[:name], trainer_hash[:version]] + GameData::Trainer.register(trainer_hash) end - } - # Add last trainer's data to records - if trainer_hash - if !current_pkmn - raise _INTL("End of file reached while last trainer has no Pokémon.\r\n{1}", FileLineData.linereport) - end - trainer_hash[:id] = [trainer_hash[:trainer_type], trainer_hash[:name], trainer_hash[:version]] - GameData::Trainer.register(trainer_hash) + process_pbs_file_message_end end # Save all data GameData::Trainer.save MessageTypes.setMessagesAsHash(MessageTypes::TrainerNames, trainer_names) MessageTypes.setMessagesAsHash(MessageTypes::TrainerLoseText, trainer_lose_texts) - process_pbs_file_message_end end #============================================================================= @@ -973,74 +999,80 @@ module Compiler # NOTE: Doesn't use compile_PBS_file_generic because it contains data for two # different GameData classes. #============================================================================= - def compile_metadata(path = "PBS/metadata.txt") - compile_pbs_file_message_start(path) + def compile_metadata(*paths) GameData::Metadata::DATA.clear GameData::PlayerMetadata::DATA.clear - # Read from PBS file - File.open(path, "rb") { |f| - FileLineData.file = path # For error reporting - # Read a whole section's lines at once, then run through this code. - # contents is a hash containing all the XXX=YYY lines in that section, where - # the keys are the XXX and the values are the YYY (as unprocessed strings). - global_schema = GameData::Metadata.schema - player_schema = GameData::PlayerMetadata.schema - idx = 0 - pbEachFileSection(f) { |contents, section_name| - echo "." if idx % 50 == 0 - Graphics.update if idx % 250 == 0 - idx += 1 - schema = (section_name.to_i == 0) ? global_schema : player_schema - data_hash = {:id => section_name.to_sym} - # Go through schema hash of compilable data and compile this section - schema.each_key do |key| - FileLineData.setSection(section_name, key, contents[key]) # For error reporting - if key == "SectionName" - data_hash[schema[key][0]] = pbGetCsvRecord(section_name, key, schema[key]) - next - end - # Skip empty properties - next if contents[key].nil? - # Compile value for key - if schema[key][1][0] == "^" - contents[key].each do |val| - value = pbGetCsvRecord(val, key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] ||= [] - data_hash[schema[key][0]].push(value) + global_schema = GameData::Metadata.schema + player_schema = GameData::PlayerMetadata.schema + paths.each do |path| + compile_pbs_file_message_start(path) + file_suffix = File.basename(path, ".txt")[GameData::Metadata::PBS_BASE_FILENAME.length + 1, path.length] || "" + # Read from PBS file + File.open(path, "rb") { |f| + FileLineData.file = path # For error reporting + # Read a whole section's lines at once, then run through this code. + # contents is a hash containing all the XXX=YYY lines in that section, where + # the keys are the XXX and the values are the YYY (as unprocessed strings). + idx = 0 + pbEachFileSection(f) { |contents, section_name| + echo "." if idx % 50 == 0 + Graphics.update if idx % 250 == 0 + idx += 1 + schema = (section_name.to_i == 0) ? global_schema : player_schema + data_hash = { + :id => section_name.to_sym, + :pbs_file_suffix => file_suffix + } + # Go through schema hash of compilable data and compile this section + schema.each_key do |key| + FileLineData.setSection(section_name, key, contents[key]) # For error reporting + if key == "SectionName" + data_hash[schema[key][0]] = pbGetCsvRecord(section_name, key, schema[key]) + next + end + # Skip empty properties + next if contents[key].nil? + # Compile value for key + if schema[key][1][0] == "^" + contents[key].each do |val| + value = pbGetCsvRecord(val, key, schema[key]) + value = nil if value.is_a?(Array) && value.empty? + data_hash[schema[key][0]] ||= [] + data_hash[schema[key][0]].push(value) + end + data_hash[schema[key][0]].compact! + else + value = pbGetCsvRecord(contents[key], key, schema[key]) + value = nil if value.is_a?(Array) && value.empty? + data_hash[schema[key][0]] = value + end + end + # Validate and modify the compiled data + if data_hash[:id] == 0 + validate_compiled_global_metadata(data_hash) + if GameData::Metadata.exists?(data_hash[:id]) + raise _INTL("Global metadata ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) end - data_hash[schema[key][0]].compact! else - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value + validate_compiled_player_metadata(data_hash) + if GameData::PlayerMetadata.exists?(data_hash[:id]) + raise _INTL("Player metadata ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) + end end - end - # Validate and modify the compiled data - if data_hash[:id] == 0 - validate_compiled_global_metadata(data_hash) - if GameData::Metadata.exists?(data_hash[:id]) - raise _INTL("Global metadata ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) + # Add section's data to records + if data_hash[:id] == 0 + GameData::Metadata.register(data_hash) + else + GameData::PlayerMetadata.register(data_hash) end - else - validate_compiled_player_metadata(data_hash) - if GameData::PlayerMetadata.exists?(data_hash[:id]) - raise _INTL("Player metadata ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - end - # Add section's data to records - if data_hash[:id] == 0 - GameData::Metadata.register(data_hash) - else - GameData::PlayerMetadata.register(data_hash) - end + } } - } + process_pbs_file_message_end + end validate_all_compiled_metadata # Save all data GameData::Metadata.save GameData::PlayerMetadata.save - process_pbs_file_message_end end def validate_compiled_global_metadata(hash) @@ -1064,14 +1096,14 @@ module Compiler end # Get storage creator's name for translating storage_creator = [GameData::Metadata.get.real_storage_creator] - MessageTypes.setMessages(MessageTypes::StorageCreator, storage_creator) + MessageTypes.setMessagesAsHash(MessageTypes::StorageCreator, storage_creator) end #============================================================================= # Compile map metadata #============================================================================= - def compile_map_metadata(path = "PBS/map_metadata.txt") - compile_PBS_file_generic(GameData::MapMetadata, path) do |final_validate, hash| + def compile_map_metadata(*paths) + compile_PBS_file_generic(GameData::MapMetadata, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_map_metadata : validate_compiled_map_metadata(hash) end end @@ -1093,8 +1125,8 @@ module Compiler #============================================================================= # Compile dungeon tileset data #============================================================================= - def compile_dungeon_tilesets(path = "PBS/dungeon_tilesets.txt") - compile_PBS_file_generic(GameData::DungeonTileset, path) do |final_validate, hash| + def compile_dungeon_tilesets(*paths) + compile_PBS_file_generic(GameData::DungeonTileset, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_dungeon_tilesets : validate_compiled_dungeon_tileset(hash) end end @@ -1108,8 +1140,8 @@ module Compiler #============================================================================= # Compile dungeon parameters data #============================================================================= - def compile_dungeon_parameters(path = "PBS/dungeon_parameters.txt") - compile_PBS_file_generic(GameData::DungeonParameters, path) do |final_validate, hash| + def compile_dungeon_parameters(*paths) + compile_PBS_file_generic(GameData::DungeonParameters, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_dungeon_parameters : validate_compiled_dungeon_parameters(hash) end end @@ -1134,8 +1166,8 @@ module Compiler #============================================================================= # Compile phone messages #============================================================================= - def compile_phone(path = "PBS/phone.txt") - compile_PBS_file_generic(GameData::PhoneMessage, path) do |final_validate, hash| + def compile_phone(*paths) + compile_PBS_file_generic(GameData::PhoneMessage, *paths) do |final_validate, hash| (final_validate) ? validate_all_compiled_phone_contacts : validate_compiled_phone_contact(hash) end end diff --git a/Data/Scripts/021_Compiler/003_Compiler_WritePBS.rb b/Data/Scripts/021_Compiler/003_Compiler_WritePBS.rb index 0a85c3e1a..0c09085a8 100644 --- a/Data/Scripts/021_Compiler/003_Compiler_WritePBS.rb +++ b/Data/Scripts/021_Compiler/003_Compiler_WritePBS.rb @@ -1,6 +1,18 @@ module Compiler module_function + def get_all_PBS_file_paths(game_data) + ret = [] + game_data.each { |element| ret.push(element.pbs_file_suffix) if !ret.include?(element.pbs_file_suffix) } + ret.each_with_index do |element, i| + ret[i] = [sprintf("PBS/%s.txt", game_data::PBS_BASE_FILENAME), element] + if !nil_or_empty?(element) + ret[i][0] = sprintf("PBS/%s_%s.txt", game_data::PBS_BASE_FILENAME, element) + end + end + return ret + end + def add_PBS_header_to_file(file) file.write(0xEF.chr) file.write(0xBB.chr) @@ -8,47 +20,55 @@ module Compiler file.write("\# " + _INTL("See the documentation on the wiki to learn how to edit this file.") + "\r\n") end - def write_PBS_file_generic(game_data, path) - write_pbs_file_message_start(path) + def write_PBS_file_generic(game_data) + paths = get_all_PBS_file_paths(game_data) schema = game_data.schema - File.open(path, "wb") { |f| - add_PBS_header_to_file(f) - # Write each element in turn - game_data.each do |element| - f.write("\#-------------------------------\r\n") - if schema["SectionName"] - f.write("[") - pbWriteCsvRecord(element.get_property_for_PBS("SectionName"), f, schema["SectionName"]) - f.write("]\r\n") - else - f.write("[#{element.id}]\r\n") - end - schema.each_key do |key| - next if key == "SectionName" - val = element.get_property_for_PBS(key) - next if val.nil? - if schema[key][1][0] == "^" && val.is_a?(Array) - val.each do |sub_val| + idx = 0 + paths.each do |path| + write_pbs_file_message_start(path[0]) + File.open(path[0], "wb") { |f| + add_PBS_header_to_file(f) + # Write each element in turn + game_data.each do |element| + next if element.pbs_file_suffix != path[1] + echo "." if idx % 50 == 0 + Graphics.update if idx % 250 == 0 + idx += 1 + f.write("\#-------------------------------\r\n") + if schema["SectionName"] + f.write("[") + pbWriteCsvRecord(element.get_property_for_PBS("SectionName"), f, schema["SectionName"]) + f.write("]\r\n") + else + f.write("[#{element.id}]\r\n") + end + schema.each_key do |key| + next if key == "SectionName" + val = element.get_property_for_PBS(key) + next if val.nil? + if schema[key][1][0] == "^" && val.is_a?(Array) + val.each do |sub_val| + f.write(sprintf("%s = ", key)) + pbWriteCsvRecord(sub_val, f, schema[key]) + f.write("\r\n") + end + else f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(sub_val, f, schema[key]) + pbWriteCsvRecord(val, f, schema[key]) f.write("\r\n") end - else - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") end end - end - } - process_pbs_file_message_end + } + process_pbs_file_message_end + end end #============================================================================= # Save Town Map data to PBS file #============================================================================= - def write_town_map(path = "PBS/town_map.txt") - write_PBS_file_generic(GameData::TownMap, path) + def write_town_map + write_PBS_file_generic(GameData::TownMap) end #============================================================================= @@ -114,36 +134,36 @@ module Compiler #============================================================================= # Save type data to PBS file #============================================================================= - def write_types(path = "PBS/types.txt") - write_PBS_file_generic(GameData::Type, path) + def write_types + write_PBS_file_generic(GameData::Type) end #============================================================================= # Save ability data to PBS file #============================================================================= - def write_abilities(path = "PBS/abilities.txt") - write_PBS_file_generic(GameData::Ability, path) + def write_abilities + write_PBS_file_generic(GameData::Ability) end #============================================================================= # Save move data to PBS file #============================================================================= - def write_moves(path = "PBS/moves.txt") - write_PBS_file_generic(GameData::Move, path) + def write_moves + write_PBS_file_generic(GameData::Move) end #============================================================================= # Save item data to PBS file #============================================================================= - def write_items(path = "PBS/items.txt") - write_PBS_file_generic(GameData::Item, path) + def write_items + write_PBS_file_generic(GameData::Item) end #============================================================================= # Save berry plant data to PBS file #============================================================================= - def write_berry_plants(path = "PBS/berry_plants.txt") - write_PBS_file_generic(GameData::BerryPlant, path) + def write_berry_plants + write_PBS_file_generic(GameData::BerryPlant) end #============================================================================= @@ -151,40 +171,55 @@ module Compiler # NOTE: Doesn't use write_PBS_file_generic because it needs to ignore defined # species with a form that isn't 0. #============================================================================= - def write_pokemon(path = "PBS/pokemon.txt") - write_pbs_file_message_start(path) + def write_pokemon + paths = [] + GameData::Species.each_species { |element| paths.push(element.pbs_file_suffix) if !paths.include?(element.pbs_file_suffix) } + paths.each_with_index do |element, i| + paths[i] = [sprintf("PBS/%s.txt", GameData::Species::PBS_BASE_FILENAME[0]), element] + if !nil_or_empty?(element) + paths[i][0] = sprintf("PBS/%s_%s.txt", GameData::Species::PBS_BASE_FILENAME[0], element) + end + end schema = GameData::Species.schema - File.open(path, "wb") { |f| - add_PBS_header_to_file(f) - # Write each element in turn - GameData::Species.each_species do |element| - f.write("\#-------------------------------\r\n") - if schema["SectionName"] - f.write("[") - pbWriteCsvRecord(element.get_property_for_PBS("SectionName"), f, schema["SectionName"]) - f.write("]\r\n") - else - f.write("[#{element.id}]\r\n") - end - schema.each_key do |key| - next if key == "SectionName" - val = element.get_property_for_PBS(key) - next if val.nil? - if schema[key][1][0] == "^" && val.is_a?(Array) - val.each do |sub_val| + idx = 0 + paths.each do |path| + write_pbs_file_message_start(path[0]) + File.open(path[0], "wb") { |f| + add_PBS_header_to_file(f) + # Write each element in turn + GameData::Species.each_species do |element| + next if element.pbs_file_suffix != path[1] + echo "." if idx % 50 == 0 + Graphics.update if idx % 250 == 0 + idx += 1 + f.write("\#-------------------------------\r\n") + if schema["SectionName"] + f.write("[") + pbWriteCsvRecord(element.get_property_for_PBS("SectionName"), f, schema["SectionName"]) + f.write("]\r\n") + else + f.write("[#{element.id}]\r\n") + end + schema.each_key do |key| + next if key == "SectionName" + val = element.get_property_for_PBS(key) + next if val.nil? + if schema[key][1][0] == "^" && val.is_a?(Array) + val.each do |sub_val| + f.write(sprintf("%s = ", key)) + pbWriteCsvRecord(sub_val, f, schema[key]) + f.write("\r\n") + end + else f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(sub_val, f, schema[key]) + pbWriteCsvRecord(val, f, schema[key]) f.write("\r\n") end - else - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") end end - end - } - process_pbs_file_message_end + } + process_pbs_file_message_end + end end #============================================================================= @@ -192,41 +227,59 @@ module Compiler # NOTE: Doesn't use write_PBS_file_generic because it needs to ignore defined # species with a form of 0, and needs its own schema. #============================================================================= - def write_pokemon_forms(path = "PBS/pokemon_forms.txt") - write_pbs_file_message_start(path) + def write_pokemon_forms + paths = [] + GameData::Species.each do |element| + next if element.form == 0 + paths.push(element.pbs_file_suffix) if !paths.include?(element.pbs_file_suffix) + end + paths.each_with_index do |element, i| + paths[i] = [sprintf("PBS/%s.txt", GameData::Species::PBS_BASE_FILENAME[1]), element] + if !nil_or_empty?(element) + paths[i][0] = sprintf("PBS/%s_%s.txt", GameData::Species::PBS_BASE_FILENAME[1], element) + end + end schema = GameData::Species.schema(true) - File.open(path, "wb") { |f| - add_PBS_header_to_file(f) - # Write each element in turn - GameData::Species.each do |element| - next if element.form == 0 - f.write("\#-------------------------------\r\n") - if schema["SectionName"] - f.write("[") - pbWriteCsvRecord(element.get_property_for_PBS("SectionName", true), f, schema["SectionName"]) - f.write("]\r\n") - else - f.write("[#{element.id}]\r\n") - end - schema.each_key do |key| - next if key == "SectionName" - val = element.get_property_for_PBS(key, true) - next if val.nil? - if schema[key][1][0] == "^" && val.is_a?(Array) - val.each do |sub_val| + idx = 0 + paths.each do |path| + write_pbs_file_message_start(path[0]) + File.open(path[0], "wb") { |f| + add_PBS_header_to_file(f) + # Write each element in turn + GameData::Species.each do |element| + next if element.form == 0 + next if element.pbs_file_suffix != path[1] + echo "." if idx % 50 == 0 + Graphics.update if idx % 250 == 0 + idx += 1 + f.write("\#-------------------------------\r\n") + if schema["SectionName"] + f.write("[") + pbWriteCsvRecord(element.get_property_for_PBS("SectionName", true), f, schema["SectionName"]) + f.write("]\r\n") + else + f.write("[#{element.id}]\r\n") + end + schema.each_key do |key| + next if key == "SectionName" + val = element.get_property_for_PBS(key, true) + next if val.nil? + if schema[key][1][0] == "^" && val.is_a?(Array) + val.each do |sub_val| + f.write(sprintf("%s = ", key)) + pbWriteCsvRecord(sub_val, f, schema[key]) + f.write("\r\n") + end + else f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(sub_val, f, schema[key]) + pbWriteCsvRecord(val, f, schema[key]) f.write("\r\n") end - else - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") end end - end - } - process_pbs_file_message_end + } + process_pbs_file_message_end + end end #============================================================================= @@ -235,55 +288,73 @@ module Compiler # metrics for forms of species where the metrics are the same as for the # base species. #============================================================================= - def write_pokemon_metrics(path = "PBS/pokemon_metrics.txt") - write_pbs_file_message_start(path) + def write_pokemon_metrics + paths = [] + GameData::SpeciesMetrics.each do |element| + next if element.form == 0 + paths.push(element.pbs_file_suffix) if !paths.include?(element.pbs_file_suffix) + end + paths.each_with_index do |element, i| + paths[i] = [sprintf("PBS/%s.txt", GameData::SpeciesMetrics::PBS_BASE_FILENAME), element] + if !nil_or_empty?(element) + paths[i][0] = sprintf("PBS/%s_%s.txt", GameData::SpeciesMetrics::PBS_BASE_FILENAME, element) + end + end schema = GameData::SpeciesMetrics.schema - File.open(path, "wb") { |f| - add_PBS_header_to_file(f) - # Write each element in turn - GameData::SpeciesMetrics.each do |element| - if element.form > 0 - base_element = GameData::SpeciesMetrics.get(element.species) - next if element.back_sprite == base_element.back_sprite && - element.front_sprite == base_element.front_sprite && - element.front_sprite_altitude == base_element.front_sprite_altitude && - element.shadow_x == base_element.shadow_x && - element.shadow_size == base_element.shadow_size - end - f.write("\#-------------------------------\r\n") - if schema["SectionName"] - f.write("[") - pbWriteCsvRecord(element.get_property_for_PBS("SectionName"), f, schema["SectionName"]) - f.write("]\r\n") - else - f.write("[#{element.id}]\r\n") - end - schema.each_key do |key| - next if key == "SectionName" - val = element.get_property_for_PBS(key) - next if val.nil? - if schema[key][1][0] == "^" && val.is_a?(Array) - val.each do |sub_val| + idx = 0 + paths.each do |path| + write_pbs_file_message_start(path[0]) + File.open(path[0], "wb") { |f| + add_PBS_header_to_file(f) + # Write each element in turn + GameData::SpeciesMetrics.each do |element| + next if element.pbs_file_suffix != path[1] + if element.form > 0 + base_element = GameData::SpeciesMetrics.get(element.species) + next if element.back_sprite == base_element.back_sprite && + element.front_sprite == base_element.front_sprite && + element.front_sprite_altitude == base_element.front_sprite_altitude && + element.shadow_x == base_element.shadow_x && + element.shadow_size == base_element.shadow_size + end + echo "." if idx % 50 == 0 + Graphics.update if idx % 250 == 0 + idx += 1 + f.write("\#-------------------------------\r\n") + if schema["SectionName"] + f.write("[") + pbWriteCsvRecord(element.get_property_for_PBS("SectionName"), f, schema["SectionName"]) + f.write("]\r\n") + else + f.write("[#{element.id}]\r\n") + end + schema.each_key do |key| + next if key == "SectionName" + val = element.get_property_for_PBS(key) + next if val.nil? + if schema[key][1][0] == "^" && val.is_a?(Array) + val.each do |sub_val| + f.write(sprintf("%s = ", key)) + pbWriteCsvRecord(sub_val, f, schema[key]) + f.write("\r\n") + end + else f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(sub_val, f, schema[key]) + pbWriteCsvRecord(val, f, schema[key]) f.write("\r\n") end - else - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") end end - end - } - process_pbs_file_message_end + } + process_pbs_file_message_end + end end #============================================================================= # Save Shadow Pokémon data to PBS file #============================================================================= - def write_shadow_pokemon(path = "PBS/shadow_pokemon.txt") - write_PBS_file_generic(GameData::ShadowPokemon, path) + def write_shadow_pokemon + write_PBS_file_generic(GameData::ShadowPokemon) end #============================================================================= @@ -321,107 +392,115 @@ module Compiler #============================================================================= # Save ability data to PBS file #============================================================================= - def write_ribbons(path = "PBS/ribbons.txt") - write_PBS_file_generic(GameData::Ribbon, path) + def write_ribbons + write_PBS_file_generic(GameData::Ribbon) end #============================================================================= # Save wild encounter data to PBS file #============================================================================= - def write_encounters(path = "PBS/encounters.txt") - write_pbs_file_message_start(path) + def write_encounters + paths = get_all_PBS_file_paths(GameData::Encounter) map_infos = pbLoadMapInfos - File.open(path, "wb") { |f| - idx = 0 - add_PBS_header_to_file(f) - GameData::Encounter.each do |encounter_data| - echo "." if idx % 50 == 0 - idx += 1 - Graphics.update if idx % 250 == 0 - f.write("\#-------------------------------\r\n") - map_name = (map_infos[encounter_data.map]) ? " # #{map_infos[encounter_data.map].name}" : "" - if encounter_data.version > 0 - f.write(sprintf("[%03d,%d]%s\r\n", encounter_data.map, encounter_data.version, map_name)) - else - f.write(sprintf("[%03d]%s\r\n", encounter_data.map, map_name)) - end - encounter_data.types.each do |type, slots| - next if !slots || slots.length == 0 - if encounter_data.step_chances[type] && encounter_data.step_chances[type] > 0 - f.write(sprintf("%s,%d\r\n", type.to_s, encounter_data.step_chances[type])) + idx = 0 + paths.each do |path| + write_pbs_file_message_start(path[0]) + File.open(path[0], "wb") { |f| + add_PBS_header_to_file(f) + GameData::Encounter.each do |element| + next if element.pbs_file_suffix != path[1] + echo "." if idx % 50 == 0 + Graphics.update if idx % 250 == 0 + idx += 1 + f.write("\#-------------------------------\r\n") + map_name = (map_infos[element.map]) ? " # #{map_infos[element.map].name}" : "" + if element.version > 0 + f.write(sprintf("[%03d,%d]%s\r\n", element.map, element.version, map_name)) else - f.write(sprintf("%s\r\n", type.to_s)) + f.write(sprintf("[%03d]%s\r\n", element.map, map_name)) end - slots.each do |slot| - if slot[2] == slot[3] - f.write(sprintf(" %d,%s,%d\r\n", slot[0], slot[1], slot[2])) + element.types.each do |type, slots| + next if !slots || slots.length == 0 + if element.step_chances[type] && element.step_chances[type] > 0 + f.write(sprintf("%s,%d\r\n", type.to_s, element.step_chances[type])) else - f.write(sprintf(" %d,%s,%d,%d\r\n", slot[0], slot[1], slot[2], slot[3])) + f.write(sprintf("%s\r\n", type.to_s)) + end + slots.each do |slot| + if slot[2] == slot[3] + f.write(sprintf(" %d,%s,%d\r\n", slot[0], slot[1], slot[2])) + else + f.write(sprintf(" %d,%s,%d,%d\r\n", slot[0], slot[1], slot[2], slot[3])) + end end end end - end - } - process_pbs_file_message_end + } + process_pbs_file_message_end + end end #============================================================================= # Save trainer type data to PBS file #============================================================================= - def write_trainer_types(path = "PBS/trainer_types.txt") - write_PBS_file_generic(GameData::TrainerType, path) + def write_trainer_types + write_PBS_file_generic(GameData::TrainerType) end #============================================================================= # Save individual trainer data to PBS file #============================================================================= - def write_trainers(path = "PBS/trainers.txt") - write_pbs_file_message_start(path) - File.open(path, "wb") { |f| - idx = 0 - add_PBS_header_to_file(f) - GameData::Trainer.each do |trainer| - echo "." if idx % 50 == 0 - idx += 1 - Graphics.update if idx % 250 == 0 - f.write("\#-------------------------------\r\n") - if trainer.version > 0 - f.write(sprintf("[%s,%s,%d]\r\n", trainer.trainer_type, trainer.real_name, trainer.version)) - else - f.write(sprintf("[%s,%s]\r\n", trainer.trainer_type, trainer.real_name)) - end - f.write(sprintf("Items = %s\r\n", trainer.items.join(","))) if trainer.items.length > 0 - if trainer.real_lose_text && !trainer.real_lose_text.empty? - f.write(sprintf("LoseText = %s\r\n", trainer.real_lose_text)) - end - trainer.pokemon.each do |pkmn| - f.write(sprintf("Pokemon = %s,%d\r\n", pkmn[:species], pkmn[:level])) - f.write(sprintf(" Name = %s\r\n", pkmn[:name])) if pkmn[:name] && !pkmn[:name].empty? - f.write(sprintf(" Form = %d\r\n", pkmn[:form])) if pkmn[:form] && pkmn[:form] > 0 - f.write(sprintf(" Gender = %s\r\n", (pkmn[:gender] == 1) ? "female" : "male")) if pkmn[:gender] - f.write(" Shiny = yes\r\n") if pkmn[:shininess] && !pkmn[:super_shininess] - f.write(" SuperShiny = yes\r\n") if pkmn[:super_shininess] - f.write(" Shadow = yes\r\n") if pkmn[:shadowness] - f.write(sprintf(" Moves = %s\r\n", pkmn[:moves].join(","))) if pkmn[:moves] && pkmn[:moves].length > 0 - f.write(sprintf(" Ability = %s\r\n", pkmn[:ability])) if pkmn[:ability] - f.write(sprintf(" AbilityIndex = %d\r\n", pkmn[:ability_index])) if pkmn[:ability_index] - f.write(sprintf(" Item = %s\r\n", pkmn[:item])) if pkmn[:item] - f.write(sprintf(" Nature = %s\r\n", pkmn[:nature])) if pkmn[:nature] - ivs_array = [] - evs_array = [] - GameData::Stat.each_main do |s| - next if s.pbs_order < 0 - ivs_array[s.pbs_order] = pkmn[:iv][s.id] if pkmn[:iv] - evs_array[s.pbs_order] = pkmn[:ev][s.id] if pkmn[:ev] + def write_trainers + paths = get_all_PBS_file_paths(GameData::Trainer) + idx = 0 + paths.each do |path| + write_pbs_file_message_start(path[0]) + File.open(path[0], "wb") { |f| + add_PBS_header_to_file(f) + GameData::Trainer.each do |element| + next if element.pbs_file_suffix != path[1] + echo "." if idx % 50 == 0 + Graphics.update if idx % 250 == 0 + idx += 1 + f.write("\#-------------------------------\r\n") + if element.version > 0 + f.write(sprintf("[%s,%s,%d]\r\n", element.trainer_type, element.real_name, element.version)) + else + f.write(sprintf("[%s,%s]\r\n", element.trainer_type, element.real_name)) + end + f.write(sprintf("Items = %s\r\n", element.items.join(","))) if element.items.length > 0 + if element.real_lose_text && !element.real_lose_text.empty? + f.write(sprintf("LoseText = %s\r\n", element.real_lose_text)) + end + element.pokemon.each do |pkmn| + f.write(sprintf("Pokemon = %s,%d\r\n", pkmn[:species], pkmn[:level])) + f.write(sprintf(" Name = %s\r\n", pkmn[:name])) if pkmn[:name] && !pkmn[:name].empty? + f.write(sprintf(" Form = %d\r\n", pkmn[:form])) if pkmn[:form] && pkmn[:form] > 0 + f.write(sprintf(" Gender = %s\r\n", (pkmn[:gender] == 1) ? "female" : "male")) if pkmn[:gender] + f.write(" Shiny = yes\r\n") if pkmn[:shininess] && !pkmn[:super_shininess] + f.write(" SuperShiny = yes\r\n") if pkmn[:super_shininess] + f.write(" Shadow = yes\r\n") if pkmn[:shadowness] + f.write(sprintf(" Moves = %s\r\n", pkmn[:moves].join(","))) if pkmn[:moves] && pkmn[:moves].length > 0 + f.write(sprintf(" Ability = %s\r\n", pkmn[:ability])) if pkmn[:ability] + f.write(sprintf(" AbilityIndex = %d\r\n", pkmn[:ability_index])) if pkmn[:ability_index] + f.write(sprintf(" Item = %s\r\n", pkmn[:item])) if pkmn[:item] + f.write(sprintf(" Nature = %s\r\n", pkmn[:nature])) if pkmn[:nature] + ivs_array = [] + evs_array = [] + GameData::Stat.each_main do |s| + next if s.pbs_order < 0 + ivs_array[s.pbs_order] = pkmn[:iv][s.id] if pkmn[:iv] + evs_array[s.pbs_order] = pkmn[:ev][s.id] if pkmn[:ev] + end + f.write(sprintf(" IV = %s\r\n", ivs_array.join(","))) if pkmn[:iv] + f.write(sprintf(" EV = %s\r\n", evs_array.join(","))) if pkmn[:ev] + f.write(sprintf(" Happiness = %d\r\n", pkmn[:happiness])) if pkmn[:happiness] + f.write(sprintf(" Ball = %s\r\n", pkmn[:poke_ball])) if pkmn[:poke_ball] end - f.write(sprintf(" IV = %s\r\n", ivs_array.join(","))) if pkmn[:iv] - f.write(sprintf(" EV = %s\r\n", evs_array.join(","))) if pkmn[:ev] - f.write(sprintf(" Happiness = %d\r\n", pkmn[:happiness])) if pkmn[:happiness] - f.write(sprintf(" Ball = %s\r\n", pkmn[:poke_ball])) if pkmn[:poke_ball] end - end - } - process_pbs_file_message_end + } + process_pbs_file_message_end + end end #============================================================================= @@ -542,22 +621,132 @@ module Compiler # NOTE: Doesn't use write_PBS_file_generic because it contains data for two # different GameData classes. #============================================================================= - def write_metadata(path = "PBS/metadata.txt") - write_pbs_file_message_start(path) + def write_metadata + paths = [] + GameData::Metadata.each do |element| + paths.push(element.pbs_file_suffix) if !paths.include?(element.pbs_file_suffix) + end + GameData::PlayerMetadata.each do |element| + paths.push(element.pbs_file_suffix) if !paths.include?(element.pbs_file_suffix) + end + paths.each_with_index do |element, i| + paths[i] = [sprintf("PBS/%s.txt", GameData::Metadata::PBS_BASE_FILENAME), element] + if !nil_or_empty?(element) + paths[i][0] = sprintf("PBS/%s_%s.txt", GameData::Metadata::PBS_BASE_FILENAME, element) + end + end global_schema = GameData::Metadata.schema player_schema = GameData::PlayerMetadata.schema - File.open(path, "wb") { |f| - add_PBS_header_to_file(f) - # Write each element in turn - [GameData::Metadata, GameData::PlayerMetadata].each do |game_data| - schema = global_schema if game_data == GameData::Metadata - schema = player_schema if game_data == GameData::PlayerMetadata - game_data.each do |element| + paths.each do |path| + write_pbs_file_message_start(path[0]) + File.open(path[0], "wb") { |f| + add_PBS_header_to_file(f) + # Write each element in turn + [GameData::Metadata, GameData::PlayerMetadata].each do |game_data| + schema = global_schema if game_data == GameData::Metadata + schema = player_schema if game_data == GameData::PlayerMetadata + game_data.each do |element| + next if element.pbs_file_suffix != path[1] + f.write("\#-------------------------------\r\n") + if schema["SectionName"] + f.write("[") + pbWriteCsvRecord(element.get_property_for_PBS("SectionName"), f, schema["SectionName"]) + f.write("]\r\n") + else + f.write("[#{element.id}]\r\n") + end + schema.each_key do |key| + next if key == "SectionName" + val = element.get_property_for_PBS(key) + next if val.nil? + if schema[key][1][0] == "^" && val.is_a?(Array) + val.each do |sub_val| + f.write(sprintf("%s = ", key)) + pbWriteCsvRecord(sub_val, f, schema[key]) + f.write("\r\n") + end + else + f.write(sprintf("%s = ", key)) + pbWriteCsvRecord(val, f, schema[key]) + f.write("\r\n") + end + end + end + end + } + process_pbs_file_message_end + end + end + + #============================================================================= + # Save map metadata data to PBS file + # NOTE: Doesn't use write_PBS_file_generic because it writes the RMXP map name + # next to the section header for each map. + #============================================================================= + def write_map_metadata + paths = get_all_PBS_file_paths(GameData::MapMetadata) + map_infos = pbLoadMapInfos + schema = GameData::MapMetadata.schema + idx = 0 + paths.each do |path| + write_pbs_file_message_start(path[0]) + File.open(path[0], "wb") { |f| + add_PBS_header_to_file(f) + GameData::MapMetadata.each do |element| + next if element.pbs_file_suffix != path[1] + echo "." if idx % 50 == 0 + Graphics.update if idx % 250 == 0 + idx += 1 + f.write("\#-------------------------------\r\n") + map_name = (map_infos && map_infos[element.id]) ? map_infos[element.id].name : nil + f.write(sprintf("[%03d]", element.id)) + f.write(sprintf(" # %s", map_name)) if map_name + f.write("\r\n") + schema.each_key do |key| + next if key == "SectionName" + val = element.get_property_for_PBS(key) + next if val.nil? + if schema[key][1][0] == "^" && val.is_a?(Array) + val.each do |sub_val| + f.write(sprintf("%s = ", key)) + pbWriteCsvRecord(sub_val, f, schema[key]) + f.write("\r\n") + end + else + f.write(sprintf("%s = ", key)) + pbWriteCsvRecord(val, f, schema[key]) + f.write("\r\n") + end + end + end + } + process_pbs_file_message_end + end + end + + #============================================================================= + # Save dungeon tileset contents data to PBS file + # NOTE: Doesn't use write_PBS_file_generic because it writes the tileset name + # next to the section header for each tileset. + #============================================================================= + def write_dungeon_tilesets + paths = get_all_PBS_file_paths(GameData::DungeonTileset) + schema = GameData::DungeonTileset.schema + tilesets = load_data("Data/Tilesets.rxdata") + paths.each do |path| + write_pbs_file_message_start(path[0]) + File.open(path[0], "wb") { |f| + add_PBS_header_to_file(f) + # Write each element in turn + GameData::DungeonTileset.each do |element| + next if element.pbs_file_suffix != path[1] f.write("\#-------------------------------\r\n") if schema["SectionName"] f.write("[") pbWriteCsvRecord(element.get_property_for_PBS("SectionName"), f, schema["SectionName"]) - f.write("]\r\n") + f.write("]") + f.write(" # #{tilesets[element.id].name}") if tilesets && tilesets[element.id] + f.write("\r\n") else f.write("[#{element.id}]\r\n") end @@ -578,109 +767,23 @@ module Compiler end end end - end - } - process_pbs_file_message_end - end - - #============================================================================= - # Save map metadata data to PBS file - # NOTE: Doesn't use write_PBS_file_generic because it writes the RMXP map name - # next to the section header for each map. - #============================================================================= - def write_map_metadata(path = "PBS/map_metadata.txt") - write_pbs_file_message_start(path) - map_infos = pbLoadMapInfos - schema = GameData::MapMetadata.schema - File.open(path, "wb") { |f| - idx = 0 - add_PBS_header_to_file(f) - GameData::MapMetadata.each do |element| - echo "." if idx % 50 == 0 - idx += 1 - Graphics.update if idx % 250 == 0 - f.write("\#-------------------------------\r\n") - map_name = (map_infos && map_infos[element.id]) ? map_infos[element.id].name : nil - f.write(sprintf("[%03d]", element.id)) - f.write(sprintf(" # %s", map_name)) if map_name - f.write("\r\n") - schema.each_key do |key| - next if key == "SectionName" - val = element.get_property_for_PBS(key) - next if val.nil? - if schema[key][1][0] == "^" && val.is_a?(Array) - val.each do |sub_val| - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(sub_val, f, schema[key]) - f.write("\r\n") - end - else - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") - end - end - end - } - process_pbs_file_message_end - end - - #============================================================================= - # Save dungeon tileset contents data to PBS file - # NOTE: Doesn't use write_PBS_file_generic because it writes the tileset name - # next to the section header for each tileset. - #============================================================================= - def write_dungeon_tilesets(path = "PBS/dungeon_tilesets.txt") - write_pbs_file_message_start(path) - tilesets = load_data("Data/Tilesets.rxdata") - schema = GameData::DungeonTileset.schema - File.open(path, "wb") { |f| - add_PBS_header_to_file(f) - # Write each element in turn - GameData::DungeonTileset.each do |element| - f.write("\#-------------------------------\r\n") - if schema["SectionName"] - f.write("[") - pbWriteCsvRecord(element.get_property_for_PBS("SectionName"), f, schema["SectionName"]) - f.write("]") - f.write(" # #{tilesets[element.id].name}") if tilesets && tilesets[element.id] - f.write("\r\n") - else - f.write("[#{element.id}]\r\n") - end - schema.each_key do |key| - next if key == "SectionName" - val = element.get_property_for_PBS(key) - next if val.nil? - if schema[key][1][0] == "^" && val.is_a?(Array) - val.each do |sub_val| - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(sub_val, f, schema[key]) - f.write("\r\n") - end - else - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") - end - end - end - } - process_pbs_file_message_end + } + process_pbs_file_message_end + end end #============================================================================= # Save dungeon parameters to PBS file #============================================================================= - def write_dungeon_parameters(path = "PBS/dungeon_parameters.txt") - write_PBS_file_generic(GameData::DungeonParameters, path) + def write_dungeon_parameters + write_PBS_file_generic(GameData::DungeonParameters) end #============================================================================= # Save phone messages to PBS file #============================================================================= - def write_phone(path = "PBS/phone.txt") - write_PBS_file_generic(GameData::PhoneMessage, path) + def write_phone + write_PBS_file_generic(GameData::PhoneMessage) end #=============================================================================