From f33eb4d8965e28b26b29087a8ec36f30748be1f1 Mon Sep 17 00:00:00 2001 From: Maruno17 Date: Sun, 20 Nov 2022 20:15:04 +0000 Subject: [PATCH] Added PBS schema character ^ for repeated lines, more refactoring of PBS compilers/writers --- Data/Scripts/010_Data/001_GameData.rb | 14 +- .../Scripts/010_Data/002_PBS data/004_Move.rb | 2 +- .../Scripts/010_Data/002_PBS data/005_Item.rb | 2 +- .../010_Data/002_PBS data/007_Species.rb | 2 +- .../002_PBS data/009_SpeciesMetrics.rb | 2 +- .../010_Data/002_PBS data/013_TrainerType.rb | 2 +- .../010_Data/002_PBS data/015_Metadata.rb | 17 - .../002_PBS data/016_PlayerMetadata.rb | 15 - .../010_Data/002_PBS data/017_MapMetadata.rb | 28 - .../002_PBS data/018_DungeonTileset.rb | 36 +- .../002_PBS data/020_DungeonParameters.rb | 2 +- .../010_Data/002_PBS data/020_PhoneMessage.rb | 55 +- .../001_Editor screens/001_EditorScreens.rb | 47 +- .../Scripts/020_Debug/002_Editor_DataTypes.rb | 2 +- Data/Scripts/021_Compiler/001_Compiler.rb | 25 +- .../021_Compiler/002_Compiler_CompilePBS.rb | 920 +++++------------- .../021_Compiler/003_Compiler_WritePBS.rb | 221 +++-- PBS/phone.txt | 4 +- PBS/town_map.txt | 54 +- 19 files changed, 516 insertions(+), 934 deletions(-) diff --git a/Data/Scripts/010_Data/001_GameData.rb b/Data/Scripts/010_Data/001_GameData.rb index 7b356a567..92d972cee 100644 --- a/Data/Scripts/010_Data/001_GameData.rb +++ b/Data/Scripts/010_Data/001_GameData.rb @@ -6,6 +6,10 @@ module GameData # For data that is known by a symbol or an ID number. #============================================================================= module ClassMethods + def schema + return self::SCHEMA + end + def register(hash) self::DATA[hash[:id]] = self::DATA[hash[:id_number]] = self.new(hash) end @@ -72,6 +76,10 @@ module GameData # For data that is only known by a symbol. #============================================================================= module ClassMethodsSymbols + def schema + return self::SCHEMA + end + def register(hash) self::DATA[hash[:id]] = self.new(hash) end @@ -143,6 +151,10 @@ module GameData # For data that is only known by an ID number. #============================================================================= module ClassMethodsIDNumbers + def schema + return self::SCHEMA + end + def register(hash) self::DATA[hash[:id]] = self.new(hash) end @@ -222,7 +234,7 @@ module GameData def get_property_for_PBS(key) ret = nil - if self.class::SCHEMA.include?(key) + if self.class::SCHEMA.include?(key) && self.respond_to?(self.class::SCHEMA[key][0]) ret = self.send(self.class::SCHEMA[key][0]) ret = nil if ret == false || (ret.is_a?(Array) && ret.length == 0) end diff --git a/Data/Scripts/010_Data/002_PBS data/004_Move.rb b/Data/Scripts/010_Data/002_PBS data/004_Move.rb index 1d37c03b2..7e0417a28 100644 --- a/Data/Scripts/010_Data/002_PBS data/004_Move.rb +++ b/Data/Scripts/010_Data/002_PBS data/004_Move.rb @@ -812,7 +812,7 @@ module GameData return data end - alias __orig__get_property_for_PBS get_property_for_PBS + alias __orig__get_property_for_PBS get_property_for_PBS unless method_defined?(:__orig__get_property_for_PBS) def get_property_for_PBS(key) ret = __orig__get_property_for_PBS(key) ret = nil if ["Power", "Priority", "EffectChance"].include?(key) && ret == 0 diff --git a/Data/Scripts/010_Data/002_PBS data/005_Item.rb b/Data/Scripts/010_Data/002_PBS data/005_Item.rb index c7b21da67..a46b52055 100644 --- a/Data/Scripts/010_Data/002_PBS data/005_Item.rb +++ b/Data/Scripts/010_Data/002_PBS data/005_Item.rb @@ -193,7 +193,7 @@ module GameData return combos[species]&.include?(@id) end - alias __orig__get_property_for_PBS get_property_for_PBS + alias __orig__get_property_for_PBS get_property_for_PBS unless method_defined?(:__orig__get_property_for_PBS) def get_property_for_PBS(key) ret = __orig__get_property_for_PBS(key) case key diff --git a/Data/Scripts/010_Data/002_PBS data/007_Species.rb b/Data/Scripts/010_Data/002_PBS data/007_Species.rb index 8f0439b38..4c0b00998 100644 --- a/Data/Scripts/010_Data/002_PBS data/007_Species.rb +++ b/Data/Scripts/010_Data/002_PBS data/007_Species.rb @@ -342,7 +342,7 @@ module GameData return 1 end - alias __orig__get_property_for_PBS get_property_for_PBS + alias __orig__get_property_for_PBS get_property_for_PBS unless method_defined?(:__orig__get_property_for_PBS) def get_property_for_PBS(key, writing_form = false) ret = nil if self.class.schema(writing_form).include?(key) diff --git a/Data/Scripts/010_Data/002_PBS data/009_SpeciesMetrics.rb b/Data/Scripts/010_Data/002_PBS data/009_SpeciesMetrics.rb index b4ac39e60..dc915efbe 100644 --- a/Data/Scripts/010_Data/002_PBS data/009_SpeciesMetrics.rb +++ b/Data/Scripts/010_Data/002_PBS data/009_SpeciesMetrics.rb @@ -85,7 +85,7 @@ module GameData # return @front_sprite_altitude > 0 end - alias __orig__get_property_for_PBS get_property_for_PBS + alias __orig__get_property_for_PBS get_property_for_PBS unless method_defined?(:__orig__get_property_for_PBS) def get_property_for_PBS(key) ret = __orig__get_property_for_PBS(key) case key diff --git a/Data/Scripts/010_Data/002_PBS data/013_TrainerType.rb b/Data/Scripts/010_Data/002_PBS data/013_TrainerType.rb index df630e740..1c2adca37 100644 --- a/Data/Scripts/010_Data/002_PBS data/013_TrainerType.rb +++ b/Data/Scripts/010_Data/002_PBS data/013_TrainerType.rb @@ -104,7 +104,7 @@ module GameData return @flags.any? { |f| f.downcase == flag.downcase } end - alias __orig__get_property_for_PBS get_property_for_PBS + alias __orig__get_property_for_PBS get_property_for_PBS unless method_defined?(:__orig__get_property_for_PBS) def get_property_for_PBS(key) ret = __orig__get_property_for_PBS(key) ret = nil if key == "SkillLevel" && ret == @base_money diff --git a/Data/Scripts/010_Data/002_PBS data/015_Metadata.rb b/Data/Scripts/010_Data/002_PBS data/015_Metadata.rb index a2869b1b2..5f02f86df 100644 --- a/Data/Scripts/010_Data/002_PBS data/015_Metadata.rb +++ b/Data/Scripts/010_Data/002_PBS data/015_Metadata.rb @@ -74,22 +74,5 @@ module GameData ret = pbGetMessage(MessageTypes::StorageCreator, 0) return nil_or_empty?(ret) ? _INTL("Bill") : ret end - - def property_from_string(str) - case str - when "StartMoney" then return @start_money - when "StartItemStorage" then return @start_item_storage - when "Home" then return @home - when "StorageCreator" then return @real_storage_creator - when "WildBattleBGM" then return @wild_battle_BGM - when "TrainerBattleBGM" then return @trainer_battle_BGM - when "WildVictoryBGM" then return @wild_victory_BGM - when "TrainerVictoryBGM" then return @trainer_victory_BGM - when "WildCaptureME" then return @wild_capture_ME - when "SurfBGM" then return @surf_BGM - when "BicycleBGM" then return @bicycle_BGM - end - return nil - end end end diff --git a/Data/Scripts/010_Data/002_PBS data/016_PlayerMetadata.rb b/Data/Scripts/010_Data/002_PBS data/016_PlayerMetadata.rb index a050296e8..6d2844d82 100644 --- a/Data/Scripts/010_Data/002_PBS data/016_PlayerMetadata.rb +++ b/Data/Scripts/010_Data/002_PBS data/016_PlayerMetadata.rb @@ -82,20 +82,5 @@ module GameData def surf_fish_charset return @surf_fish_charset || fish_charset end - - def property_from_string(str) - case str - when "TrainerType" then return @trainer_type - when "WalkCharset" then return @walk_charset - when "RunCharset" then return @run_charset - when "CycleCharset" then return @cycle_charset - when "SurfCharset" then return @surf_charset - when "DiveCharset" then return @dive_charset - when "FishCharset" then return @fish_charset - when "SurfFishCharset" then return @surf_fish_charset - when "Home" then return @home - end - return nil - end end end diff --git a/Data/Scripts/010_Data/002_PBS data/017_MapMetadata.rb b/Data/Scripts/010_Data/002_PBS data/017_MapMetadata.rb index bf6f9397d..8ccba189e 100644 --- a/Data/Scripts/010_Data/002_PBS data/017_MapMetadata.rb +++ b/Data/Scripts/010_Data/002_PBS data/017_MapMetadata.rb @@ -109,34 +109,6 @@ module GameData @flags = hash[:flags] || [] end - def property_from_string(str) - case str - when "Name" then return @real_name - when "Outdoor" then return @outdoor_map - when "ShowArea" then return @announce_location - when "Bicycle" then return @can_bicycle - when "BicycleAlways" then return @always_bicycle - when "HealingSpot" then return @teleport_destination - when "Weather" then return @weather - when "MapPosition" then return @town_map_position - when "DiveMap" then return @dive_map_id - when "DarkMap" then return @dark_map - when "SafariMap" then return @safari_map - when "SnapEdges" then return @snap_edges - when "Dungeon" then return @random_dungeon - when "BattleBack" then return @battle_background - when "WildBattleBGM" then return @wild_battle_BGM - when "TrainerBattleBGM" then return @trainer_battle_BGM - when "WildVictoryBGM" then return @wild_victory_BGM - when "TrainerVictoryBGM" then return @trainer_victory_BGM - when "WildCaptureME" then return @wild_capture_ME - when "MapSize" then return @town_map_size - when "Environment" then return @battle_environment - when "Flags" then return @flags - end - return nil - end - # @return [String] the translated name of this map def name return pbGetMapNameFromId(@id) diff --git a/Data/Scripts/010_Data/002_PBS data/018_DungeonTileset.rb b/Data/Scripts/010_Data/002_PBS data/018_DungeonTileset.rb index b7c03e68b..854a0d50d 100644 --- a/Data/Scripts/010_Data/002_PBS data/018_DungeonTileset.rb +++ b/Data/Scripts/010_Data/002_PBS data/018_DungeonTileset.rb @@ -15,8 +15,9 @@ module GameData DATA_FILENAME = "dungeon_tilesets.dat" SCHEMA = { - "Autotile" => [:autotile, "um"], - "Tile" => [:tile, "um"], + "SectionName" => [:id, "u"], + "Autotile" => [:autotile, "^um"], + "Tile" => [:tile, "^um"], "SnapToLargeGrid" => [:snap_to_large_grid, "b"], "LargeVoidTiles" => [:large_void_tiles, "b"], "LargeWallTiles" => [:large_wall_tiles, "b"], @@ -192,18 +193,27 @@ module GameData return ret end - def property_from_string(str) - case str - when "SnapToLargeGrid" then return @snap_to_large_grid - when "LargeVoidTiles" then return @large_void_tiles - when "LargeWallTiles" then return @large_wall_tiles - when "LargeFloorTiles" then return @large_floor_tiles - when "DoubleWalls" then return @double_walls - when "FloorPatchUnderWalls" then return @floor_patch_under_walls - when "ThinNorthWallOffset" then return @thin_north_wall_offset - when "Flags" then return @flags + alias __orig__get_property_for_PBS get_property_for_PBS unless method_defined?(:__orig__get_property_for_PBS) + def get_property_for_PBS(key) + ret = __orig__get_property_for_PBS(key) + case key + when "ThinNorthWallOffset" + ret = nil if ret == 0 + when "Tile", "Autotile" + ret = [] + @tile_type_ids.each do |tile_type, tile_ids| + tile_ids.each do |tile| + case key + when "Tile" + ret.push([tile[0] - 384, tile_type]) if !tile[1] && tile[0] >= 384 + when "Autotile" + ret.push([tile[0] / 48, tile_type]) if !tile[1] && tile[0] < 384 + end + end + end + ret = nil if ret.length == 0 end - return nil + return ret end end end 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 df0d4663e..91723de05 100644 --- a/Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb +++ b/Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb @@ -115,7 +115,7 @@ module GameData return width, height end - alias __orig__get_property_for_PBS get_property_for_PBS + alias __orig__get_property_for_PBS get_property_for_PBS unless method_defined?(:__orig__get_property_for_PBS) def get_property_for_PBS(key) case key when "SectionName" then return [@area, (@version > 0) ? @version : nil] diff --git a/Data/Scripts/010_Data/002_PBS data/020_PhoneMessage.rb b/Data/Scripts/010_Data/002_PBS data/020_PhoneMessage.rb index 9f90c3223..2a5dcb27d 100644 --- a/Data/Scripts/010_Data/002_PBS data/020_PhoneMessage.rb +++ b/Data/Scripts/010_Data/002_PBS data/020_PhoneMessage.rb @@ -11,29 +11,36 @@ module GameData DATA_FILENAME = "phone.dat" SCHEMA = { - "Intro" => [:intro, "q"], - "IntroMorning" => [:intro_morning, "q"], - "IntroAfternoon" => [:intro_afternoon, "q"], - "IntroEvening" => [:intro_evening, "q"], - "Body" => [:body, "q"], - "Body1" => [:body1, "q"], - "Body2" => [:body2, "q"], - "BattleRequest" => [:battle_request, "q"], - "BattleRemind" => [:battle_remind, "q"], - "End" => [:end, "q"] + "SectionName" => [:id, "q"], + "Intro" => [:intro, "^q"], + "IntroMorning" => [:intro_morning, "^q"], + "IntroAfternoon" => [:intro_afternoon, "^q"], + "IntroEvening" => [:intro_evening, "^q"], + "Body1" => [:body1, "^q"], + "Body2" => [:body2, "^q"], + "Body" => [:body, "^q"], + "BattleRequest" => [:battle_request, "^q"], + "BattleRemind" => [:battle_remind, "^q"], + "End" => [:end, "^q"] } extend ClassMethodsSymbols include InstanceMethods # @param tr_type [Symbol, String] - # @param tr_name [String] + # @param tr_name [String, nil] only nil for the default message set # @param tr_version [Integer, nil] # @return [Boolean] whether the given other is defined as a self - def self.exists?(tr_type, tr_name, tr_version = 0) + def self.exists?(tr_type, tr_name = nil, tr_version = 0) + if tr_type.is_a?(Array) + tr_name = tr_type[1] + tr_version = tr_type[2] + tr_type = tr_type[0] + end validate tr_type => [Symbol, String] - validate tr_name => [String] + validate tr_name => [String, NilClass] key = [tr_type.to_sym, tr_name, tr_version] + key = key[0] if key[1] == nil return !self::DATA[key].nil? end @@ -63,7 +70,7 @@ module GameData def initialize(hash) @id = hash[:id] @trainer_type = hash[:trainer_type] - @real_name = hash[:name] + @real_name = hash[:real_name] @version = hash[:version] || 0 @intro = hash[:intro] @intro_morning = hash[:intro_morning] @@ -77,20 +84,14 @@ module GameData @end = hash[:end] end - def property_from_string(str) - case str - when "Intro" then return @intro - when "IntroMorning" then return @intro_morning - when "IntroAfternoon" then return @intro_afternoon - when "IntroEvening" then return @intro_evening - when "Body" then return @body - when "Body1" then return @body1 - when "Body2" then return @body2 - when "BattleRequest" then return @battle_request - when "BattleRemind" then return @battle_remind - when "End" then return @end + alias __orig__get_property_for_PBS get_property_for_PBS unless method_defined?(:__orig__get_property_for_PBS) + def get_property_for_PBS(key) + if key == "SectionName" + return "Default" if @id == "default" + ret = [@trainer_type, @real_name, (@version > 0) ? @version : nil] + return ret.compact.join(",") end - return nil + return __orig__get_property_for_PBS(key) end end end 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 8194793b8..fbfe37d17 100644 --- a/Data/Scripts/020_Debug/001_Editor screens/001_EditorScreens.rb +++ b/Data/Scripts/020_Debug/001_Editor screens/001_EditorScreens.rb @@ -345,7 +345,7 @@ end #=============================================================================== def pbTrainerTypeEditor gender_array = [] - GameData::TrainerType::SCHEMA["Gender"][2].each { |key, value| gender_array[value] = key if !gender_array[value] } + GameData::TrainerType.schema["Gender"][2].each { |key, value| gender_array[value] = key if !gender_array[value] } trainer_type_properties = [ [_INTL("ID"), ReadOnlyProperty, _INTL("ID of this Trainer Type (used as a symbol like :XXX).")], [_INTL("Name"), StringProperty, _INTL("Name of this Trainer Type as displayed by the game.")], @@ -732,23 +732,25 @@ def pbEditMetadata metadata = GameData::Metadata.get properties = GameData::Metadata.editor_properties properties.each do |property| - data.push(metadata.property_from_string(property[0])) + val = metadata.get_property_for_PBS(property[0]) + val = property[1].defaultValue if val.nil? && property[1].respond_to?(:defaultValue) + data.push(val) end if pbPropertyList(_INTL("Global Metadata"), data, properties, true) # Construct metadata hash metadata_hash = { - :id => 0, - :start_money => data[0], - :start_item_storage => data[1], - :home => data[2], - :storage_creator => data[3], - :wild_battle_BGM => data[4], - :trainer_battle_BGM => data[5], - :wild_victory_BGM => data[6], - :trainer_victory_BGM => data[7], - :wild_capture_ME => data[8], - :surf_BGM => data[9], - :bicycle_BGM => data[10] + :id => 0, + :start_money => data[0], + :start_item_storage => data[1], + :home => data[2], + :real_storage_creator => data[3], + :wild_battle_BGM => data[4], + :trainer_battle_BGM => data[5], + :wild_victory_BGM => data[6], + :trainer_victory_BGM => data[7], + :wild_capture_ME => data[8], + :surf_BGM => data[9], + :bicycle_BGM => data[10] } # Add metadata's data to records GameData::Metadata.register(metadata_hash) @@ -776,7 +778,9 @@ def pbEditPlayerMetadata(player_id = 1) metadata = GameData::PlayerMetadata.try_get(player_id) if metadata.nil? properties = GameData::PlayerMetadata.editor_properties properties.each do |property| - data.push(metadata.property_from_string(property[0])) + val = metadata.get_property_for_PBS(property[0]) + val = property[1].defaultValue if val.nil? && property[1].respond_to?(:defaultValue) + data.push(val) end if pbPropertyList(_INTL("Player {1}", metadata.id), data, properties, true) # Construct player metadata hash @@ -789,7 +793,8 @@ def pbEditPlayerMetadata(player_id = 1) :surf_charset => data[4], :dive_charset => data[5], :fish_charset => data[6], - :surf_fish_charset => data[7] + :surf_fish_charset => data[7], + :home => data[8] } # Add player metadata's data to records GameData::PlayerMetadata.register(metadata_hash) @@ -819,13 +824,15 @@ def pbEditMapMetadata(map_id) metadata = GameData::MapMetadata.new({ :id => map_id }) if !metadata properties = GameData::MapMetadata.editor_properties properties.each do |property| - data.push(metadata.property_from_string(property[0])) + val = metadata.get_property_for_PBS(property[0]) + val = property[1].defaultValue if val.nil? && property[1].respond_to?(:defaultValue) + data.push(val) end if pbPropertyList(map_name, data, properties, true) # Construct map metadata hash metadata_hash = { :id => map_id, - :name => data[0], + :real_name => data[0], :outdoor_map => data[1], :announce_location => data[2], :can_bicycle => data[3], @@ -862,9 +869,9 @@ end #=============================================================================== def pbItemEditor field_use_array = [_INTL("Can't use in field")] - GameData::Item::SCHEMA["FieldUse"][2].each { |key, value| field_use_array[value] = key if !field_use_array[value] } + GameData::Item.schema["FieldUse"][2].each { |key, value| field_use_array[value] = key if !field_use_array[value] } battle_use_array = [_INTL("Can't use in battle")] - GameData::Item::SCHEMA["BattleUse"][2].each { |key, value| battle_use_array[value] = key if !battle_use_array[value] } + GameData::Item.schema["BattleUse"][2].each { |key, value| battle_use_array[value] = key if !battle_use_array[value] } item_properties = [ [_INTL("ID"), ReadOnlyProperty, _INTL("ID of this item (used as a symbol like :XXX).")], [_INTL("Name"), ItemNameProperty, _INTL("Name of this item as displayed by the game.")], diff --git a/Data/Scripts/020_Debug/002_Editor_DataTypes.rb b/Data/Scripts/020_Debug/002_Editor_DataTypes.rb index 8080a2a98..de0beff16 100644 --- a/Data/Scripts/020_Debug/002_Editor_DataTypes.rb +++ b/Data/Scripts/020_Debug/002_Editor_DataTypes.rb @@ -240,7 +240,7 @@ class StringListProperty def self.set(_setting_name, old_setting) real_cmds = [] real_cmds.push([_INTL("[ADD VALUE]"), -1]) - old_setting.length.times do + old_setting.length.times do |i| real_cmds.push([old_setting[i], 0]) end # Edit list diff --git a/Data/Scripts/021_Compiler/001_Compiler.rb b/Data/Scripts/021_Compiler/001_Compiler.rb index 72f74a5da..0f415c84e 100644 --- a/Data/Scripts/021_Compiler/001_Compiler.rb +++ b/Data/Scripts/021_Compiler/001_Compiler.rb @@ -92,7 +92,7 @@ module Compiler #============================================================================= # PBS file readers #============================================================================= - def pbEachFileSectionEx(f) + def pbEachFileSectionEx(f, schema = nil) lineno = 1 havesection = false sectionname = nil @@ -120,7 +120,12 @@ module Compiler end r1 = $~[1] r2 = $~[2] - lastsection[r1] = r2.gsub(/\s+$/, "") + if schema && schema[r1] && schema[r1][1][0] == "^" + lastsection[r1] ||= [] + lastsection[r1].push(r2.gsub(/\s+$/, "")) + else + lastsection[r1] = r2.gsub(/\s+$/, "") + end end end lineno += 1 @@ -133,15 +138,15 @@ module Compiler # pokemon.txt, pokemon_forms.txt, pokemon_metrics.txt, shadow_pokemon.txt, # ribbons.txt, trainer_types.txt, battle_facility_lists.txt, Battle Tower # trainers PBS files and dungeon_parameters.txt - def pbEachFileSection(f) - pbEachFileSectionEx(f) { |section, name| + def pbEachFileSection(f, schema = nil) + pbEachFileSectionEx(f, schema) { |section, name| yield section, name if block_given? && name[/^.+$/] } end # Used for metadata.txt and map_metadata.txt - def pbEachFileSectionNumbered(f) - pbEachFileSectionEx(f) { |section, name| + def pbEachFileSectionNumbered(f, schema = nil) + pbEachFileSectionEx(f, schema) { |section, name| yield section, name.to_i if block_given? && name[/^\d+$/] } end @@ -401,10 +406,14 @@ module Compiler def pbGetCsvRecord(rec, lineno, schema) record = [] repeat = false + schema_length = schema[1].length start = 0 if schema[1][0, 1] == "*" repeat = true start = 1 + elsif schema[1][0, 1] == "^" + start = 1 + schema_length -= 1 end subarrays = repeat && schema[1].length > 2 loop do @@ -560,7 +569,7 @@ module Compiler break if repeat && nil_or_empty?(rec) break unless repeat end - return (!repeat && schema[1].length == 1) ? record[0] : record + return (!repeat && schema_length == 1) ? record[0] : record end #============================================================================= @@ -568,7 +577,7 @@ module Compiler #============================================================================= def pbWriteCsvRecord(record, file, schema) rec = (record.is_a?(Array)) ? record.flatten : [record] - start = (schema[1][0, 1] == "*") ? 1 : 0 + start = (["*", "^"].include?(schema[1][0, 1])) ? 1 : 0 index = -1 loop do (start...schema[1].length).each do |i| diff --git a/Data/Scripts/021_Compiler/002_Compiler_CompilePBS.rb b/Data/Scripts/021_Compiler/002_Compiler_CompilePBS.rb index a8616ba76..00fa43090 100644 --- a/Data/Scripts/021_Compiler/002_Compiler_CompilePBS.rb +++ b/Data/Scripts/021_Compiler/002_Compiler_CompilePBS.rb @@ -1,58 +1,144 @@ module Compiler module_function + def compile_PBS_file_generic(game_data, path) + compile_pbs_file_message_start(path) + 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) + 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) + } + } + 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_message_start(path) - nonglobaltypes = { - "Name" => [0, "s"], - "Filename" => [1, "s"], - "Point" => [2, "uussUUUU"] - } - currentmap = -1 - rgnnames = [] - placenames = [] - placedescs = [] - sections = [] - pbCompilerEachCommentedLine(path) { |line, lineno| - if line[/^\s*\[\s*(\d+)\s*\]\s*$/] - currentmap = $~[1].to_i - sections[currentmap] = [] - else - if currentmap < 0 - raise _INTL("Expected a section at the beginning of the file\r\n{1}", FileLineData.linereport) - end - if !line[/^\s*(\w+)\s*=\s*(.*)$/] - raise _INTL("Bad line syntax (expected syntax like XXX=YYY)\r\n{1}", FileLineData.linereport) - end - settingname = $~[1] - schema = nonglobaltypes[settingname] - if schema - record = pbGetCsvRecord($~[2], lineno, schema) - case settingname - when "Name" - rgnnames[currentmap] = record - sections[currentmap][schema[0]] = record - when "Point" - placenames.push(record[2]) - placedescs.push(record[3]) - sections[currentmap][schema[0]] = [] if !sections[currentmap][schema[0]] - sections[currentmap][schema[0]].push(record) - else # Filename - sections[currentmap][schema[0]] = record + sections = [] + # 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 = { + "SectionName" => [:id, "u"], + "Name" => [:real_name, "s"], + "Filename" => [:filename, "s"], + "Point" => [:point, "^uussUUUU"] + } + 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) + 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 - end + # Validate and modify the compiled data + validate_compiled_town_map(data_hash) + if sections[data_hash[:id]] + raise _INTL("Region ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) + end + # Add town map messages to records + sections[data_hash[:id]] = [data_hash[:real_name], data_hash[:filename], data_hash[:point]] + } } + validate_all_compiled_town_maps(sections) + # Save all data save_data(sections, "Data/town_map.dat") - MessageTypes.setMessages(MessageTypes::RegionNames, rgnnames) - MessageTypes.setMessagesAsHash(MessageTypes::PlaceNames, placenames) - MessageTypes.setMessagesAsHash(MessageTypes::PlaceDescriptions, placedescs) process_pbs_file_message_end end + def validate_compiled_town_map(hash) + end + + def validate_all_compiled_town_maps(sections) + # Get town map names and descriptions for translating + region_names = [] + point_names = [] + interest_names = [] + sections.each_with_index do |region, i| + region_names[i] = region[0] + region[2].each do |point| + point_names.push(point[2]) + interest_names.push(point[3]) + end + end + MessageTypes.setMessages(MessageTypes::RegionNames, region_names) + MessageTypes.setMessagesAsHash(MessageTypes::PlaceNames, point_names) + MessageTypes.setMessagesAsHash(MessageTypes::PlaceDescriptions, interest_names) + end + #============================================================================= # Compile map connections #============================================================================= @@ -100,120 +186,46 @@ module Compiler # Compile phone messages #============================================================================= def compile_phone(path = "PBS/phone.txt") - return if !safeExists?(path) - compile_pbs_file_message_start(path) - GameData::PhoneMessage::DATA.clear - schema = GameData::PhoneMessage::SCHEMA - messages = [] - contact_hash = nil - # Read each line of phone.txt at a time and compile it as a contact 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 contact_hash - # Add contact's data to records - if contact_hash[:trainer_type] == "default" - contact_hash[:id] = contact_hash[:trainer_type] - else - contact_hash[:id] = [contact_hash[:trainer_type], contact_hash[:name], contact_hash[:version]] - end - GameData::PhoneMessage.register(contact_hash) - end - # Construct contact hash - header = $~[1] - if header.strip.downcase == "default" - contact_hash = { - :trainer_type => "default" - } - else - line_data = pbGetCsvRecord($~[1], line_no, [0, "esU", :TrainerType]) - contact_hash = { - :trainer_type => line_data[0], - :name => line_data[1], - :version => line_data[2] || 0 - } - end - elsif line[/^\s*(\w+)\s*=\s*(.*)$/] - # XXX=YYY lines - if !contact_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) - # Record XXX=YYY setting - contact_hash[line_schema[0]] ||= [] - contact_hash[line_schema[0]].push(property_value) - messages.push(property_value) - end - } - # Add last contact's data to records - if contact_hash - # Add contact's data to records - if contact_hash[:trainer_type] == "default" - contact_hash[:id] = contact_hash[:trainer_type] - else - contact_hash[:id] = [contact_hash[:trainer_type], contact_hash[:name], contact_hash[:version]] - end - GameData::PhoneMessage.register(contact_hash) + compile_PBS_file_generic(GameData::PhoneMessage, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_phone_contacts : validate_compiled_phone_contact(hash) + end + end + + def validate_compiled_phone_contact(hash) + # Split trainer type/name/version into their own values, generate compound ID from them + if hash[:id].strip.downcase == "default" + hash[:id] = "default" + hash[:trainer_type] = hash[:id] + else + line_data = pbGetCsvRecord(hash[:id], -1, [0, "esU", :TrainerType]) + hash[:trainer_type] = line_data[0] + hash[:real_name] = line_data[1] + hash[:version] = line_data[2] || 0 + hash[:id] = [hash[:trainer_type], hash[:real_name], hash[:version]] + end + end + + def validate_all_compiled_phone_contacts + # Get all phone messages for translating + messages = [] + GameData::PhoneMessage.each do |contact| + [:intro, :intro_morning, :intro_afternoon, :intro_evening, :body, :body1, + :body2, :battle_request, :battle_remind, :end].each do |msg_type| + msgs = contact.send(msg_type) + next if !msgs || msgs.length == 0 + msgs.each { |msg| messages.push(msg) } + end end - # Save all data - GameData::PhoneMessage.save MessageTypes.setMessagesAsHash(MessageTypes::PhoneMessages, messages) - process_pbs_file_message_end end #============================================================================= # Compile type data #============================================================================= def compile_types(path = "PBS/types.txt") - compile_pbs_file_message_start(path) - GameData::Type::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 = GameData::Type::SCHEMA - idx = 0 - pbEachFileSection(f) { |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 - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_type(data_hash) - if GameData::Type.exists?(data_hash[:id]) - raise _INTL("Type ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add type's data to records - GameData::Type.register(data_hash) - } - } - validate_all_compiled_types - # Save all data - GameData::Type.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::Type, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_types : validate_compiled_type(hash) + end end def validate_compiled_type(hash) @@ -249,48 +261,9 @@ module Compiler # Compile ability data #============================================================================= def compile_abilities(path = "PBS/abilities.txt") - compile_pbs_file_message_start(path) - GameData::Ability::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 = GameData::Ability::SCHEMA - idx = 0 - pbEachFileSection(f) { |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 - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_ability(data_hash) - if GameData::Ability.exists?(data_hash[:id]) - raise _INTL("Ability ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add ability's data to records - GameData::Ability.register(data_hash) - } - } - validate_all_compiled_abilities - # Save all data - GameData::Ability.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::Ability, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_abilities : validate_compiled_ability(hash) + end end def validate_compiled_ability(hash) @@ -312,48 +285,9 @@ module Compiler # Compile move data #============================================================================= def compile_moves(path = "PBS/moves.txt") - compile_pbs_file_message_start(path) - GameData::Move::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 = GameData::Move::SCHEMA - idx = 0 - pbEachFileSection(f) { |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 - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_move(data_hash) - if GameData::Move.exists?(data_hash[:id]) - raise _INTL("Move ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add move's data to records - GameData::Move.register(data_hash) - } - } - validate_all_compiled_moves - # Save all data - GameData::Move.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::Move, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_moves : validate_compiled_move(hash) + end end def validate_compiled_move(hash) @@ -383,48 +317,9 @@ module Compiler # Compile item data #============================================================================= def compile_items(path = "PBS/items.txt") - compile_pbs_file_message_start(path) - GameData::Item::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 = GameData::Item::SCHEMA - idx = 0 - pbEachFileSection(f) { |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 - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_item(data_hash) - if GameData::Item.exists?(data_hash[:id]) - raise _INTL("Item ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add item's data to records - GameData::Item.register(data_hash) - } - } - validate_all_compiled_items - # Save all data - GameData::Item.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::Item, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_items : validate_compiled_item(hash) + end end def validate_compiled_item(hash) @@ -449,48 +344,9 @@ module Compiler # Compile berry plant data #============================================================================= def compile_berry_plants(path = "PBS/berry_plants.txt") - compile_pbs_file_message_start(path) - GameData::BerryPlant::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 = GameData::BerryPlant::SCHEMA - idx = 0 - pbEachFileSection(f) { |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 - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_berry_plant(data_hash) - if GameData::BerryPlant.exists?(data_hash[:id]) - raise _INTL("Berry plant ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add berry plant's data to records - GameData::BerryPlant.register(data_hash) - } - } - validate_all_compiled_berry_plants - # Save all data - GameData::BerryPlant.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::BerryPlant, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_berry_plants : validate_compiled_berry_plant(hash) + end end def validate_compiled_berry_plant(hash) @@ -503,48 +359,9 @@ module Compiler # Compile Pokémon data #============================================================================= def compile_pokemon(path = "PBS/pokemon.txt") - compile_pbs_file_message_start(path) - GameData::Species::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 = GameData::Species.schema - idx = 0 - pbEachFileSection(f) { |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 - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_pokemon(data_hash) - if GameData::Species.exists?(data_hash[:id]) - raise _INTL("Species ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add species's data to records - GameData::Species.register(data_hash) - } - } - validate_all_compiled_pokemon - # Save all data - GameData::Species.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::Species, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_pokemon : validate_compiled_pokemon(hash) + end end # NOTE: This method is also called by def validate_compiled_pokemon_form @@ -630,6 +447,8 @@ module Compiler #============================================================================= # Compile Pokémon forms data + # 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) @@ -641,7 +460,7 @@ module Compiler # the keys are the XXX and the values are the YYY (as unprocessed strings). schema = GameData::Species.schema(true) idx = 0 - pbEachFileSection(f) { |contents, section_name| + pbEachFileSection(f, schema) { |contents, section_name| echo "." if idx % 50 == 0 Graphics.update if idx % 250 == 0 idx += 1 @@ -656,16 +475,26 @@ module Compiler # Skip empty properties next if contents[key].nil? # Compile value for key - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value + 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 validate_compiled_pokemon_form(data_hash) if GameData::Species.exists?(data_hash[:id]) - raise _INTL("Species ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) + raise _INTL("Section name '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) end - # Add species's data to records + # Add section's data to records GameData::Species.register(data_hash) } } @@ -752,48 +581,9 @@ module Compiler # Compile Pokémon metrics data #============================================================================= def compile_pokemon_metrics(path = "PBS/pokemon_metrics.txt") - compile_pbs_file_message_start(path) - GameData::SpeciesMetrics::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 = GameData::SpeciesMetrics::SCHEMA - idx = 0 - pbEachFileSection(f) { |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 - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_pokemon_metrics(data_hash) - if GameData::SpeciesMetrics.exists?(data_hash[:id]) - raise _INTL("Metrics for species '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add species' metrics to records - GameData::SpeciesMetrics.register(data_hash) - } - } - validate_all_compiled_pokemon_metrics - # Save all data - GameData::SpeciesMetrics.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::SpeciesMetrics, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_pokemon_metrics : validate_compiled_pokemon_metrics(hash) + end end def validate_compiled_pokemon_metrics(hash) @@ -816,48 +606,9 @@ module Compiler # Compile Shadow Pokémon data #============================================================================= def compile_shadow_pokemon(path = "PBS/shadow_pokemon.txt") - compile_pbs_file_message_start(path) - GameData::ShadowPokemon::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 = GameData::ShadowPokemon::SCHEMA - idx = 0 - pbEachFileSection(f) { |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 - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_shadow_pokemon(data_hash) - if GameData::ShadowPokemon.exists?(data_hash[:id]) - raise _INTL("Species ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add Shadow Pokémon data to records - GameData::ShadowPokemon.register(data_hash) - } - } - validate_all_compiled_shadow_pokemon - # Save all data - GameData::ShadowPokemon.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::ShadowPokemon, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_shadow_pokemon : validate_compiled_shadow_pokemon(hash) + end end def validate_compiled_shadow_pokemon(hash) @@ -909,48 +660,9 @@ module Compiler # Compile ribbon data #============================================================================= def compile_ribbons(path = "PBS/ribbons.txt") - compile_pbs_file_message_start(path) - GameData::Ribbon::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 = GameData::Ribbon::SCHEMA - idx = 0 - pbEachFileSection(f) { |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 - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_ribbon(data_hash) - if GameData::Ribbon.exists?(data_hash[:id]) - raise _INTL("Ribbon ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add ribbon data to records - GameData::Ribbon.register(data_hash) - } - } - validate_all_compiled_ribbons - # Save all data - GameData::Ribbon.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::Ribbon, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_ribbons : validate_compiled_ribbon(hash) + end end def validate_compiled_ribbon(hash) @@ -1081,48 +793,9 @@ module Compiler # Compile trainer type data #============================================================================= def compile_trainer_types(path = "PBS/trainer_types.txt") - compile_pbs_file_message_start(path) - GameData::TrainerType::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 = GameData::TrainerType::SCHEMA - idx = 0 - pbEachFileSection(f) { |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 - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_trainer_type(data_hash) - if GameData::TrainerType.exists?(data_hash[:id]) - raise _INTL("Trainer type ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add trainer type data to records - GameData::TrainerType.register(data_hash) - } - } - validate_all_compiled_trainer_types - # Save all data - GameData::TrainerType.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::TrainerType, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_trainer_types : validate_compiled_trainer_type(hash) + end end def validate_compiled_trainer_type(hash) @@ -1143,7 +816,7 @@ module Compiler def compile_trainers(path = "PBS/trainers.txt") compile_pbs_file_message_start(path) GameData::Trainer::DATA.clear - schema = GameData::Trainer::SCHEMA + schema = GameData::Trainer.schema max_level = GameData::GrowthRate.max_level trainer_names = [] trainer_lose_texts = [] @@ -1386,6 +1059,8 @@ module Compiler #============================================================================= # Compile metadata + # 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) @@ -1397,31 +1072,41 @@ module Compiler # 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 + global_schema = GameData::Metadata.schema + player_schema = GameData::PlayerMetadata.schema idx = 0 - pbEachFileSectionNumbered(f) { |contents, section_name| + pbEachFileSection(f) { |contents, section_name| echo "." if idx % 50 == 0 Graphics.update if idx % 250 == 0 idx += 1 - schema = (section_name == 0) ? global_schema : player_schema - data_hash = {:id => section_name} + 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.to_s, key, contents[key]) # For error reporting + FileLineData.setSection(section_name, key, contents[key]) # For error reporting if key == "SectionName" - data_hash[schema[key][0]] = pbGetCsvRecord(section_name.to_s, key, schema[key]) + 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 - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value + 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 section_name == 0 + 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) @@ -1432,8 +1117,8 @@ module Compiler raise _INTL("Player metadata ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) end end - # Add trainer type data to records - if section_name == 0 + # Add section's data to records + if data_hash[:id] == 0 GameData::Metadata.register(data_hash) else GameData::PlayerMetadata.register(data_hash) @@ -1456,6 +1141,7 @@ module Compiler def validate_compiled_player_metadata(hash) end + # Should be used to check both global metadata and player character metadata. def validate_all_compiled_metadata # Ensure global metadata is defined if !GameData::Metadata.exists?(0) @@ -1474,48 +1160,9 @@ module Compiler # Compile map metadata #============================================================================= def compile_map_metadata(path = "PBS/map_metadata.txt") - compile_pbs_file_message_start(path) - GameData::MapMetadata::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 = GameData::MapMetadata::SCHEMA - idx = 0 - pbEachFileSectionNumbered(f) { |contents, section_name| - echo "." if idx % 50 == 0 - Graphics.update if idx % 250 == 0 - idx += 1 - data_hash = {:id => section_name} - # Go through schema hash of compilable data and compile this section - schema.each_key do |key| - FileLineData.setSection(section_name.to_s, key, contents[key]) # For error reporting - if key == "SectionName" - data_hash[schema[key][0]] = pbGetCsvRecord(section_name.to_s, key, schema[key]) - next - end - # Skip empty properties - next if contents[key].nil? - # Compile value for key - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_map_metadata(data_hash) - if GameData::MapMetadata.exists?(data_hash[:id]) - raise _INTL("Map metadata for map '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add map metadata to records - GameData::MapMetadata.register(data_hash) - } - } - validate_all_compiled_map_metadata - # Save all data - GameData::MapMetadata.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::MapMetadata, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_map_metadata : validate_compiled_map_metadata(hash) + end end def validate_compiled_map_metadata(hash) @@ -1528,9 +1175,7 @@ module Compiler def validate_all_compiled_map_metadata # Get map names for translating map_names = [] - GameData::MapMetadata.each do |map| - map_names[map.id] = map.real_name - end + GameData::MapMetadata.each { |map| map_names[map.id] = map.real_name } MessageTypes.setMessages(MessageTypes::MapNames, map_names) end @@ -1538,97 +1183,24 @@ module Compiler # Compile dungeon tileset data #============================================================================= def compile_dungeon_tilesets(path = "PBS/dungeon_tilesets.txt") - compile_pbs_file_message_start(path) - GameData::DungeonTileset::DATA.clear - schema = GameData::DungeonTileset::SCHEMA - tileset_hash = nil - # Read each line of dungeon_tilesets.txt at a time and compile it as a tileset 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 - # Add tileset's data to records - GameData::DungeonTileset.register(tileset_hash) if tileset_hash - # Construct tileset hash - tileset_hash = { - :id => $~[1].to_i, - :tile => [], - :autotile => [] - } - elsif line[/^\s*(\w+)\s*=\s*(.*)$/] - # XXX=YYY lines - if !tileset_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) - # Record XXX=YYY setting - case property_name - when "Tile", "Autotile" - tileset_hash[line_schema[0]].push(property_value) - else - tileset_hash[line_schema[0]] = property_value - end - end - } - # Add last tileset's data to records - GameData::DungeonTileset.register(tileset_hash) if tileset_hash - # Save all data - GameData::DungeonTileset.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::DungeonTileset, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_dungeon_tilesets : validate_compiled_dungeon_tileset(hash) + end + end + + def validate_compiled_dungeon_tileset(hash) + end + + def validate_all_compiled_dungeon_tilesets end #============================================================================= # Compile dungeon parameters data #============================================================================= def compile_dungeon_parameters(path = "PBS/dungeon_parameters.txt") - compile_pbs_file_message_start(path) - GameData::DungeonParameters::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 = GameData::DungeonParameters::SCHEMA - idx = 0 - pbEachFileSection(f) { |contents, section_name| - echo "." if idx % 50 == 0 - Graphics.update if idx % 250 == 0 - idx += 1 - data_hash = {:id => section_name} - # Go through schema hash of compilable data and compile this section - schema.each_key do |key| - FileLineData.setSection(section_name.to_s, key, contents[key]) # For error reporting - if key == "SectionName" - data_hash[schema[key][0]] = pbGetCsvRecord(section_name.to_s, key, schema[key]) - next - end - # Skip empty properties - next if contents[key].nil? - # Compile value for key - value = pbGetCsvRecord(contents[key], key, schema[key]) - value = nil if value.is_a?(Array) && value.empty? - data_hash[schema[key][0]] = value - end - # Validate and modify the compiled data - validate_compiled_dungeon_parameters(data_hash) - if GameData::DungeonParameters.exists?(data_hash[:id]) - raise _INTL("Dungeon ID '{1}' is used twice.\r\n{2}", data_hash[:id], FileLineData.linereport) - end - # Add dungeon parameters to records - GameData::DungeonParameters.register(data_hash) - } - } - validate_all_compiled_dungeon_parameters - # Save all data - GameData::DungeonParameters.save - process_pbs_file_message_end + compile_PBS_file_generic(GameData::DungeonParameters, path) do |final_validate, hash| + (final_validate) ? validate_all_compiled_dungeon_parameters : validate_compiled_dungeon_parameters(hash) + end end def validate_compiled_dungeon_parameters(hash) diff --git a/Data/Scripts/021_Compiler/003_Compiler_WritePBS.rb b/Data/Scripts/021_Compiler/003_Compiler_WritePBS.rb index ec31f3d51..c93410f9b 100644 --- a/Data/Scripts/021_Compiler/003_Compiler_WritePBS.rb +++ b/Data/Scripts/021_Compiler/003_Compiler_WritePBS.rb @@ -10,7 +10,7 @@ module Compiler def write_PBS_file_generic(game_data, path) write_pbs_file_message_start(path) - schema = game_data::SCHEMA + schema = game_data.schema File.open(path, "wb") { |f| add_PBS_header_to_file(f) # Write each element in turn @@ -27,9 +27,17 @@ module Compiler next if key == "SectionName" val = element.get_property_for_PBS(key) next if val.nil? - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") + 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 } @@ -40,27 +48,32 @@ module Compiler # Save Town Map data to PBS file #============================================================================= def write_town_map(path = "PBS/town_map.txt") - mapdata = pbLoadTownMapData - return if !mapdata write_pbs_file_message_start(path) + schema = { + "Name" => [0, "s"], + "Filename" => [1, "s"], + "Point" => [2, "^uussUUUU"] + } File.open(path, "wb") { |f| - idx = 0 add_PBS_header_to_file(f) - mapdata.length.times do |i| - echo "." if idx % 50 == 0 - idx += 1 - Graphics.update if idx % 250 == 0 - map = mapdata[i] - next if !map + # Write each element in turn + pbLoadTownMapData.each_with_index do |element, i| f.write("\#-------------------------------\r\n") f.write(sprintf("[%d]\r\n", i)) - rname = pbGetMessage(MessageTypes::RegionNames, i) - f.write(sprintf("Name = %s\r\n", (rname && rname != "") ? rname : _INTL("Unnamed"))) - f.write(sprintf("Filename = %s\r\n", csvQuote((map[1].is_a?(Array)) ? map[1][0] : map[1]))) - map[2].each do |loc| - f.write("Point = ") - pbWriteCsvRecord(loc, f, [nil, "uussUUUU"]) - f.write("\r\n") + schema.each_key do |key| + val = element[schema[key][0]] + 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 } @@ -131,28 +144,7 @@ module Compiler # Save phone messages to PBS file #============================================================================= def write_phone(path = "PBS/phone.txt") - write_pbs_file_message_start(path) - keys = GameData::PhoneMessage::SCHEMA.keys - File.open(path, "wb") { |f| - add_PBS_header_to_file(f) - # Write message sets - GameData::PhoneMessage.each do |contact| - f.write("\#-------------------------------\r\n") - if contact.id == "default" - f.write("[Default]\r\n") - elsif contact.version > 0 - f.write(sprintf("[%s,%s,%d]\r\n", contact.trainer_type, contact.real_name, contact.version)) - else - f.write(sprintf("[%s,%s]\r\n", contact.trainer_type, contact.real_name)) - end - keys.each do |key| - msgs = contact.property_from_string(key) - next if !msgs || msgs.length == 0 - msgs.each { |msg| f.write(key + " = " + msg + "\r\n") } - end - end - } - process_pbs_file_message_end + write_PBS_file_generic(GameData::PhoneMessage, path) end #============================================================================= @@ -192,6 +184,8 @@ module Compiler #============================================================================= # Save Pokémon data to PBS file + # 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) @@ -212,9 +206,17 @@ module Compiler next if key == "SectionName" val = element.get_property_for_PBS(key) next if val.nil? - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") + 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 } @@ -223,6 +225,8 @@ module Compiler #============================================================================= # Save Pokémon forms data to PBS file + # 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) @@ -244,9 +248,17 @@ module Compiler next if key == "SectionName" val = element.get_property_for_PBS(key, true) next if val.nil? - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") + 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 } @@ -255,10 +267,13 @@ module Compiler #============================================================================= # Write species metrics + # NOTE: Doesn't use write_PBS_file_generic because it needs to ignore defined + # 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) - schema = GameData::SpeciesMetrics::SCHEMA + schema = GameData::SpeciesMetrics.schema File.open(path, "wb") { |f| add_PBS_header_to_file(f) # Write each element in turn @@ -270,10 +285,6 @@ module Compiler element.front_sprite_altitude == base_element.front_sprite_altitude && element.shadow_x == base_element.shadow_x && element.shadow_size == base_element.shadow_size - else - next if element.back_sprite == [0, 0] && element.front_sprite == [0, 0] && - element.front_sprite_altitude == 0 && - element.shadow_x == 0 && element.shadow_size == 2 end f.write("\#-------------------------------\r\n") if schema["SectionName"] @@ -287,9 +298,17 @@ module Compiler next if key == "SectionName" val = element.get_property_for_PBS(key) next if val.nil? - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") + 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 } @@ -556,11 +575,13 @@ module Compiler #============================================================================= # Save metadata data to PBS file + # 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) - global_schema = GameData::Metadata::SCHEMA - player_schema = GameData::PlayerMetadata::SCHEMA + 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 @@ -580,9 +601,17 @@ module Compiler next if key == "SectionName" val = element.get_property_for_PBS(key) next if val.nil? - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") + 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 @@ -592,11 +621,13 @@ module Compiler #============================================================================= # 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 + schema = GameData::MapMetadata.schema File.open(path, "wb") { |f| idx = 0 add_PBS_header_to_file(f) @@ -613,9 +644,17 @@ module Compiler next if key == "SectionName" val = element.get_property_for_PBS(key) next if val.nil? - f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(val, f, schema[key]) - f.write("\r\n") + 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 } @@ -624,48 +663,40 @@ module Compiler #============================================================================= # 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 - keys = schema.keys + schema = GameData::DungeonTileset.schema File.open(path, "wb") { |f| - idx = 0 add_PBS_header_to_file(f) - GameData::DungeonTileset.each do |tileset_data| - echo "." if idx % 50 == 0 - idx += 1 - Graphics.update if idx % 250 == 0 + # Write each element in turn + GameData::DungeonTileset.each do |element| f.write("\#-------------------------------\r\n") - tileset_name = (tilesets && tilesets[tileset_data.id]) ? tilesets[tileset_data.id].name : nil - if tileset_name - f.write(sprintf("[%d] # %s\r\n", tileset_data.id, tileset_name)) + 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(sprintf("[%d]\r\n", tileset_data.id)) + f.write("[#{element.id}]\r\n") end - keys.each do |key| - if ["Autotile", "Tile"].include?(key) - tiles = tileset_data.tile_type_ids - tiles.each do |tile_type, tile_ids| - tile_ids.each do |tile| - next if tile[1] # Tile was auto-generated from "walls" property - if tile[0] < 384 - next if key == "Tile" - f.write(sprintf("Autotile = %i,%s", tile[0] / 48, tile_type.to_s)) - else - next if key == "Autotile" - f.write(sprintf("Tile = %i,%s", tile[0] - 384, tile_type.to_s)) - end - f.write("\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 - record = tileset_data.property_from_string(key) - next if record.nil? || (record.is_a?(Array) && record.empty?) - next if record == false || record == 0 f.write(sprintf("%s = ", key)) - pbWriteCsvRecord(record, f, schema[key]) + pbWriteCsvRecord(val, f, schema[key]) f.write("\r\n") end end diff --git a/PBS/phone.txt b/PBS/phone.txt index c8084c76f..46080d9c1 100644 --- a/PBS/phone.txt +++ b/PBS/phone.txt @@ -28,7 +28,7 @@ Body1 = My \TP is looking more and more like me. It's getting cuter! Body2 = And you know? Now we can KO \TE easily.\mI should challenge the Cedolan Gym. Body2 = And you know? We just failed to beat \TE by a tiny margin.\mI'm guessing my Pokémon's levels aren't high enough yet... BattleRequest = You must be a lot better now, huh?\mHow about showing me your technique in a real battle with me?\mI'll be waiting on \TM. -BattleReminder = Where are you? Let's have our battle soon!\mI'll be waiting on \TM. +BattleRemind = Where are you? Let's have our battle soon!\mI'll be waiting on \TM. End = See you later! #------------------------------- [PICNICKER,Susie] @@ -44,5 +44,5 @@ Body1 = My \TP and I are getting more in sync with each other. Body2 = We battled a wild \TE and managed to beat it in a close match.\mWe're getting into the groove! Body2 = But, you know what? I still haven't caught \TE.\mIt's getting beyond frustrating... BattleRequest = Would you be my practice partner again sometime?\mI'll be waiting on \TM...\mCould you take it a little easier on me next time? -BattleReminder = How soon can I expect to see you?\mDon't forget, \TM! +BattleRemind = How soon can I expect to see you?\mDon't forget, \TM! End = Bye! Let's chat again! diff --git a/PBS/town_map.txt b/PBS/town_map.txt index c0cacc79f..11891d45a 100644 --- a/PBS/town_map.txt +++ b/PBS/town_map.txt @@ -3,34 +3,34 @@ [0] Name = Essen Filename = mapRegion0.png -Point = 13,12,Lappet Town,Oak's Lab,2,8,8, -Point = 13,11,Route 1,,,,, -Point = 13,10,Cedolan City,Cedolan Dept. Store,7,47,11, -Point = 14,10,Cedolan City,,7,47,11, -Point = 14,9,Route 2,,,,, -Point = 14,8,Route 2,,,,, -Point = 15,8,Lerucean Town,,23,11,15, -Point = 16,8,Natural Park,,,,, -Point = 15,7,Route 3,,,,, -Point = 15,6,Route 3,Ice Cave,,,, -Point = 14,6,Route 3,,,,, -Point = 13,6,Ingido Plateau,,35,17,7, -Point = 12,6,Route 4,,,,, -Point = 11,6,Route 4,,,,, -Point = 11,7,Route 5,Cycle Road,,,, -Point = 11,8,Route 5,Cycle Road,,,, -Point = 11,9,Route 5,Cycle Road,,,, -Point = 11,10,Route 6,,,,, -Point = 12,10,Route 6,,,,, -Point = 15,10,Route 7,,,,, -Point = 16,10,Route 7,Rock Cave,,,, -Point = 17,10,Battle Frontier,,52,17,14, -Point = 12,12,Safari Zone,,,,, -Point = 13,13,Route 8,Diving area,,,, -Point = 18,17,Berth Island,,,,,51 -Point = 22,16,Faraday Island,,,,,52 +Point = 13,12,Lappet Town,Oak's Lab,2,8,8 +Point = 13,11,Route 1, +Point = 13,10,Cedolan City,Cedolan Dept. Store,7,47,11 +Point = 14,10,Cedolan City,,7,47,11 +Point = 14,9,Route 2, +Point = 14,8,Route 2, +Point = 15,8,Lerucean Town,,23,11,15 +Point = 16,8,Natural Park, +Point = 15,7,Route 3, +Point = 15,6,Route 3,Ice Cave +Point = 14,6,Route 3, +Point = 13,6,Ingido Plateau,,35,17,7 +Point = 12,6,Route 4, +Point = 11,6,Route 4, +Point = 11,7,Route 5,Cycle Road +Point = 11,8,Route 5,Cycle Road +Point = 11,9,Route 5,Cycle Road +Point = 11,10,Route 6, +Point = 12,10,Route 6, +Point = 15,10,Route 7, +Point = 16,10,Route 7,Rock Cave +Point = 17,10,Battle Frontier,,52,17,14 +Point = 12,12,Safari Zone, +Point = 13,13,Route 8,Diving area +Point = 18,17,Berth Island,,51 +Point = 22,16,Faraday Island,,52 #------------------------------- [1] Name = Tiall Filename = mapRegion1.png -Point = 13,16,Here,,,,, +Point = 13,16,Here,