#=============================================================================== # Compile metadata #=============================================================================== class PBTrainers; end def pbCompileMetadata sections = [] currentmap = -1 pbCompilerEachCommentedLine("PBS/metadata.txt") { |line,lineno| if line[/^\s*\[\s*(\d+)\s*\]\s*$/] sectionname = $~[1] if currentmap==0 if sections[currentmap][MetadataHome]==nil raise _INTL("The entry Home is required in metadata.txt section [{1}]",sectionname) end if sections[currentmap][MetadataPlayerA]==nil raise _INTL("The entry PlayerA is required in metadata.txt section [{1}]",sectionname) end end currentmap = sectionname.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 matchData = $~ schema = nil FileLineData.setSection(currentmap,matchData[1],matchData[2]) if currentmap==0 schema = PokemonMetadata::GlobalTypes[matchData[1]] else schema = PokemonMetadata::NonGlobalTypes[matchData[1]] end if schema record = pbGetCsvRecord(matchData[2],lineno,schema) sections[currentmap][schema[0]] = record end end } save_data(sections,"Data/metadata.dat") end #=============================================================================== # Compile town map points #=============================================================================== def pbCompileTownMap nonglobaltypes = { "Name" => [0, "s"], "Filename" => [1, "s"], "Point" => [2, "uussUUUU"] } currentmap = -1 rgnnames = [] placenames = [] placedescs = [] sections = [] pbCompilerEachCommentedLine("PBS/townmap.txt") { |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) if settingname=="Name" rgnnames[currentmap] = record elsif settingname=="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 end end end } save_data(sections,"Data/town_map.dat") MessageTypes.setMessages(MessageTypes::RegionNames,rgnnames) MessageTypes.setMessagesAsHash(MessageTypes::PlaceNames,placenames) MessageTypes.setMessagesAsHash(MessageTypes::PlaceDescriptions,placedescs) end #=============================================================================== # Compile map connections #=============================================================================== def pbCompileConnections records = [] constants = "" itemnames = [] pbCompilerEachPreppedLine("PBS/connections.txt") { |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])) && !pbRgssExists?(sprintf("Data/Map%03d.rvdata",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])) && !pbRgssExists?(sprintf("Data/Map%03d.rvdata",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) } save_data(records,"Data/map_connections.dat") Graphics.update end #=============================================================================== # Compile berry plants #=============================================================================== def pbCompileBerryPlants sections = [] if File.exists?("PBS/berryplants.txt") pbCompilerEachCommentedLine("PBS/berryplants.txt") { |line,lineno| if line[ /^\s*(\w+)\s*=\s*(.*)$/ ] key = $1 value = $2 value = value.split(",") for i in 0...value.length value[i].sub!(/^\s*/,"") value[i].sub!(/\s*$/,"") value[i] = value[i].to_i end item = parseItem(key) sections[item] = value end } end save_data(sections,"Data/berry_plants.dat") end #=============================================================================== # Compile phone messages #=============================================================================== def pbCompilePhoneData return if !safeExists?("PBS/phone.txt") database = PhoneDatabase.new sections = [] File.open("PBS/phone.txt","rb") { |f| pbEachSection(f) { |section,name| case name when "" database.generics=section sections.concat(section) when "" database.battleRequests=section sections.concat(section) when "" database.greetingsMorning=section sections.concat(section) when "" database.greetingsEvening=section sections.concat(section) when "" database.greetings=section sections.concat(section) when "" database.bodies1=section sections.concat(section) when "" database.bodies2=section sections.concat(section) end } } MessageTypes.setMessagesAsHash(MessageTypes::PhoneMessages,sections) save_data(database,"Data/phone.dat") end #=============================================================================== # Compile types #=============================================================================== def pbWriteDefaultTypes if !safeExists?("PBS/types.txt") File.open("PBS/types.txt","w") { |f| f.write(0xEF.chr) f.write(0xBB.chr) f.write(0xBF.chr) fx=< [1, "s"], "InternalName" => [2, "s"], } optionaltypes = { "IsPseudoType" => [3, "b"], "IsSpecialType" => [4, "b"], "Weaknesses" => [5, "*s"], "Resistances" => [6, "*s"], "Immunities" => [7, "*s"] } currentmap = -1 foundtypes = [] pbCompilerEachCommentedLine("PBS/types.txt") { |line,lineno| if line[/^\s*\[\s*(\d+)\s*\]\s*$/] sectionname = $~[1] if currentmap>=0 for reqtype in requiredtypes.keys if !foundtypes.include?(reqtype) raise _INTL("Required value '{1}' not given in section '{2}'\r\n{3}",reqtype,currentmap,FileLineData.linereport) end end foundtypes.clear end currentmap = sectionname.to_i types[currentmap] = [currentmap,nil,nil,false,false,[],[],[]] 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 matchData = $~ schema = nil FileLineData.setSection(currentmap,matchData[1],matchData[2]) if requiredtypes.keys.include?(matchData[1]) schema = requiredtypes[matchData[1]] foundtypes.push(matchData[1]) else schema = optionaltypes[matchData[1]] end if schema record = pbGetCsvRecord(matchData[2],lineno,schema) types[currentmap][schema[0]] = record end end } types.compact! maxValue = 0 for type in types; maxValue = [maxValue,type[0]].max; end pseudotypes = [] specialtypes = [] typenames = [] typeinames = [] typehash = {} for type in types pseudotypes.push(type[0]) if type[3] typenames[type[0]] = type[1] typeinames[type[0]] = type[2] typehash[type[0]] = type end for type in types n = type[1] for w in type[5] if !typeinames.include?(w) raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Weaknesses)",w,n) end end for w in type[6] if !typeinames.include?(w) raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Resistances)",w,n) end end for w in type[7] if !typeinames.include?(w) raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Immunities)",w,n) end end end for i in 0..maxValue pseudotypes.push(i) if !typehash[i] end pseudotypes.sort! types.each { |type| specialtypes.push(type[0]) if type[4] } specialtypes.sort! count = maxValue+1 for i in 0...count type = typehash[i] j = 0; k = i; while j>3 curpos = 0 for i in 0...numrec file.pos = curpos offset = file.fgetdw length = file.fgetdw record = SerialRecord.decode(file,offset,length) ret[record[0]] = record curpos += 8 end } return ret end def pbCompileItems records = [] constants = "" itemnames = [] itempluralnames = [] itemdescs = [] maxValue = 0 pbCompilerEachCommentedLine("PBS/items.txt") { |line,lineno| linerecord = pbGetCsvRecord(line,lineno,[0,"vnssuusuuUN"]) id = linerecord[0] record = [] record[ITEM_ID] = id constant = linerecord[1] constants += "#{constant}=#{id}\r\n" record[ITEM_NAME] = linerecord[2] itemnames[id] = linerecord[2] record[ITEM_PLURAL] = linerecord[3] itempluralnames[id] = linerecord[3] record[ITEM_POCKET] = linerecord[4] record[ITEM_PRICE] = linerecord[5] record[ITEM_DESCRIPTION] = linerecord[6] itemdescs[id] = linerecord[6] record[ITEM_FIELD_USE] = linerecord[7] record[ITEM_BATTLE_USE] = linerecord[8] record[ITEM_TYPE] = linerecord[9] if record[ITEM_TYPE]!="" && linerecord[10] record[ITEM_MACHINE] = parseMove(linerecord[10]) else record[ITEM_MACHINE] = 0 end maxValue = [maxValue,id].max records[id] = record } MessageTypes.setMessages(MessageTypes::Items,itemnames) MessageTypes.setMessages(MessageTypes::ItemPlurals,itempluralnames) MessageTypes.setMessages(MessageTypes::ItemDescriptions,itemdescs) save_data(records,"Data/items.dat") code = "class PBItems\r\n" code += constants code += "def self.getName(id)\r\n" code += "id=getID(PBItems,id)\r\n" code += "return pbGetMessage(MessageTypes::Items,id); end\r\n" code += "def self.getNamePlural(id)\r\n" code += "id=getID(PBItems,id)\r\n" code += "return pbGetMessage(MessageTypes::ItemPlurals,id); end\r\n" code += "def self.getCount; return #{records.length}; end\r\n" code += "def self.maxValue; return #{maxValue}; end\r\n" code += "end\r\n" eval(code) pbAddScript(code,"PBItems") Graphics.update end #=============================================================================== # Compile move data #=============================================================================== def pbCompileMoves records = [] moveNames = [] moveDescs = [] maxValue = 0 count = 0 pbCompilerEachPreppedLine("PBS/moves.txt") { |line,lineno| thisline = line.clone record = [] lineRecord = pbGetCsvRecord(line,lineno,[0,"vnssueeuuuyiss", nil,nil,nil,nil,nil,PBTypes,["Physical","Special","Status"], nil,nil,nil,PBTargets,nil,nil,nil ]) if lineRecord[6]==2 && lineRecord[4]!=0 raise _INTL("Status moves must have a base damage of 0, use either Physical or Special\r\n{1}",FileLineData.linereport) end if lineRecord[6]!=2 && lineRecord[4]==0 print _INTL("Warning: Physical and special moves can't have a base damage of 0, changing to a Status move\r\n{1}",FileLineData.linereport) lineRecord[6] = 2 end record[MOVE_ID] = lineRecord[0] record[MOVE_INTERNAL_NAME] = lineRecord[1] record[MOVE_NAME] = lineRecord[2] record[MOVE_FUNCTION_CODE] = lineRecord[3] record[MOVE_BASE_DAMAGE] = lineRecord[4] record[MOVE_TYPE] = lineRecord[5] record[MOVE_CATEGORY] = lineRecord[6] record[MOVE_ACCURACY] = lineRecord[7] record[MOVE_TOTAL_PP] = lineRecord[8] record[MOVE_EFFECT_CHANCE] = lineRecord[9] record[MOVE_TARGET] = lineRecord[10] record[MOVE_PRIORITY] = lineRecord[11] record[MOVE_FLAGS] = lineRecord[12] record[MOVE_DESCRIPTION] = lineRecord[13] maxValue = [maxValue,lineRecord[0]].max count += 1 moveNames[lineRecord[0]] = lineRecord[2] # Name moveDescs[lineRecord[0]] = lineRecord[13] # Description records[lineRecord[0]] = record } save_data(records,"Data/moves.dat") MessageTypes.setMessages(MessageTypes::Moves,moveNames) MessageTypes.setMessages(MessageTypes::MoveDescriptions,moveDescs) code = "class PBMoves\r\n" for rec in records code += "#{rec[MOVE_INTERNAL_NAME]}=#{rec[MOVE_ID]}\r\n" if rec end code += "def self.getName(id)\r\n" code += "id=getID(PBMoves,id)\r\n" code += "return pbGetMessage(MessageTypes::Moves,id); end\r\n" code += "def self.getCount; return #{count}; end\r\n" code += "def self.maxValue; return #{maxValue}; end\r\n" code += "end\r\n" eval(code) pbAddScript(code,"PBMoves") end #=============================================================================== # Compile battle animations #=============================================================================== def pbCompileAnimations begin if $RPGVX pbanims = load_data("Data/PkmnAnimations.rvdata") else pbanims = load_data("Data/PkmnAnimations.rxdata") end rescue pbanims = PBAnimations.new end move2anim = [[],[]] =begin if $RPGVX anims = load_data("Data/Animations.rvdata") else anims = load_data("Data/Animations.rxdata") end for anim in anims next if !anim || anim.frames.length==1 found = false for i in 0...pbanims.length if pbanims[i] && pbanims[i].id==anim.id found = true if pbanims[i].array.length>1 break end end pbanims[anim.id] = pbConvertRPGAnimation(anim) if !found end =end for i in 0...pbanims.length next if !pbanims[i] if pbanims[i].name[/^OppMove\:\s*(.*)$/] if hasConst?(PBMoves,$~[1]) moveid = PBMoves.const_get($~[1]) move2anim[1][moveid] = i end elsif pbanims[i].name[/^Move\:\s*(.*)$/] if hasConst?(PBMoves,$~[1]) moveid = PBMoves.const_get($~[1]) move2anim[0][moveid] = i end end end save_data(move2anim,"Data/move2anim.dat") save_data(pbanims,"Data/PkmnAnimations.rxdata") end #=============================================================================== # Compile Pokémon #=============================================================================== def pbCompilePokemonData # Get schemas. requiredValues = PokemonSpeciesData.requiredValues optionalValues = PokemonSpeciesData.optionalValues # Prepare arrays for compiled data. speciesData = [] movesets = [] eggMoves = [] regionalDexes = [] spriteMetrics = [] evolutions = [] speciesNames = [] formNames = [] pokedexKinds = [] pokedexEntries = [] # Prepare variables used to record scripted constants. constants = "" maxValue = 0 # Highest species ID # Read from PBS file. File.open("PBS/pokemon.txt","rb") { |f| FileLineData.file = "PBS/pokemon.txt" # 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). pbEachFileSection(f) { |contents,speciesID| # Create array to store compiled data in. speciesData[speciesID] = [] # Copy Type1 into Type2 if Type2 is undefined. (All species must have two # defined types; if both are the same, it is treated as single typed.) if !contents["Type2"] || contents["Type2"]=="" if !contents["Type1"] || contents["Type1"]=="" raise _INTL("No Pokémon type is defined in section {1} (PBS/pokemon.txt)",speciesID.to_s) end contents["Type2"] = contents["Type1"].clone end # Go through hashes of compilable data and compile this section. [requiredValues,optionalValues].each do |hash| for key in hash.keys FileLineData.setSection(speciesID,key,contents[key]) # For error reporting maxValue = [maxValue,speciesID].max # Set highest species ID next if hash[key][0]<0 # Property is not to be compiled; skip it # Raise an error if the species ID is 0. if speciesID==0 raise _INTL("A Pokémon species can't be numbered 0 (PBS/pokemon.txt)") end # Skip empty optional properties, or raise an error if a required # property is empty. if !contents[key] || contents[key]=="" raise _INTL("Required entry {1} is missing or empty in section {2} (PBS/pokemon.txt)", key,speciesID.to_s) if hash==requiredValues next end # Compile value for key. schema = hash[key] value = pbGetCsvRecord(contents[key],key,schema) # Modify value as required. case key when "Height", "Weight" # Convert height/weight to 1 decimal place and multiply by 10. value = (value*10).round if value<=0 raise _INTL("Value for '{1}' can't be less than or close to 0 (section {2}, PBS/pokemon.txt)",key,speciesID) end end # Add value to appropriate array for saving. case key when "Moves" speciesMoves = [] for i in 0...value.length/2 speciesMoves.push([value[i*2],value[i*2+1],i]) end speciesMoves.sort! { |a,b| (a[0]==b[0]) ? a[2]<=>b[2] : a[0]<=>b[0] } for i in speciesMoves; i.pop; end movesets[speciesID] = speciesMoves when "EggMoves" if value.is_a?(Array); eggMoves[speciesID] = value else; eggMoves[speciesID] = [value] end when "RegionalNumbers" if value.is_a?(Array) value.each_with_index do |num,dexID| regionalDexes[dexID] = [] if !regionalDexes[dexID] regionalDexes[dexID][speciesID] = num end else regionalDexes[0] = [] if !regionalDexes[0] regionalDexes[0][speciesID] = value end when "BattlerPlayerX", "BattlerPlayerY", "BattlerEnemyX", "BattlerEnemyY", "BattlerAltitude", "BattlerShadowX", "BattlerShadowSize" spriteMetrics[schema[0]] = [] if !spriteMetrics[schema[0]] spriteMetrics[schema[0]][speciesID] = value when "Evolutions" speciesEvolutions = [] for i in 0...value.length/3 speciesEvolutions.push([value[i*3],value[i*3+1],value[i*3+2],false]) end evolutions[speciesID] = speciesEvolutions when "Name" speciesNames[speciesID] = value when "FormName" formNames[speciesID] = value when "Kind" pokedexKinds[speciesID] = value when "Pokedex" pokedexEntries[speciesID] = value when "InternalName" constants += "#{value}=#{speciesID}\r\n" else # All other data speciesData[speciesID][schema[0]] = value end end end } } # All data is compiled now, just need to save it. raise _INTL("No Pokémon species are defined (PBS/pokemon.txt)") if speciesData.length==0 # Write all constants and some helpful code for PBSpecies. count = speciesData.compact.length code = "module PBSpecies\r\n#{constants}" code += "def PBSpecies.getName(id)\r\n" code += "id=getID(PBSpecies,id)\r\n" code += "return pbGetMessage(MessageTypes::Species,id); end\r\n" code += "def PBSpecies.getCount; return #{count}; end\r\n" code += "def PBSpecies.maxValue; return #{maxValue}; end\r\n" code += "end\r\n" eval(code) pbAddScript(code,"PBSpecies") # Save main species data. save_data(speciesData,"Data/species.dat") # Save movesets data. save_data(movesets,"Data/species_movesets.dat") # Save egg moves data. save_data(eggMoves,"Data/species_eggmoves.dat") # Save regional dexes data. save_data(regionalDexes,"Data/regional_dexes.dat") # Save metrics data. for i in 0...7 defaultValue = (i==MetricBattlerShadowSize) ? 2 : 0 # Shadow size 2, other metrics 0 for j in 0..maxValue spriteMetrics[i] = [] if !spriteMetrics[i] spriteMetrics[i][j] ||= defaultValue end end save_data(spriteMetrics,"Data/species_metrics.dat") # Evaluate evolution data (has to be done after all species are read). for e in 0...evolutions.length next if !evolutions[e] evolutions[e].each_with_index do |evo,i| FileLineData.setSection(i,"Evolutions","") evo[0] = csvEnumField!(evo[0],PBSpecies,"Evolutions",i) # Species case PBEvolution::EVOPARAM[evo[1]] # Evolution method when 1; evo[2] = csvPosInt!(evo[2]) when 2; evo[2] = csvEnumField!(evo[2],PBItems,"Evolutions",i) when 3; evo[2] = csvEnumField!(evo[2],PBMoves,"Evolutions",i) when 4; evo[2] = csvEnumField!(evo[2],PBSpecies,"Evolutions",i) when 5; evo[2] = csvEnumField!(evo[2],PBTypes,"Evolutions",i) when 6; evo[2] = csvEnumField!(evo[2],PBAbilities,"Evolutions",i) else; evo[2] = 0 end end end # Add prevolution data to all species as the first "evolution method". for sp in 1..maxValue next if !evolutions[sp] preSpecies = -1 evoData = nil # Check for another species that evolves into sp. for f in 0...evolutions.length next if !evolutions[f] || f==sp evolutions[f].each do |evo| next if evo[0]!=sp || evo[3] # Evolved species isn't sp or is a prevolution preSpecies = f # f evolves into sp evoData = evo break end break if evoData end next if !evoData # evoData[1]=method, evoData[2]=level - both are unused # Found a species that evolves into e, record it as a prevolution. evolutions[sp] = [[preSpecies,evoData[1],evoData[2],true]].concat(evolutions[sp]) end # Save evolutions data. save_data(evolutions,"Data/species_evolutions.dat") # Save all messages. speciesNames.map! { |name| name || "????????" } MessageTypes.setMessages(MessageTypes::Species,speciesNames) MessageTypes.setMessages(MessageTypes::FormNames,formNames) MessageTypes.setMessages(MessageTypes::Kinds,pokedexKinds) MessageTypes.setMessages(MessageTypes::Entries,pokedexEntries) end #=============================================================================== # Compile Pokémon forms #=============================================================================== def pbCompilePokemonForms # Get schemas. requiredValues = PokemonSpeciesData.requiredValues(true) optionalValues = PokemonSpeciesData.optionalValues(true) # Prepare arrays for compiled data. speciesData = pbLoadSpeciesData movesets = [] eggMoves = [] spriteMetrics = [] evolutions = [] formNames = [] pokedexKinds = [] pokedexEntries = [] formToSpecies = [] # Saved speciesToForm = [] # Only used in this method for i in 1..PBSpecies.maxValue formToSpecies[i] = [i] speciesToForm[i] = i end # Prepare variables used to record scripted constants. constants = "" maxValue = PBSpecies.maxValue # Highest species ID # Read from PBS file. File.open("PBS/pokemonforms.txt","rb") { |f| FileLineData.file = "PBS/pokemonforms.txt" # 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). pbEachFileSection2(f) { |contents,sectionName| # Split sectionName into a species number and form number. splitSectionName = sectionName.split(/[-,\s]/) if splitSectionName.length!=2 raise _INTL("Section name {1} is invalid (PBS/pokemonforms.txt). Expected syntax like [XXX,Y] (XXX=internal name, Y=form number).",sectionName) end baseSpeciesID = parseSpecies(splitSectionName[0]) form = csvInt!(splitSectionName[1]) # Ensure this is a valid form and not a duplicate. if form==0 raise _INTL("Form {1} is invalid (PBS/pokemonforms.txt). Form 0 data should be defined in \"PBS/pokemon.txt\".",sectionName) next end if formToSpecies[baseSpeciesID] && formToSpecies[baseSpeciesID][form] raise _INTL("Form {1} is defined at least twice (PBS/pokemonforms.txt). It should only be defined once.",sectionName) next end # Record new species number in formToSpecies. speciesID = baseSpeciesID if form>0 maxValue += 1 speciesID = maxValue formToSpecies[baseSpeciesID] = [] if !formToSpecies[baseSpeciesID] formToSpecies[baseSpeciesID][form] = speciesID speciesToForm[speciesID] = baseSpeciesID end # Generate internal name for this form. cName = getConstantName(PBSpecies,baseSpeciesID).to_s+"_"+form.to_s constants += "#{cName}=#{speciesID}\r\n" # Create array to store compiled data in. speciesData[speciesID] = [] # Clone data from base form as a starting point. speciesData[baseSpeciesID].each_with_index do |val,i| speciesData[speciesID][i] = (val.is_a?(Array)) ? val.clone : val end # Copy Type1 into Type2 if if Type1 is defined but Type2 isn't. (Shouldn't # inherit either of the base form's types if Type1 is defined for a form.) if contents["Type1"] && contents["Type1"]!="" if !contents["Type2"] || contents["Type2"]=="" contents["Type2"] = contents["Type1"].clone end end # If any held item is defined for this form, clear default data for all # three held items. if (contents["WildItemCommon"] && contents["WildItemCommon"]!="") || (contents["WildItemUncommon"] && contents["WildItemUncommon"]!="") || (contents["WildItemRare"] && contents["WildItemRare"]!="") speciesData[speciesID][SpeciesWildItemCommon] = nil speciesData[speciesID][SpeciesWildItemUncommon] = nil speciesData[speciesID][SpeciesWildItemRare] = nil end # Go through hashes of compilable data and compile this section. [requiredValues,optionalValues].each do |hash| for key in hash.keys FileLineData.setSection(speciesID,key,contents[key]) # For error reporting next if hash[key][0]<0 # Property is not to be compiled; skip it # Skip empty properties (none are required). next if !contents[key] || contents[key]=="" # Compile value for key. schema = hash[key] value = pbGetCsvRecord(contents[key],key,schema) # Modify value as required. case key when "Height", "Weight" # Convert height/weight to 1 decimal place and multiply by 10. value = (value*10).round if value<=0 raise _INTL("Value for '{1}' can't be less than or close to 0 (section {2}, PBS/pokemonforms.txt)",key,speciesID) end end # Add value to appropriate array for saving. case key when "Moves" speciesMoves = [] for i in 0...value.length/2 speciesMoves.push([value[i*2],value[i*2+1],i]) end speciesMoves.sort! { |a,b| (a[0]==b[0]) ? a[2]<=>b[2] : a[0]<=>b[0] } for i in speciesMoves; i.pop; end movesets[speciesID] = speciesMoves when "EggMoves" if value.is_a?(Array); eggMoves[speciesID] = value else; eggMoves[speciesID] = [value] end when "BattlerPlayerX", "BattlerPlayerY", "BattlerEnemyX", "BattlerEnemyY", "BattlerAltitude", "BattlerShadowX", "BattlerShadowSize" spriteMetrics[schema[0]] = [] if !spriteMetrics[schema[0]] spriteMetrics[schema[0]][speciesID] = value when "Evolutions" speciesEvolutions = [] for i in 0...value.length/3 speciesEvolutions.push([value[i*3],value[i*3+1],value[i*3+2],false]) end evolutions[speciesID] = speciesEvolutions when "FormName" formNames[speciesID] = value when "Kind" pokedexKinds[speciesID] = value when "Pokedex" pokedexEntries[speciesID] = value else # All other data speciesData[speciesID][schema[0]] = value end end end } } # All data is compiled now, just need to save it. # Write all constants and some helpful code for PBSpecies. code = "module PBSpecies\r\n#{constants}" code += "def PBSpecies.maxValueF; return #{maxValue}; end\r\n" code += "end\r\n" eval(code) pbAddScript(code,"PBSpecies") # Save main species data. save_data(speciesData,"Data/species.dat") # Save conversions of form to species data. save_data(formToSpecies,"Data/form2species.dat") # Inherit base form moveset. newMovesets = pbLoadMovesetsData pbAppendToBaseFormData(PBSpecies.maxValue+1,maxValue,newMovesets,movesets,speciesToForm,true) save_data(newMovesets,"Data/species_movesets.dat") $PokemonTemp.speciesMovesets = nil if $PokemonTemp # Inherit base form egg moves. newEggMoves = pbLoadEggMovesData pbAppendToBaseFormData(PBSpecies.maxValue+1,maxValue,newEggMoves,eggMoves,speciesToForm,false) save_data(newEggMoves,"Data/species_eggmoves.dat") $PokemonTemp.speciesEggMoves = nil if $PokemonTemp # Inherit base form metrics data. newSpriteMetrics = pbLoadSpeciesMetrics for i in 0...7 defaultValue = (i==MetricBattlerShadowSize) ? 2 : 0 # Shadow size 2, other metrics 0 pbAppendToBaseFormData(PBSpecies.maxValue+1,maxValue,newSpriteMetrics[i], spriteMetrics[i] || [],speciesToForm,false,defaultValue) end save_data(newSpriteMetrics,"Data/species_metrics.dat") # Evaluate evolution data (has to be done after all species are read). for e in 0...evolutions.length next if !evolutions[e] evolutions[e].each_with_index do |evo,i| FileLineData.setSection(i,"Evolutions","") evo[0] = csvEnumField!(evo[0],PBSpecies,"Evolutions",i) # Species case PBEvolution::EVOPARAM[evo[1]] # Evolution method when 1; evo[2] = csvPosInt!(evo[2]) when 2; evo[2] = csvEnumField!(evo[2],PBItems,"Evolutions",i) when 3; evo[2] = csvEnumField!(evo[2],PBMoves,"Evolutions",i) when 4; evo[2] = csvEnumField!(evo[2],PBSpecies,"Evolutions",i) when 5; evo[2] = csvEnumField!(evo[2],PBTypes,"Evolutions",i) when 6; evo[2] = csvEnumField!(evo[2],PBAbilities,"Evolutions",i) else; evo[2] = 0 end end end # Inherit base form evolution methods. newEvolutions = pbLoadEvolutionsData pbAppendToBaseFormData(PBSpecies.maxValue+1,maxValue,newEvolutions,evolutions,speciesToForm,true) # Add prevolution data to all species as the first "evolution method". for i in (PBSpecies.maxValue+1)..maxValue baseSpecies = speciesToForm[i] preSpecies = -1 evoData = nil # Check for another species that evolves into baseSpecies. for f in 0...newEvolutions.length next if !newEvolutions[f] || speciesToForm[f]==baseSpecies newEvolutions[f].each do |evo| next if evo[0]!=baseSpecies || evo[3] # Evolved species isn't baseSpecies or is a prevolution preSpecies = speciesToForm[f] # f evolves into baseSpecies evoData = evo break end break if evoData end next if !evoData # evoData[1]=method, evoData[2]=level - both are unused # Found a species that evolves into e, record it as a prevolution. if newEvolutions[i] newEvolutions[i] = [[preSpecies,evoData[1],evoData[2],true]].concat(newEvolutions[i]) else newEvolutions[i] = [[preSpecies,evoData[1],evoData[2],true]] end end # Save evolutions data. save_data(newEvolutions,"Data/species_evolutions.dat") $PokemonTemp.evolutionsData = nil if $PokemonTemp # Save all messages. MessageTypes.addMessages(MessageTypes::FormNames,formNames) MessageTypes.addMessages(MessageTypes::Kinds,pokedexKinds) MessageTypes.addMessages(MessageTypes::Entries,pokedexEntries) end def pbAppendToBaseFormData(idxStart,idxEnd,baseData,extraData,speciesToForm,clone=false,defaultValue=nil) for i in idxStart..idxEnd if extraData[i] baseData[i] = extraData[i] else species = speciesToForm[i] if baseData[species] if clone baseData[i] = [] baseData[species].each { |datum| baseData[i].push(datum.clone) } elsif baseData[species].is_a?(Array) baseData[i] = baseData[species].clone else baseData[i] = baseData[species] end else baseData[i] = defaultValue end end end end #=============================================================================== # Compile TM/TM/Move Tutor compatibilities #=============================================================================== def pbTMRS # Backup Gen 3 TM list rstm = [ # TMs :FOCUSPUNCH,:DRAGONCLAW,:WATERPULSE,:CALMMIND,:ROAR, :TOXIC,:HAIL,:BULKUP,:BULLETSEED,:HIDDENPOWER, :SUNNYDAY,:TAUNT,:ICEBEAM,:BLIZZARD,:HYPERBEAM, :LIGHTSCREEN,:PROTECT,:RAINDANCE,:GIGADRAIN,:SAFEGUARD, :FRUSTRATION,:SOLARBEAM,:IRONTAIL,:THUNDERBOLT,:THUNDER, :EARTHQUAKE,:RETURN,:DIG,:PSYCHIC,:SHADOWBALL, :BRICKBREAK,:DOUBLETEAM,:REFLECT,:SHOCKWAVE,:FLAMETHROWER, :SLUDGEBOMB,:SANDSTORM,:FIREBLAST,:ROCKTOMB,:AERIALACE, :TORMENT,:FACADE,:SECRETPOWER,:REST,:ATTRACT, :THIEF,:STEELWING,:SKILLSWAP,:SNATCH,:OVERHEAT, # HMs :CUT,:FLY,:SURF,:STRENGTH,:FLASH,:ROCKSMASH,:WATERFALL,:DIVE ] ret = [] for i in 0...rstm.length ret.push((parseMove(rstm.to_s) rescue 0)) end return ret end def pbCompileMachines lineno = 1 havesection = false sectionname = nil sections = [] if safeExists?("PBS/tm.txt") f = File.open("PBS/tm.txt","rb") FileLineData.file="PBS/tm.txt" f.each_line { |line| if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF line = line[3,line.length-3] end FileLineData.setLine(line,lineno) if !line[/^\#/] && !line[/^\s*$/] if line[/^\s*\[\s*(.*)\s*\]\s*$/] sectionname = parseMove($~[1]) sections[sectionname] = WordArray.new havesection = true else if sectionname==nil raise _INTL("Expected a section at the beginning of the file. This error may also occur if the file was not saved in UTF-8.\r\n{1}", FileLineData.linereport) end specieslist = line.sub(/\s+$/,"").split(",") for species in specieslist next if !species || species=="" sec = sections[sectionname] sec[sec.length] = parseSpecies(species) end end end lineno += 1 Graphics.update if lineno%50==0 Win32API.SetWindowText(_INTL("Processing TM line {1}",lineno)) if lineno%50==0 } f.close elsif safeExists?("Data/tmRS.dat") tmrs = pbTMRS() for i in 0...tmrs.length next if !tmrs[i] || tmrs[i]==0 sections[tmrs[i]] = [] end File.open("Data/tmRS.dat","rb") { |f| species = 1 while !f.eof? data = f.read(8)+"\0\0\0\0\0\0\0\0" for i in 0...58 next if !tmrs[i] || tmrs[i]==0 if (data[i>>3]&(1<<(i&7)))!=0 sections[tmrs[i]].push(species) end end species += 1 end } end save_data(sections,"Data/tm.dat") end #=============================================================================== # Compile Shadow moves #=============================================================================== def pbCompileShadowMoves sections = [] if File.exists?("PBS/shadowmoves.txt") pbCompilerEachCommentedLine("PBS/shadowmoves.txt") { |line,lineno| if line[ /^\s*(\w+)\s*=\s*(.*)$/ ] key = $1 value = $2 value = value.split(",") species = parseSpecies(key) moves = [] for i in 0...[4,value.length].min moves.push((parseMove(value[i]) rescue nil)) end moves.compact! sections[species] = moves if moves.length>0 end } end save_data(sections,"Data/shadow_movesets.dat") end #=============================================================================== # Compile wild encounters #=============================================================================== def pbCompileEncounters lines = [] linenos = [] FileLineData.file = "PBS/encounters.txt" File.open("PBS/encounters.txt","rb") { |f| lineno = 1 f.each_line { |line| if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF line = line[3,line.length-3] end line = prepline(line) if line.length!=0 lines[lines.length] = line linenos[linenos.length] = lineno end lineno += 1 } } encounters = {} thisenc = nil lastenc = -1 lastenclen = 0 needdensity = false lastmapid = -1 i = 0; while i=0 needdensity = false enclines = EncounterTypes::EnctypeChances[enc].length encarray = [] j = i+1; k = 0; while jmaxlevel raise _INTL("Level number is not valid: {1}\r\n{2}",splitarr[1],FileLineData.linereport) end if splitarr[2]<=0 || splitarr[2]>maxlevel raise _INTL("Level number is not valid: {1}\r\n{2}",splitarr[2],FileLineData.linereport) end if splitarr[1]>splitarr[2] raise _INTL("Minimum level is greater than maximum level: {1}\r\n{2}",line,FileLineData.linereport) end splitarr[0] = parseSpecies(splitarr[0]) encarray.push(splitarr) thisenc[1][enc] = encarray j += 1; k += 1 end if j==lines.length && k=3 for j in 0...EncounterTypes::EnctypeChances.length next if !EncounterTypes::EnctypeChances[j] || EncounterTypes::EnctypeChances[j].length==0 next if EncounterTypes::EnctypeCompileDens[j]==0 thisenc[0][j] = nums[EncounterTypes::EnctypeCompileDens[j]-1].to_i end else raise _INTL("Wrong syntax for densities in encounters.txt; got \"{1}\"\r\n{2}",line,FileLineData.linereport) end i += 1 else raise _INTL("Undefined encounter type {1}, expected one of the following:\r\n{2}\r\n{3}",line,EncounterTypes::Names.inspect,FileLineData.linereport) end end save_data(encounters,"Data/encounters.dat") end #=============================================================================== # Compile trainer types #=============================================================================== def pbCompileTrainerTypes # Trainer types records = [] trainernames = [] count = 0 maxValue = 0 pbCompilerEachPreppedLine("PBS/trainertypes.txt") { |line,lineno| record=pbGetCsvRecord(line,lineno,[0,"unsUSSSeUS", # ID can be 0 nil,nil,nil,nil,nil,nil,nil,{ "" => 2, "Male" => 0,"M" => 0,"0" => 0, "Female" => 1,"F" => 1,"1" => 1, "Mixed" => 2,"X" => 2,"2" => 2 },nil,nil] ) if records[record[0]] raise _INTL("Two trainer types ({1} and {2}) have the same ID ({3}), which is not allowed.\r\n{4}", records[record[0]][1],record[1],record[0],FileLineData.linereport) end trainernames[record[0]] = record[2] records[record[0]] = record maxValue = [maxValue,record[0]].max } count = records.compact.length MessageTypes.setMessages(MessageTypes::TrainerTypes,trainernames) code = "class PBTrainers\r\n" for rec in records next if !rec code += "#{rec[1]}=#{rec[0]}\r\n" end code += "def self.getName(id)\r\n" code += "id=getID(PBTrainers,id)\r\n" code += "return pbGetMessage(MessageTypes::TrainerTypes,id); end\r\n" code += "def self.getCount; return #{count}; end\r\n" code += "def self.maxValue; return #{maxValue}; end\r\n" code += "end\r\n" eval(code) pbAddScript(code,"PBTrainers") save_data(records,"Data/trainer_types.dat") end #=============================================================================== # Compile individual trainers #=============================================================================== def pbCompileTrainers nonglobaltypes = { "Items" => [0, "eEEEEEEE",PBItems,PBItems,PBItems,PBItems, PBItems,PBItems,PBItems,PBItems], "Pokemon" => [TPSPECIES, "ev",PBSpecies], # Species, level "Item" => [TPITEM, "e",PBItems], "Moves" => [TPMOVES, "eEEE",PBMoves,PBMoves,PBMoves,PBMoves], "Ability" => [TPABILITY, "u"], "Gender" => [TPGENDER, "e",{"M"=>0,"m"=>0,"Male"=>0,"male"=>0,"0"=>0, "F"=>1,"f"=>1,"Female"=>1,"female"=>1,"1"=>1}], "Form" => [TPFORM, "u"], "Shiny" => [TPSHINY, "b"], "Nature" => [TPNATURE, "e",PBNatures], "IV" => [TPIV, "uUUUUU"], "Happiness" => [TPHAPPINESS, "u"], "Name" => [TPNAME, "s"], "Shadow" => [TPSHADOW, "b"], "Ball" => [TPBALL, "u"], "EV" => [TPEV, "uUUUUU"], "LoseText" => [TPLOSETEXT, "s"] } mLevel = PBExperience.maxLevel trainerindex = -1 trainers = [] trainernames = [] trainerlosetext = [] pokemonindex = -2 oldcompilerline = 0 oldcompilerlength = 0 pbCompilerEachCommentedLine("PBS/trainers.txt") { |line,lineno| if line[/^\s*\[\s*(.+)\s*\]\s*$/] # Section [trainertype,trainername] or [trainertype,trainername,partyid] if oldcompilerline>0 raise _INTL("Previous trainer not defined with as many Pokémon as expected\r\n{1}",FileLineData.linereport) end if pokemonindex==-1 raise _INTL("Started new trainer while previous trainer has no Pokémon\r\n{1}",FileLineData.linereport) end section = pbGetCsvRecord($~[1],lineno,[0,"esU",PBTrainers]) trainerindex += 1 trainertype = section[0] trainername = section[1] partyid = section[2] || 0 trainers[trainerindex] = [trainertype,trainername,[],[],partyid,nil] trainernames[trainerindex] = trainername pokemonindex = -1 elsif line[/^\s*(\w+)\s*=\s*(.*)$/] # XXX=YYY lines if trainerindex<0 raise _INTL("Expected a section at the beginning of the file\r\n{1}",FileLineData.linereport) end if oldcompilerline>0 raise _INTL("Previous trainer not defined with as many Pokémon as expected\r\n{1}",FileLineData.linereport) end settingname = $~[1] schema = nonglobaltypes[settingname] next if !schema record = pbGetCsvRecord($~[2],lineno,schema) # Error checking in XXX=YYY lines case settingname when "Pokemon" if record[1]>mLevel raise _INTL("Bad level: {1} (must be 1-{2})\r\n{3}",record[1],mLevel,FileLineData.linereport) end when "Moves" record = [record] if record.is_a?(Integer) record.compact! when "Ability" if record>5 raise _INTL("Bad ability flag: {1} (must be 0 or 1 or 2-5)\r\n{2}",record,FileLineData.linereport) end when "IV" record = [record] if record.is_a?(Integer) record.compact! for i in record next if i<=PokeBattle_Pokemon::IV_STAT_LIMIT raise _INTL("Bad IV: {1} (must be 0-{2})\r\n{3}",i,PokeBattle_Pokemon::IV_STAT_LIMIT,FileLineData.linereport) end when "EV" record = [record] if record.is_a?(Integer) record.compact! for i in record next if i<=PokeBattle_Pokemon::EV_STAT_LIMIT raise _INTL("Bad EV: {1} (must be 0-{2})\r\n{3}",i,PokeBattle_Pokemon::EV_STAT_LIMIT,FileLineData.linereport) end evtotal = 0 for i in 0...6 evtotal += (iPokeBattle_Pokemon::EV_LIMIT raise _INTL("Total EVs are greater than allowed ({1})\r\n{2}",PokeBattle_Pokemon::EV_LIMIT,FileLineData.linereport) end when "Happiness" if record>255 raise _INTL("Bad happiness: {1} (must be 0-255)\r\n{2}",record,FileLineData.linereport) end when "Name" if record.length>PokeBattle_Pokemon::MAX_POKEMON_NAME_SIZE raise _INTL("Bad nickname: {1} (must be 1-{2} characters)\r\n{3}",record,PokeBattle_Pokemon::MAX_POKEMON_NAME_SIZE,FileLineData.linereport) end end # Record XXX=YYY setting case settingname when "Items" # Items in the trainer's Bag, not the held item record = [record] if record.is_a?(Integer) record.compact! trainers[trainerindex][2] = record when "LoseText" trainerlosetext[trainerindex] = record trainers[trainerindex][5] = record when "Pokemon" pokemonindex += 1 trainers[trainerindex][3][pokemonindex] = [] trainers[trainerindex][3][pokemonindex][TPSPECIES] = record[0] trainers[trainerindex][3][pokemonindex][TPLEVEL] = record[1] else if pokemonindex<0 raise _INTL("Pokémon hasn't been defined yet!\r\n{1}",FileLineData.linereport) end trainers[trainerindex][3][pokemonindex][schema[0]] = record end else # Old compiler - backwards compatibility is SUCH fun! if pokemonindex==-1 && oldcompilerline==0 raise _INTL("Unexpected line format, started new trainer while previous trainer has no Pokémon\r\n{1}",FileLineData.linereport) end if oldcompilerline==0 # Started an old trainer section oldcompilerlength = 3 oldcompilerline = 0 trainerindex += 1 trainers[trainerindex] = [0,"",[],[],0] pokemonindex = -1 end oldcompilerline += 1 case oldcompilerline when 1 # Trainer type record = pbGetCsvRecord(line,lineno,[0,"e",PBTrainers]) trainers[trainerindex][0] = record when 2 # Trainer name, version number record = pbGetCsvRecord(line,lineno,[0,"sU"]) record = [record] if record.is_a?(Integer) trainers[trainerindex][1] = record[0] trainernames[trainerindex] = record[0] trainers[trainerindex][4] = record[1] if record[1] when 3 # Number of Pokémon, items record = pbGetCsvRecord(line,lineno,[0,"vEEEEEEEE",nil,PBItems,PBItems, PBItems,PBItems,PBItems,PBItems,PBItems,PBItems]) record = [record] if record.is_a?(Integer) record.compact! oldcompilerlength += record[0] record.shift trainers[trainerindex][2] = record if record else # Pokémon lines pokemonindex += 1 trainers[trainerindex][3][pokemonindex] = [] record = pbGetCsvRecord(line,lineno, [0,"evEEEEEUEUBEUUSBU",PBSpecies,nil, PBItems,PBMoves,PBMoves,PBMoves, PBMoves,nil,{"M"=>0,"m"=>0,"Male"=>0,"male"=>0, "0"=>0,"F"=>1,"f"=>1,"Female"=>1,"female"=>1, "1"=>1},nil,nil,PBNatures,nil,nil,nil,nil,nil]) # Error checking (the +3 is for properties after the four moves) for i in 0...record.length next if record[i]==nil case i when TPLEVEL if record[i]>mLevel raise _INTL("Bad level: {1} (must be 1-{2})\r\n{3}",record[i],mLevel,FileLineData.linereport) end when TPABILITY+3 if record[i]>5 raise _INTL("Bad ability flag: {1} (must be 0 or 1 or 2-5)\r\n{2}",record[i],FileLineData.linereport) end when TPIV+3 if record[i]>31 raise _INTL("Bad IV: {1} (must be 0-31)\r\n{2}",record[i],FileLineData.linereport) end record[i] = [record[i]] when TPEV+3 if record[i]>PokeBattle_Pokemon::EV_STAT_LIMIT raise _INTL("Bad EV: {1} (must be 0-{2})\r\n{3}",record[i],PokeBattle_Pokemon::EV_STAT_LIMIT,FileLineData.linereport) end record[i] = [record[i]] when TPHAPPINESS+3 if record[i]>255 raise _INTL("Bad happiness: {1} (must be 0-255)\r\n{2}",record[i],FileLineData.linereport) end when TPNAME+3 if record[i].length>PokeBattle_Pokemon::MAX_POKEMON_NAME_SIZE raise _INTL("Bad nickname: {1} (must be 1-{2} characters)\r\n{3}",record[i],PokeBattle_Pokemon::MAX_POKEMON_NAME_SIZE,FileLineData.linereport) end end end # Write data to trainer array for i in 0...record.length next if record[i]==nil if i>=TPMOVES && i=TPMOVES+4) ? i-3 : i trainers[trainerindex][3][pokemonindex][d] = record[i] end end end oldcompilerline = 0 if oldcompilerline>=oldcompilerlength end } save_data(trainers,"Data/trainers.dat") MessageTypes.setMessagesAsHash(MessageTypes::TrainerNames,trainernames) MessageTypes.setMessagesAsHash(MessageTypes::TrainerLoseText,trainerlosetext) end #=============================================================================== # Compile Battle Tower and other Cups trainers/Pokémon #=============================================================================== def pbCompileBTTrainers(filename) sections = [] requiredtypes = { "Type" => [0, "e",PBTrainers], "Name" => [1, "s"], "BeginSpeech" => [2, "s"], "EndSpeechWin" => [3, "s"], "EndSpeechLose" => [4, "s"], "PokemonNos" => [5, "*u"] } trainernames = [] beginspeech = [] endspeechwin = [] endspeechlose = [] if safeExists?(filename) File.open(filename,"rb") { |f| FileLineData.file = filename pbEachFileSectionEx(f) { |section,name| rsection = [] for key in section.keys FileLineData.setSection(name,key,section[key]) schema = requiredtypes[key] next if !schema record = pbGetCsvRecord(section[key],0,schema) rsection[schema[0]] = record end trainernames.push(rsection[1]) beginspeech.push(rsection[2]) endspeechwin.push(rsection[3]) endspeechlose.push(rsection[4]) sections.push(rsection) } } end MessageTypes.addMessagesAsHash(MessageTypes::TrainerNames,trainernames) MessageTypes.addMessagesAsHash(MessageTypes::BeginSpeech,beginspeech) MessageTypes.addMessagesAsHash(MessageTypes::EndSpeechWin,endspeechwin) MessageTypes.addMessagesAsHash(MessageTypes::EndSpeechLose,endspeechlose) return sections end def pbCompileTrainerLists btTrainersRequiredTypes = { "Trainers" => [0, "s"], "Pokemon" => [1, "s"], "Challenges" => [2, "*s"] } if !safeExists?("PBS/trainerlists.txt") File.open("PBS/trainerlists.txt","wb") { |f| f.write(0xEF.chr) f.write(0xBB.chr) f.write(0xBF.chr) f.write("[DefaultTrainerList]\r\n") f.write("Trainers = bttrainers.txt\r\n") f.write("Pokemon = btpokemon.txt\r\n") } end database = [] sections = [] MessageTypes.setMessagesAsHash(MessageTypes::BeginSpeech,[]) MessageTypes.setMessagesAsHash(MessageTypes::EndSpeechWin,[]) MessageTypes.setMessagesAsHash(MessageTypes::EndSpeechLose,[]) File.open("PBS/trainerlists.txt","rb") { |f| FileLineData.file = "PBS/trainerlists.txt" pbEachFileSectionEx(f) { |section,name| next if name!="DefaultTrainerList" && name!="TrainerList" rsection = [] for key in section.keys FileLineData.setSection(name,key,section[key]) schema = btTrainersRequiredTypes[key] next if key=="Challenges" && name=="DefaultTrainerList" next if !schema record = pbGetCsvRecord(section[key],0,schema) rsection[schema[0]] = record end if !rsection[0] raise _INTL("No trainer data file given in section {1}\r\n{2}",name,FileLineData.linereport) end if !rsection[1] raise _INTL("No trainer data file given in section {1}\r\n{2}",name,FileLineData.linereport) end rsection[3] = rsection[0] rsection[4] = rsection[1] rsection[5] = (name=="DefaultTrainerList") if safeExists?("PBS/"+rsection[0]) rsection[0] = pbCompileBTTrainers("PBS/"+rsection[0]) else rsection[0] = [] end if safeExists?("PBS/"+rsection[1]) filename = "PBS/"+rsection[1] rsection[1] = [] pbCompilerEachCommentedLine(filename) { |line,lineno| rsection[1].push(PBPokemon.fromInspected(line)) } else rsection[1] = [] end rsection[2] = [] if !rsection[2] while rsection[2].include?("") rsection[2].delete("") end rsection[2].compact! sections.push(rsection) } } save_data(sections,"Data/trainer_lists.dat") end