From 4dd3a1a2c58a3e6f99b8a83ab7428a4100121300 Mon Sep 17 00:00:00 2001 From: Maruno17 Date: Sun, 17 Jan 2021 00:22:49 +0000 Subject: [PATCH] Implemented class GameData::Trainer --- Data/Scripts/011_Data/001_Data_Cache.rb | 22 -- .../011_Data/001_Game data/001_Game data.rb | 5 +- .../011_Data/001_Game data/012_Trainer.rb | 170 +++++++++ .../014_Trainers/002_PTrainer_NPCTrainers.rb | 219 +++--------- Data/Scripts/015_Items/004_PItem_Phone.rb | 18 +- Data/Scripts/021_Debug/004_Editor_Screens.rb | 328 ++++++++++-------- .../Scripts/021_Debug/007_Editor_DataTypes.rb | 46 +-- Data/Scripts/021_Debug/008_Editor_Listers.rb | 88 ++--- .../Scripts/021_Debug/009_Editor_Utilities.rb | 4 +- .../022_Compiler/002_Compiler_CompilePBS.rb | 254 +++++--------- .../022_Compiler/003_Compiler_WritePBS.rb | 110 ++---- .../004_Compiler_MapsAndEvents.rb | 15 +- 12 files changed, 608 insertions(+), 671 deletions(-) create mode 100644 Data/Scripts/011_Data/001_Game data/012_Trainer.rb diff --git a/Data/Scripts/011_Data/001_Data_Cache.rb b/Data/Scripts/011_Data/001_Data_Cache.rb index cad2d411b..41f1fa2a4 100644 --- a/Data/Scripts/011_Data/001_Data_Cache.rb +++ b/Data/Scripts/011_Data/001_Data_Cache.rb @@ -7,7 +7,6 @@ class PokemonTemp attr_accessor :phoneData attr_accessor :regionalDexes attr_accessor :speciesShadowMovesets - attr_accessor :trainersData attr_accessor :moveToAnim attr_accessor :battleAnims end @@ -19,7 +18,6 @@ def pbClearData $PokemonTemp.phoneData = nil $PokemonTemp.regionalDexes = nil $PokemonTemp.speciesShadowMovesets = nil - $PokemonTemp.trainersData = nil $PokemonTemp.moveToAnim = nil $PokemonTemp.battleAnims = nil end @@ -92,26 +90,6 @@ def pbLoadShadowMovesets return $PokemonTemp.speciesShadowMovesets end -#=============================================================================== -# Methods to get data about individual trainers. -#=============================================================================== -def pbLoadTrainersData - $PokemonTemp = PokemonTemp.new if !$PokemonTemp - if !$PokemonTemp.trainersData - $PokemonTemp.trainersData = load_data("Data/trainers.dat") || [] - end - return $PokemonTemp.trainersData -end - -def pbGetTrainerData(trainer_id, trainer_name, party_id = 0) - trainers_data = pbLoadTrainersData - for t in trainers_data - next if t[0] != trainer_id || t[1] != trainer_name || t[4] != party_id - return t - end - return nil -end - #=============================================================================== # Methods relating to battle animations data. #=============================================================================== diff --git a/Data/Scripts/011_Data/001_Game data/001_Game data.rb b/Data/Scripts/011_Data/001_Game data/001_Game data.rb index 9d1813763..45e2f8937 100644 --- a/Data/Scripts/011_Data/001_Game data/001_Game data.rb +++ b/Data/Scripts/011_Data/001_Game data/001_Game data.rb @@ -27,6 +27,8 @@ module GameData return self::DATA[other] end + # @param other [Symbol, self, String, Integer] + # @return [self, nil] def try_get(other) return nil if other.nil? validate other => [Symbol, self, String, Integer] @@ -40,7 +42,7 @@ module GameData def each keys = self::DATA.keys.sort { |a, b| self::DATA[a].id_number <=> self::DATA[b].id_number } - keys.each { |key| yield self::DATA[key] if key.is_a?(Symbol) } + keys.each { |key| yield self::DATA[key] if !key.is_a?(Integer) } end def load @@ -127,5 +129,6 @@ module GameData TrainerType.load Type.load Species.load + Trainer.load end end diff --git a/Data/Scripts/011_Data/001_Game data/012_Trainer.rb b/Data/Scripts/011_Data/001_Game data/012_Trainer.rb new file mode 100644 index 000000000..0fc9879a2 --- /dev/null +++ b/Data/Scripts/011_Data/001_Game data/012_Trainer.rb @@ -0,0 +1,170 @@ +module GameData + class Trainer + attr_reader :id_number + attr_reader :trainer_type + attr_reader :real_name + attr_reader :version + attr_reader :items + attr_reader :real_lose_text + attr_reader :pokemon + + DATA = {} + DATA_FILENAME = "trainers.dat" + + SCHEMA = { + "Items" => [:items, "*e", :Item], + "LoseText" => [:lose_text, "s"], + "Pokemon" => [:pokemon, "ev", :Species], # Species, level + "Form" => [:form, "u"], + "Name" => [:name, "s"], + "Moves" => [:moves, "*e", :Move], + "Ability" => [:ability_flag, "u"], + "Item" => [:item, "e", :Item], + "Gender" => [:gender, "e", { "M" => 0, "m" => 0, "Male" => 0, "male" => 0, "0" => 0, + "F" => 1, "f" => 1, "Female" => 1, "female" => 1, "1" => 1 }], + "Nature" => [:nature, "e", :PBNatures], + "IV" => [:iv, "uUUUUU"], + "EV" => [:ev, "uUUUUU"], + "Happiness" => [:happiness, "u"], + "Shiny" => [:shininess, "b"], + "Shadow" => [:shadowness, "b"], + "Ball" => [:poke_ball, "u"], + } + + extend ClassMethods + include InstanceMethods + + # @param tr_type [Symbol, String] + # @param tr_name [String] + # @param tr_version [Integer] + # @return [Boolean] whether the given other is defined as a self + def self.exists?(tr_type, tr_name, tr_version = 0) + validate tr_type => [Symbol, String] + validate tr_name => [String] + key = [tr_type.to_sym, tr_name, tr_version] + return !self::DATA[key].nil? + end + + # @param tr_type [Symbol, String] + # @param tr_name [String] + # @param tr_version [Integer] + # @return [self] + def self.get(tr_type, tr_name, tr_version = 0) + validate tr_type => [Symbol, String] + validate tr_name => [String] + key = [tr_type.to_sym, tr_name, tr_version] + raise "Unknown trainer #{tr_type} #{tr_name} #{tr_version}." unless self::DATA.has_key?(key) + return self::DATA[key] + end + + # @param other [Symbol, self, String, Integer] + # @return [self, nil] + def try_get(tr_type, tr_name, tr_version = 0) + validate tr_type => [Symbol, String] + validate tr_name => [String] + key = [tr_type.to_sym, tr_name, tr_version] + return (self::DATA.has_key?(key)) ? self::DATA[key] : nil + end + + def initialize(hash) + @id_number = hash[:id] + @trainer_type = hash[:trainer_type] + @real_name = hash[:name] || "Unnamed" + @version = hash[:version] || 0 + @items = hash[:items] || [] + @real_lose_text = hash[:lose_text] || "..." + @pokemon = hash[:pokemon] || [] + @pokemon.each do |pkmn| + if pkmn[:iv] + 6.times { |i| pkmn[:iv][i] = pkmn[:iv][0] if !pkmn[:iv][i] } + end + if pkmn[:ev] + 6.times { |i| pkmn[:ev][i] = pkmn[:ev][0] if !pkmn[:ev][i] } + end + end + end + + # @return [String] the translated name of this trainer + def name + return pbGetMessageFromHash(MessageTypes::TrainerNames, @real_name) + end + + # @return [String] the translated in-battle lose message of this trainer + def lose_text + return pbGetMessageFromHash(MessageTypes::TrainerLoseText, @real_lose_text) + end + + # Creates a battle-ready version of a trainer's data. + # @return [Array] all information about a trainer in a usable form + def to_trainer + # Determine trainer's name + tr_name = self.name + RIVAL_NAMES.each do |rival| + next if rival[0] != @trainer_type || !$game_variables[rival[1]].is_a?(String) + tr_name = $game_variables[rival[1]] + break + end + # Create trainer object + trainer = PokeBattle_Trainer.new(tr_name, @trainer_type) + trainer.setForeignID($Trainer) + party = [] + # Create each Pokémon owned by the trainer + @pokemon.each do |pkmn_data| + species = GameData::Species.get(pkmn_data[:species]).species + pkmn = Pokemon.new(species, pkmn_data[:level], trainer, false) + party.push(pkmn) + # Set Pokémon's properties if defined + if pkmn_data[:form] + pkmn.forcedForm = pkmn_data[:form] if MultipleForms.hasFunction?(species, "getForm") + pkmn.formSimple = pkmn_data[:form] + end + pkmn.setItem(pkmn_data[:item]) + if pkmn_data[:moves] && pkmn_data[:moves].length > 0 + pkmn_data[:moves].each { |move| pkmn.pbLearnMove(move) } + else + pkmn.resetMoves + end + pkmn.setAbility(pkmn_data[:ability_flag]) + gender = pkmn_data[:gender] || ((trainer.female?) ? 1 : 0) + pkmn.setGender(gender) + (pkmn_data[:shininess]) ? pkmn.makeShiny : pkmn.makeNotShiny + if pkmn_data[:nature] + pkmn.setNature(pkmn_data[:nature]) + else + nature = pkmn.species_data.id_number + GameData::TrainerType.get(trainer.trainertype).id_number + pkmn.setNature(nature % (PBNatures.maxValue + 1)) + end + PBStats.eachStat do |s| + if pkmn_data[:iv] && pkmn_data[:iv].length > 0 + pkmn.iv[s] = pkmn_data[:iv][s] || pkmn_data[:iv][0] + else + pkmn.iv[s] = [pkmn_data[:level] / 2, Pokemon::IV_STAT_LIMIT].min + end + if pkmn_data[:ev] && pkmn_data[:ev].length > 0 + pkmn.ev[s] = pkmn_data[:ev][s] || pkmn_data[:ev][0] + else + pkmn.ev[s] = [pkmn_data[:level] * 3 / 2, Pokemon::EV_LIMIT / 6].min + end + end + pkmn.happiness = pkmn_data[:happiness] if pkmn_data[:happiness] + pkmn.name = pkmn_data[:name] if pkmn_data[:name] && !pkmn_data[:name].empty? + if pkmn_data[:shadowness] + pkmn.makeShadow + pkmn.pbUpdateShadowMoves(true) + pkmn.makeNotShiny + end + pkmn.ballused = pkmn_data[:poke_ball] if pkmn_data[:poke_ball] + pkmn.calcStats + end + return [trainer, @items.clone, party, self.lose_text] + end + end +end + +#=============================================================================== +# Deprecated methods +#=============================================================================== +def pbGetTrainerData(tr_type, tr_name, tr_version = 0) + Deprecation.warn_method('pbGetTrainerData', 'v20', 'GameData::Trainer.get(tr_type, tr_name, tr_version)') + return GameData::Trainer.get(tr_type, tr_name, tr_version) +end diff --git a/Data/Scripts/014_Trainers/002_PTrainer_NPCTrainers.rb b/Data/Scripts/014_Trainers/002_PTrainer_NPCTrainers.rb index 0471698ad..1bc08cb44 100644 --- a/Data/Scripts/014_Trainers/002_PTrainer_NPCTrainers.rb +++ b/Data/Scripts/014_Trainers/002_PTrainer_NPCTrainers.rb @@ -1,143 +1,26 @@ -#=============================================================================== -# Trainer data -#=============================================================================== -module TrainerData - SPECIES = 0 - LEVEL = 1 - ITEM = 2 - MOVES = 3 - ABILITY = 4 - GENDER = 5 - FORM = 6 - SHINY = 7 - NATURE = 8 - IV = 9 - HAPPINESS = 10 - NAME = 11 - SHADOW = 12 - BALL = 13 - EV = 14 - LOSETEXT = 15 - - SCHEMA = { - "Items" => [0, "eEEEEEEE", :Item, :Item, :Item, :Item, - :Item, :Item, :Item, :Item], - "Pokemon" => [SPECIES, "ev", :Species, nil], # Species, level - "Item" => [ITEM, "e", :Item], - "Moves" => [MOVES, "eEEE", :Move, :Move, :Move, :Move], - "Ability" => [ABILITY, "u"], - "Gender" => [GENDER, "e", { "M" => 0, "m" => 0, "Male" => 0, "male" => 0, "0" => 0, - "F" => 1, "f" => 1, "Female" => 1, "female" => 1, "1" => 1 }], - "Form" => [FORM, "u"], - "Shiny" => [SHINY, "b"], - "Nature" => [NATURE, "e", :PBNatures], - "IV" => [IV, "uUUUUU"], - "Happiness" => [HAPPINESS, "u"], - "Name" => [NAME, "s"], - "Shadow" => [SHADOW, "b"], - "Ball" => [BALL, "u"], - "EV" => [EV, "uUUUUU"], - "LoseText" => [LOSETEXT, "s"] - } -end - #=============================================================================== # #=============================================================================== -def pbLoadTrainer(tr_type, tr_name, tr_id = 0) - if !GameData::TrainerType.exists?(tr_type) - raise _INTL("Trainer type {1} does not exist.", tr_type) - end - tr_type = GameData::TrainerType.get(tr_type).id - success = false - items = [] - party = [] - opponent = nil - trainers = pbLoadTrainersData - for trainer in trainers - next if trainer[0] != tr_type || trainer[1] != tr_name || trainer[4] != tr_id - # Found the trainer we want, load it up - items = trainer[2].clone - tr_name = pbGetMessageFromHash(MessageTypes::TrainerNames, tr_name) - for i in RIVAL_NAMES - next if i[0] != tr_type || !$game_variables[i[1]].is_a?(String) - tr_name = $game_variables[i[1]] - break - end - loseText = pbGetMessageFromHash(MessageTypes::TrainerLoseText,trainer[5]) - opponent = PokeBattle_Trainer.new(tr_name, tr_type) - opponent.setForeignID($Trainer) - # Load up each Pokémon in the trainer's party - for poke in trainer[3] - species = GameData::Species.get(poke[TrainerData::SPECIES]).species - level = poke[TrainerData::LEVEL] - pokemon = Pokemon.new(species,level,opponent,false) - if poke[TrainerData::FORM] - pokemon.forcedForm = poke[TrainerData::FORM] if MultipleForms.hasFunction?(pokemon.species,"getForm") - pokemon.formSimple = poke[TrainerData::FORM] - end - pokemon.setItem(poke[TrainerData::ITEM]) - if poke[TrainerData::MOVES] && poke[TrainerData::MOVES].length>0 - for move in poke[TrainerData::MOVES] - pokemon.pbLearnMove(move) - end - else - pokemon.resetMoves - end - pokemon.setAbility(poke[TrainerData::ABILITY]) - g = (poke[TrainerData::GENDER]) ? poke[TrainerData::GENDER] : (opponent.female?) ? 1 : 0 - pokemon.setGender(g) - (poke[TrainerData::SHINY]) ? pokemon.makeShiny : pokemon.makeNotShiny - if poke[TrainerData::NATURE] - n = poke[TrainerData::NATURE] - else - n = pokemon.species_data.id_number + GameData::TrainerType.get(opponent.trainertype).id_number - n = n % (PBNatures.maxValue + 1) - end - pokemon.setNature(n) - for i in 0...6 - if poke[TrainerData::IV] && poke[TrainerData::IV].length>0 - pokemon.iv[i] = (i0 - pokemon.ev[i] = (i0 + break if i > 0 pbMessage(_INTL("This trainer must have at least 1 Pokémon!")) end end end - trainer = [tr_type,tr_name,[],pokemon,tr_id] - if savechanges - data = pbLoadTrainersData - data.push(trainer) - save_data(data,"Data/trainers.dat") - $PokemonTemp.trainersData = nil + trainer = [tr_type, tr_name, [], party, tr_version] + if save_changes + trainer_hash = { + :id => GameData::Trainer::HASH.keys.length / 2, + :trainer_type => tr_type, + :name => tr_name, + :version => tr_version, + :pokemon => [] + } + party.each do |pkmn| + trainer_hash[:pokemon].push({ + :species => pkmn[0], + :level => pkmn[1] + }) + end + # Add trainer's data to records + key = [tr_type, tr_name, tr_version] + GameData::Trainer::DATA[trainer_hash[:id]] = GameData::Trainer::DATA[key] = GameData::Trainer.new(trainer_hash) + GameData::Trainer.save pbConvertTrainerData pbMessage(_INTL("The Trainer's data was added to the list of battles and in PBS/trainers.txt.")) end @@ -181,57 +77,48 @@ def pbTrainerTypeCheck(trainer_type) end def pbGetFreeTrainerParty(tr_type, tr_name) - if !GameData::TrainerType.exists?(tr_type) - raise _INTL("Trainer type {1} does not exist.", tr_type) - end - tr_type = GameData::TrainerType.get(tr_type).id - trainers = pbLoadTrainersData - used_ids = [] - for trainer in trainers - next if trainer[0] != tr_type || trainer[1] != tr_name - used_ids.push(trainer[4]) - end + tr_type_data = GameData::TrainerType.try_get(tr_type) + raise _INTL("Trainer type {1} does not exist.", tr_type) if !tr_type_data + tr_type = tr_type_data.id for i in 0...256 - return i if !used_ids.include?(i) + return i if !GameData::Trainer.try_get(tr_type, tr_name, i) end return -1 end # Called from trainer events to ensure the trainer exists -def pbTrainerCheck(tr_type, tr_name, max_battles, tr_id = 0) +def pbTrainerCheck(tr_type, tr_name, max_battles, tr_version = 0) return true if !$DEBUG # Check for existence of trainer type pbTrainerTypeCheck(tr_type) - return false if !GameData::TrainerType.exists?(tr_type) - tr_type = GameData::TrainerType.get(tr_type).id + tr_type_data = GameData::TrainerType.try_get(tr_type) + return false if !tr_type_data + tr_type = tr_type_data.id # Check for existence of trainer with given ID number - return true if pbLoadTrainer(tr_type, tr_name, tr_id) + return true if GameData::Trainer.exists?(tr_type, tr_name, tr_version) # Add new trainer if pbConfirmMessage(_INTL("Add new trainer variant {1} (of {2}) for {3} {4}?", - tr_id, max_battles, tr_type.to_s, tr_name)) - pbNewTrainer(tr_type, tr_name, tr_id) + tr_version, max_battles, tr_type.to_s, tr_name)) + pbNewTrainer(tr_type, tr_name, tr_version) end return true end -def pbMissingTrainer(tr_type, tr_name, tr_id) - if !GameData::TrainerType.exists?(tr_type) - raise _INTL("Trainer type {1} does not exist.", tr_type) - end - tr_type = GameData::TrainerType.get(tr_type).id +def pbMissingTrainer(tr_type, tr_name, tr_version) + tr_type_data = GameData::TrainerType.try_get(tr_type) + raise _INTL("Trainer type {1} does not exist.", tr_type) if !tr_type_data + tr_type = tr_type_data.id if !$DEBUG - raise _INTL("Can't find trainer ({1}, {2}, ID {3})", tr_type.to_s, tr_name, tr_id) + raise _INTL("Can't find trainer ({1}, {2}, ID {3})", tr_type.to_s, tr_name, tr_version) end message = "" - if tr_id != 0 - message = _INTL("Add new trainer ({1}, {2}, ID {3})?", tr_type.to_s, tr_name, tr_id) + if tr_version != 0 + message = _INTL("Add new trainer ({1}, {2}, ID {3})?", tr_type.to_s, tr_name, tr_version) else message = _INTL("Add new trainer ({1}, {2})?", tr_type.to_s, tr_name) end cmd = pbMessage(message, [_INTL("Yes"), _INTL("No")], 2) - if cmd == 0 - pbNewTrainer(tr_type, tr_name, tr_id) - end + pbNewTrainer(tr_type, tr_name, tr_version) if cmd == 0 return cmd end diff --git a/Data/Scripts/015_Items/004_PItem_Phone.rb b/Data/Scripts/015_Items/004_PItem_Phone.rb index d1fb03d41..2d72790ed 100644 --- a/Data/Scripts/015_Items/004_PItem_Phone.rb +++ b/Data/Scripts/015_Items/004_PItem_Phone.rb @@ -265,16 +265,20 @@ end def pbTrainerSpecies(phonenum) return "" if !phonenum[0] - partyid = [0,(phonenum[5]-1)].max - trainer = pbGetTrainerData(phonenum[1],phonenum[2],partyid) - return "" if !trainer || trainer[3].length==0 - rndpoke = trainer[3][rand(trainer[3].length)] - return GameData::Species.get(rndpoke[0]).name + partyid = [0, phonenum[5] - 1].max + trainer_data = GameData::Trainer.try_get(phonenum[1], phonenum[2], partyid) + return "" if !trainer_data + if trainer_data.pokemon.length == 1 + pkmn = trainer_data.pokemon[0][:species] + else + pkmn = trainer_data.pokemon[rand(trainer_data.pokemon.length)][:species] + end + return GameData::Species.get(pkmn).name end def pbTrainerMapName(phonenum) - return "" if !phonenum[6] || phonenum[6]==0 - return pbGetMessage(MessageTypes::MapNames,phonenum[6]) + return "" if !phonenum[6] || phonenum[6] == 0 + return pbGetMessage(MessageTypes::MapNames, phonenum[6]) end #=============================================================================== diff --git a/Data/Scripts/021_Debug/004_Editor_Screens.rb b/Data/Scripts/021_Debug/004_Editor_Screens.rb index 0d93676d3..e13846b34 100644 --- a/Data/Scripts/021_Debug/004_Editor_Screens.rb +++ b/Data/Scripts/021_Debug/004_Editor_Screens.rb @@ -221,7 +221,6 @@ end # Trainer type editor #=============================================================================== def pbTrainerTypeEditor - selection = 0 trainer_type_properties = [ [_INTL("Internal Name"), ReadOnlyProperty, _INTL("Internal name that is used as a symbol like :XXX.")], [_INTL("Trainer Name"), StringProperty, _INTL("Name of the trainer type as displayed by the game.")], @@ -235,9 +234,9 @@ def pbTrainerTypeEditor [_INTL("Skill Level"), LimitProperty.new(9999), _INTL("Skill level of this Trainer type.")], [_INTL("Skill Code"), StringProperty, _INTL("Letters/phrases representing AI modifications of trainers of this type.")], ] - pbListScreenBlock(_INTL("Trainer Types"), TrainerTypeLister.new(selection, true)) { |button, tr_type| + pbListScreenBlock(_INTL("Trainer Types"), TrainerTypeLister.new(0, true)) { |button, tr_type| if tr_type - if button==Input::A + if button == Input::A if tr_type.is_a?(Symbol) if pbConfirmMessageSerious("Delete this trainer type?") id_number = GameData::TrainerType.get(tr_type).id_number @@ -354,32 +353,24 @@ end # Individual trainer editor #=============================================================================== module TrainerBattleProperty - def self.set(settingname,oldsetting) + NUM_ITEMS = 8 + + def self.set(settingname, oldsetting) return nil if !oldsetting properties = [ [_INTL("Trainer Type"), TrainerTypeProperty, _INTL("Name of the trainer type for this Trainer.")], [_INTL("Trainer Name"), StringProperty, _INTL("Name of the Trainer.")], - [_INTL("Battle ID"), LimitProperty.new(9999), _INTL("ID used to distinguish Trainers with the same name and trainer type.")], - [_INTL("Lose Text"), StringProperty, _INTL("Message shown in battle when the Trainer is defeated.")], - [_INTL("Pokémon 1"), TrainerPokemonProperty, _INTL("First Pokémon.")], - [_INTL("Pokémon 2"), TrainerPokemonProperty, _INTL("Second Pokémon.")], - [_INTL("Pokémon 3"), TrainerPokemonProperty, _INTL("Third Pokémon.")], - [_INTL("Pokémon 4"), TrainerPokemonProperty, _INTL("Fourth Pokémon.")], - [_INTL("Pokémon 5"), TrainerPokemonProperty, _INTL("Fifth Pokémon.")], - [_INTL("Pokémon 6"), TrainerPokemonProperty, _INTL("Sixth Pokémon.")], - [_INTL("Item 1"), ItemProperty, _INTL("Item used by the Trainer during battle.")], - [_INTL("Item 2"), ItemProperty, _INTL("Item used by the Trainer during battle.")], - [_INTL("Item 3"), ItemProperty, _INTL("Item used by the Trainer during battle.")], - [_INTL("Item 4"), ItemProperty, _INTL("Item used by the Trainer during battle.")], - [_INTL("Item 5"), ItemProperty, _INTL("Item used by the Trainer during battle.")], - [_INTL("Item 6"), ItemProperty, _INTL("Item used by the Trainer during battle.")], - [_INTL("Item 7"), ItemProperty, _INTL("Item used by the Trainer during battle.")], - [_INTL("Item 8"), ItemProperty, _INTL("Item used by the Trainer during battle.")] + [_INTL("Version"), LimitProperty.new(9999), _INTL("Number used to distinguish Trainers with the same name and trainer type.")], + [_INTL("Lose Text"), StringProperty, _INTL("Message shown in battle when the Trainer is defeated.")] ] - if !pbPropertyList(settingname,oldsetting,properties,true) - return nil + MAX_PARTY_SIZE.times do |i| + properties.push([_INTL("Pokémon {1}", i + 1), TrainerPokemonProperty, _INTL("A Pokémon owned by the Trainer.")]) end - oldsetting = nil if !oldsetting[0] || oldsetting[0]==0 + NUM_ITEMS.times do |i| + properties.push([_INTL("Item {1}", i + 1), ItemProperty, _INTL("An item used by the Trainer during battle.")]) + end + return nil if !pbPropertyList(settingname, oldsetting, properties, true) + oldsetting = nil if !oldsetting[0] return oldsetting end @@ -391,92 +382,126 @@ end def pbTrainerBattleEditor - selection = 0 - trainers = pbLoadTrainersData modified = false - for trainer in trainers - next if GameData::TrainerType.exists?(trainer[0]) - trainer[0] = nil - modified = true - end - pbListScreenBlock(_INTL("Trainer Battles"),TrainerBattleLister.new(selection,true)) { |button,trtype| - next if !trtype - index = trtype[0] - trainerdata = trtype[1] - if button==Input::A - # Delete trainer - if index>=0 - if pbConfirmMessageSerious("Delete this trainer battle?") - trainers.delete_at(index) - modified = true - pbMessage(_INTL("The Trainer battle was deleted.")) - end - end - elsif button==Input::C - # New trainer/edit existing trainer - selection = index - if selection<0 - # New trainer - trainertype = nil - ret = pbMessage(_INTL("First, define the new trainer's type."),[ - _INTL("Use existing type"), - _INTL("Create new type"), - _INTL("Cancel")], 3) - if ret==0 - trainertype = pbListScreen(_INTL("TRAINER TYPE"),TrainerTypeLister.new(0,false)) - elsif ret==1 - trainertype = pbTrainerTypeEditorNew(nil) - else - next - end - next if !trainertype - trainername = pbMessageFreeText(_INTL("Now enter the trainer's name."),"",false,30) - next if trainername=="" - trainerparty = pbGetFreeTrainerParty(trainertype,trainername) - if trainerparty<0 - pbMessage(_INTL("There is no room to create a trainer of that type and name.")) - next - end - t = pbNewTrainer(trainertype,trainername,trainerparty,false) - trainers.push(t) if t - pbMessage(_INTL("The Trainer battle was added.")) - else - # Edit existing trainer - data = [trainerdata[0],trainerdata[1],trainerdata[4],trainerdata[5]] # Type, name, ID, lose text - for i in 0...6 - data.push(trainerdata[3][i]) # Pokémon - end - for i in 0...8 - data.push(trainerdata[2][i]) # Items - end - loop do - data = TrainerBattleProperty.set(trainerdata[1],data) - break if !data - trainerdata = [ - data[0], - data[1], - [data[10],data[11],data[12],data[13],data[14],data[15],data[16],data[17]].compact!, # Item list - [data[4],data[5],data[6],data[7],data[8],data[9]].find_all { |i| i && i[TrainerData::SPECIES]!=0 }, # Pokémon list - data[2], - data[3] - ] - if !trainerdata[1] || trainerdata[1].length==0 - pbMessage(_INTL("Can't save. No name was entered.")) - elsif trainerdata[3].length==0 - pbMessage(_INTL("Can't save. The Pokémon list is empty.")) - else - trainers[index] = trainerdata + pbListScreenBlock(_INTL("Trainer Battles"), TrainerBattleLister.new(0, true)) { |button, trainer_id| + if trainer_id + if button == Input::A + if trainer_id.is_a?(Array) + if pbConfirmMessageSerious("Delete this trainer battle?") + tr_data = GameData::Trainer::DATA[trainer_id] + GameData::Trainer::DATA.delete(trainer_id) + GameData::Trainer::DATA.delete(tr_data.id_number) + modified = true + pbMessage(_INTL("The Trainer battle was deleted.")) + end + end + elsif button == Input::C + if trainer_id.is_a?(Array) # Edit existing trainer + tr_data = GameData::Trainer::DATA[trainer_id] + old_type = tr_data.trainer_type + old_name = tr_data.real_name + old_version = tr_data.version + data = [ + tr_data.trainer_type, + tr_data.real_name, + tr_data.version, + tr_data.real_lose_text + ] + for i in 0...MAX_PARTY_SIZE + data.push(tr_data.pokemon[i]) + end + for i in 0...TrainerBattleProperty::NUM_ITEMS + data.push(tr_data.items[i]) + end + loop do + data = TrainerBattleProperty.set(tr_data.real_name, data) + break if !data + party = [] + items = [] + for i in 0...MAX_PARTY_SIZE + party.push(data[4 + i]) if data[4 + i] && data[4 + i][:species] + end + for i in 0...TrainerBattleProperty::NUM_ITEMS + items.push(data[4 + MAX_PARTY_SIZE + i]) if data[4 + MAX_PARTY_SIZE + i] + end + if !data[0] + pbMessage(_INTL("Can't save. No trainer type was chosen.")) + elsif !data[1] || data[1].empty? + pbMessage(_INTL("Can't save. No name was entered.")) + elsif party.length == 0 + pbMessage(_INTL("Can't save. The Pokémon list is empty.")) + else + trainer_hash = { + :id => tr_data.id_number, + :trainer_type => data[0], + :name => data[1], + :version => data[2], + :lose_text => data[3], + :pokemon => party, + :items => items + } + # Add trainer type's data to records + key = [data[0], data[1], data[2]] + GameData::Trainer::DATA[tr_data.id_number] = GameData::Trainer::DATA[key] = GameData::Trainer.new(trainer_hash) + if data[0] != old_type || data[1] != old_name || data[2] != old_version + GameData::Trainer::DATA.delete([old_type, old_name, old_version]) + end + modified = true + break + end + end + else # New trainer + tr_type = nil + ret = pbMessage(_INTL("First, define the new trainer's type."), [ + _INTL("Use existing type"), + _INTL("Create new type"), + _INTL("Cancel")], 3) + case ret + when 0 + tr_type = pbListScreen(_INTL("TRAINER TYPE"), TrainerTypeLister.new(0, false)) + when 1 + tr_type = pbTrainerTypeEditorNew(nil) + else + next + end + next if !tr_type + tr_name = pbMessageFreeText(_INTL("Now enter the trainer's name."), "", false, 30) + next if tr_name == "" + tr_version = pbGetFreeTrainerParty(tr_type, tr_name) + if tr_version < 0 + pbMessage(_INTL("There is no room to create a trainer of that type and name.")) + next + end + t = pbNewTrainer(tr_type, tr_name, tr_version, false) + if t + trainer_hash = { + :id => GameData::Trainer::HASH.keys.length / 2, + :trainer_type => tr_type, + :name => tr_name, + :version => tr_version, + :pokemon => [] + } + t[3].each do |pkmn| + trainer_hash[:pokemon].push({ + :species => pkmn[0], + :level => pkmn[1] + }) + end + # Add trainer's data to records + key = [tr_type, tr_name, tr_version] + GameData::Trainer::DATA[trainer_hash[:id]] = GameData::Trainer::DATA[key] = GameData::Trainer.new(trainer_hash) + pbMessage(_INTL("The Trainer battle was added.")) modified = true - break end end end end } if modified && pbConfirmMessage(_INTL("Save changes?")) - save_data(trainers,"Data/trainers.dat") - $PokemonTemp.trainersData = nil + GameData::Trainer.save pbConvertTrainerData + else + GameData::Trainer.load end end @@ -487,60 +512,81 @@ end #=============================================================================== module TrainerPokemonProperty def self.set(settingname,initsetting) - initsetting = [0,10] if !initsetting - oldsetting = [] - for i in 0...TrainerData::EV - if i==TrainerData::MOVES - for j in 0...4 - oldsetting.push((initsetting[TrainerData::MOVES]) ? initsetting[TrainerData::MOVES][j] : nil) - end - else - oldsetting.push(initsetting[i]) - end + initsetting = {:species => nil, :level => 10} if !initsetting + oldsetting = [ + initsetting[:species], + initsetting[:level], + initsetting[:name], + initsetting[:form], + initsetting[:gender], + initsetting[:shininess], + initsetting[:shadowness] + ] + Pokemon::MAX_MOVES.times do |i| + oldsetting.push((initsetting[:moves]) ? initsetting[:moves][i] : nil) end - mLevel = PBExperience.maxLevel + oldsetting.concat([ + initsetting[:ability_flag], + initsetting[:item], + initsetting[:nature], + initsetting[:iv], + initsetting[:ev], + initsetting[:happiness], + initsetting[:poke_ball] + ]) + max_level = PBExperience.maxLevel pkmn_properties = [ [_INTL("Species"), SpeciesProperty, _INTL("Species of the Pokémon.")], - [_INTL("Level"), NonzeroLimitProperty.new(mLevel), _INTL("Level of the Pokémon (1-{1}).",mLevel)], - [_INTL("Held item"), ItemProperty, _INTL("Item held by the Pokémon.")], - [_INTL("Move 1"), MoveProperty2.new(oldsetting), _INTL("First move. Leave all moves blank (use Z key) to give it a wild moveset.")], - [_INTL("Move 2"), MoveProperty2.new(oldsetting), _INTL("Second move. Leave all moves blank (use Z key) to give it a wild moveset.")], - [_INTL("Move 3"), MoveProperty2.new(oldsetting), _INTL("Third move. Leave all moves blank (use Z key) to give it a wild moveset.")], - [_INTL("Move 4"), MoveProperty2.new(oldsetting), _INTL("Fourth move. Leave all moves blank (use Z key) to give it a wild moveset.")], - [_INTL("Ability"), LimitProperty2.new(5), _INTL("Ability flag. 0=first ability, 1=second ability, 2-5=hidden ability.")], - [_INTL("Gender"), GenderProperty.new, _INTL("Gender of the Pokémon.")], + [_INTL("Level"), NonzeroLimitProperty.new(max_level), _INTL("Level of the Pokémon (1-{1}).", max_level)], + [_INTL("Name"), StringProperty, _INTL("Name of the Pokémon.")], [_INTL("Form"), LimitProperty2.new(999), _INTL("Form of the Pokémon.")], + [_INTL("Gender"), GenderProperty.new, _INTL("Gender of the Pokémon.")], [_INTL("Shiny"), BooleanProperty2, _INTL("If set to true, the Pokémon is a different-colored Pokémon.")], + [_INTL("Shadow"), BooleanProperty2, _INTL("If set to true, the Pokémon is a Shadow Pokémon.")] + ] + Pokemon::MAX_MOVES.times do |i| + pkmn_properties.push([_INTL("Move {1}", i + 1), MovePropertyForSpecies.new(oldsetting), _INTL("A move known by the Pokémon. Leave all moves blank (use Z key to delete) for a wild moveset.")]) + end + pkmn_properties.concat([ + [_INTL("Ability"), LimitProperty2.new(99), _INTL("Ability flag. 0=first ability, 1=second ability, 2-5=hidden ability.")], + [_INTL("Held item"), ItemProperty, _INTL("Item held by the Pokémon.")], [_INTL("Nature"), NatureProperty, _INTL("Nature of the Pokémon.")], [_INTL("IVs"), IVsProperty.new(Pokemon::IV_STAT_LIMIT), _INTL("Individual values for each of the Pokémon's stats.")], + [_INTL("EVs"), EVsProperty.new(Pokemon::EV_STAT_LIMIT), _INTL("Effort values for each of the Pokémon's stats.")], [_INTL("Happiness"), LimitProperty2.new(255), _INTL("Happiness of the Pokémon (0-255).")], - [_INTL("Nickname"), StringProperty, _INTL("Name of the Pokémon.")], - [_INTL("Shadow"), BooleanProperty2, _INTL("If set to true, the Pokémon is a Shadow Pokémon.")], - [_INTL("Ball"), BallProperty.new(oldsetting), _INTL("The kind of Poké Ball the Pokémon is kept in.")], - [_INTL("EVs"), EVsProperty.new(Pokemon::EV_STAT_LIMIT), _INTL("Effort values for each of the Pokémon's stats.")] - ] + [_INTL("Poké Ball"), BallProperty.new(oldsetting), _INTL("The kind of Poké Ball the Pokémon is kept in.")] + ]) pbPropertyList(settingname, oldsetting, pkmn_properties, false) - return nil if !oldsetting[TrainerData::SPECIES] - ret = [] + return nil if !oldsetting[0] # Species is nil + ret = { + :species => oldsetting[0], + :level => oldsetting[1], + :name => oldsetting[2], + :form => oldsetting[3], + :gender => oldsetting[4], + :shininess => oldsetting[5], + :shadowness => oldsetting[6], + :ability_flag => oldsetting[7 + Pokemon::MAX_MOVES], + :item => oldsetting[8 + Pokemon::MAX_MOVES], + :nature => oldsetting[9 + Pokemon::MAX_MOVES], + :iv => oldsetting[10 + Pokemon::MAX_MOVES], + :ev => oldsetting[11 + Pokemon::MAX_MOVES], + :happiness => oldsetting[12 + Pokemon::MAX_MOVES], + :poke_ball => oldsetting[13 + Pokemon::MAX_MOVES], + } moves = [] - for i in 0...oldsetting.length - if i>=TrainerData::MOVES && i0 - # Remove unnecessary nils from the end of ret - ret.pop while ret.last.nil? && ret.size>0 + ret[:moves] = moves return ret end def self.format(value) - return "-" if !value || !value[TrainerData::SPECIES] - return sprintf("%s,%d", GameData::Species.get(value[TrainerData::SPECIES]).name, value[TrainerData::LEVEL]) + return "-" if !value || !value[:species] + return sprintf("%s,%d", GameData::Species.get(value[:species]).name, value[:level]) end end @@ -636,7 +682,6 @@ end # Item editor #=============================================================================== def pbItemEditor - selection = 0 item_properties = [ [_INTL("Internal Name"), ReadOnlyProperty, _INTL("Internal name that is used as a symbol like :XXX.")], [_INTL("Item Name"), ItemNameProperty, _INTL("Name of the item as displayed by the game.")], @@ -662,7 +707,7 @@ def pbItemEditor _INTL("Mega Stone")]), _INTL("For special kinds of items.")], [_INTL("Machine"), MoveProperty, _INTL("Move taught by this TM or HM.")] ] - pbListScreenBlock(_INTL("Items"), ItemLister.new(selection, true)) { |button, item| + pbListScreenBlock(_INTL("Items"), ItemLister.new(0, true)) { |button, item| if item if button == Input::A if item.is_a?(Symbol) @@ -784,7 +829,6 @@ end # Pokémon species editor #=============================================================================== def pbPokemonEditor - selection = 0 species_properties = [ [_INTL("InternalName"), ReadOnlyProperty, _INTL("Internal name of the Pokémon.")], [_INTL("Name"), LimitStringProperty.new(Pokemon::MAX_NAME_SIZE), _INTL("Name of the Pokémon.")], @@ -848,7 +892,7 @@ def pbPokemonEditor [_INTL("BattlerShadowX"), ReadOnlyProperty, _INTL("Affects positioning of the Pokémon in battle. This is edited elsewhere.")], [_INTL("BattlerShadowSize"), ReadOnlyProperty, _INTL("Affects positioning of the Pokémon in battle. This is edited elsewhere.")], ] - pbListScreenBlock(_INTL("Pokémon species"), SpeciesLister.new(selection, false)) { |button, species| + pbListScreenBlock(_INTL("Pokémon species"), SpeciesLister.new(0, false)) { |button, species| if species if button == Input::A if species.is_a?(Symbol) diff --git a/Data/Scripts/021_Debug/007_Editor_DataTypes.rb b/Data/Scripts/021_Debug/007_Editor_DataTypes.rb index 57dd1a946..da7200bd7 100644 --- a/Data/Scripts/021_Debug/007_Editor_DataTypes.rb +++ b/Data/Scripts/021_Debug/007_Editor_DataTypes.rb @@ -312,13 +312,13 @@ end -class MoveProperty2 +class MovePropertyForSpecies def initialize(pokemondata) @pokemondata = pokemondata end def set(_settingname, oldsetting) - ret = pbChooseMoveListForSpecies(@pokemondata[TrainerData::SPECIES], oldsetting || nil) + ret = pbChooseMoveListForSpecies(@pokemondata[0], oldsetting || nil) return ret || oldsetting end @@ -394,7 +394,7 @@ class IVsProperty @limit = limit end - def set(settingname,oldsetting) + def set(settingname, oldsetting) oldsetting = [nil] if !oldsetting for i in 0...6 oldsetting[i] = oldsetting[0] if !oldsetting[i] @@ -406,21 +406,13 @@ class IVsProperty properties[PBStats::SPATK] = [_INTL("Sp. Atk"), LimitProperty2.new(@limit), _INTL("Individual values for the Pokémon's Sp. Atk stat (0-{1}).", @limit)] properties[PBStats::SPDEF] = [_INTL("Sp. Def"), LimitProperty2.new(@limit), _INTL("Individual values for the Pokémon's Sp. Def stat (0-{1}).", @limit)] properties[PBStats::SPEED] = [_INTL("Speed"), LimitProperty2.new(@limit), _INTL("Individual values for the Pokémon's Speed stat (0-{1}).", @limit)] - pbPropertyList(settingname,oldsetting,properties,false) + pbPropertyList(settingname, oldsetting, properties, false) hasNonNil = false - hasAltVal = false firstVal = oldsetting[0] || 0 for i in 0...6 - if oldsetting[i] - hasNonNil = true - hasAltVal = true if oldsetting[i]!=firstVal - else - oldsetting[i] = firstVal - end + (oldsetting[i]) ? hasNonNil = true : oldsetting[i] = firstVal end - return nil if !hasNonNil # All IVs are nil - return [firstVal] if !hasAltVal # All IVs are the same, just return 1 value - return oldsetting # 6 IVs defined + return (hasNonNil) ? oldsetting : nil end def defaultValue @@ -429,10 +421,10 @@ class IVsProperty def format(value) return "-" if !value - return value[0].to_s if value.length==1 + return value[0].to_s if value.uniq.length == 1 ret = "" for i in 0...6 - ret.concat(",") if i>0 + ret.concat(",") if i > 0 ret.concat((value[i] || 0).to_s) end return ret @@ -446,7 +438,7 @@ class EVsProperty @limit = limit end - def set(settingname,oldsetting) + def set(settingname, oldsetting) oldsetting = [nil] if !oldsetting for i in 0...6 oldsetting[i] = oldsetting[0] if !oldsetting[i] @@ -459,31 +451,23 @@ class EVsProperty properties[PBStats::SPDEF] = [_INTL("Sp. Def"), LimitProperty2.new(@limit), _INTL("Effort values for the Pokémon's Sp. Def stat (0-{1}).", @limit)] properties[PBStats::SPEED] = [_INTL("Speed"), LimitProperty2.new(@limit), _INTL("Effort values for the Pokémon's Speed stat (0-{1}).", @limit)] loop do - pbPropertyList(settingname,oldsetting,properties,false) + pbPropertyList(settingname, oldsetting, properties, false) evtotal = 0 for i in 0...6 evtotal += oldsetting[i] if oldsetting[i] end - if evtotal>Pokemon::EV_LIMIT + if evtotal > Pokemon::EV_LIMIT pbMessage(_INTL("Total EVs ({1}) are greater than allowed ({2}). Please reduce them.", evtotal, Pokemon::EV_LIMIT)) else break end end hasNonNil = false - hasAltVal = false firstVal = oldsetting[0] || 0 for i in 0...6 - if oldsetting[i] - hasNonNil = true - hasAltVal = true if oldsetting[i]!=firstVal - else - oldsetting[i] = firstVal - end + (oldsetting[i]) ? hasNonNil = true : oldsetting[i] = firstVal end - return nil if !hasNonNil # All EVs are nil - return [firstVal] if !hasAltVal # All EVs are the same, just return 1 value - return oldsetting # 6 EVs defined + return (hasNonNil) ? oldsetting : nil end def defaultValue @@ -492,10 +476,10 @@ class EVsProperty def format(value) return "-" if !value - return value[0].to_s if value.length==1 + return value[0].to_s if value.uniq.length == 1 ret = "" for i in 0...6 - ret.concat(",") if i>0 + ret.concat(",") if i > 0 ret.concat((value[i] || 0).to_s) end return ret diff --git a/Data/Scripts/021_Debug/008_Editor_Listers.rb b/Data/Scripts/021_Debug/008_Editor_Listers.rb index f6280c8dd..dfc9845ff 100644 --- a/Data/Scripts/021_Debug/008_Editor_Listers.rb +++ b/Data/Scripts/021_Debug/008_Editor_Listers.rb @@ -442,7 +442,6 @@ class TrainerTypeLister @commands = [] @ids = [] @includeNew = includeNew - @trainers = nil @index = 0 end @@ -466,7 +465,7 @@ class TrainerTypeLister GameData::TrainerType.each do |tr_type| cmds.push([tr_type.id_number, tr_type.id, tr_type.real_name]) end - cmds.sort! { |a, b| a[2].downcase <=> b[2].downcase } + cmds.sort! { |a, b| a[2] == b[2] ? a[0] <=> b[0] : a[2].downcase <=> b[2].downcase } if @includeNew @commands.push(_INTL("[NEW TRAINER TYPE]")) @ids.push(true) @@ -508,17 +507,13 @@ class TrainerBattleLister def initialize(selection,includeNew) @sprite = IconSprite.new(Graphics.width * 3 / 4, (Graphics.height / 2) + 32) @sprite.z = 2 - @pkmnList = Window_UnformattedTextPokemon.new() - @pkmnList.x = Graphics.width/2 - @pkmnList.y = Graphics.height-64 - @pkmnList.width = Graphics.width/2 - @pkmnList.height = 64 - @pkmnList.z = 3 + @pkmnList = Window_UnformattedTextPokemon.newWithSize("", + Graphics.width / 2, Graphics.height - 64, Graphics.width / 2, 64) + @pkmnList.z = 3 @selection = selection @commands = [] @ids = [] @includeNew = includeNew - @trainers = nil @index = 0 end @@ -540,61 +535,74 @@ class TrainerBattleLister def commands @commands.clear @ids.clear - @trainers = pbLoadTrainersData + cmds = [] + GameData::Trainer.each do |trainer| + cmds.push([trainer.id_number, trainer.trainer_type, trainer.real_name, trainer.version]) + end + cmds.sort! { |a, b| + if a[1] == b[1] + if a[2] == b[2] + (a[3] == b[3]) ? a[0] <=> b[0] : a[3] <=> b[3] + else + a[2].downcase <=> b[2].downcase + end + else + a[1].to_s.downcase <=> b[1].to_s.downcase + end + } if @includeNew @commands.push(_INTL("[NEW TRAINER BATTLE]")) - @ids.push(-1) + @ids.push(true) end - @trainers.length.times do |i| - next if !@trainers[i] - if @trainers[i][4]>0 - # TrainerType TrainerName (version) xPartySize - @commands.push(_ISPRINTF("{1:s} {2:s} ({3:d}) x{4:d}", - GameData::TrainerType.get(@trainers[i][0]).name, @trainers[i][1], - @trainers[i][4], @trainers[i][3].length)) + for t in cmds + if t[3] > 0 + @commands.push(_INTL("{1} {2} ({3}) x{4}", + GameData::TrainerType.get(t[1]).name, t[2], t[3], + GameData::Trainer.get(t[1], t[2], t[3]).pokemon.length)) else - # TrainerType TrainerName xPartySize - @commands.push(_ISPRINTF("{1:s} {2:s} x{3:d}", - GameData::TrainerType.get(@trainers[i][0]).name, @trainers[i][1], - @trainers[i][3].length)) + @commands.push(_INTL("{1} {2} x{3}", + GameData::TrainerType.get(t[1]).name, t[2], + GameData::Trainer.get(t[1], t[2], t[3]).pokemon.length)) end - # Trainer type ID - @ids.push(@trainers[i][0]) + @ids.push([t[1], t[2], t[3]]) end - @index = @selection - @index = @commands.length-1 if @index>=@commands.length - @index = 0 if @index<0 + @index = @selection + @index = @commands.length - 1 if @index >= @commands.length + @index = 0 if @index < 0 return @commands end def value(index) - return nil if index<0 - return [-1,nil] if index==0 && @includeNew - realIndex = (@includeNew) ? index-1 : index - return [realIndex,@trainers[realIndex]] + return nil if index < 0 + return @ids[index] end def refresh(index) + # Refresh trainer sprite @sprite.bitmap.dispose if @sprite.bitmap - return if index<0 + return if index < 0 begin - @sprite.setBitmap(GameData::TrainerType.front_sprite_filename(@ids[index]),0) + @sprite.setBitmap(GameData::TrainerType.front_sprite_filename(@ids[index][0]), 0) rescue @sprite.setBitmap(nil) end if @sprite.bitmap - @sprite.ox = @sprite.bitmap.width/2 + @sprite.ox = @sprite.bitmap.width / 2 @sprite.oy = @sprite.bitmap.height end + # Refresh list of Pokémon text = "" - if !@includeNew || index>0 - @trainers[(@includeNew) ? index-1 : index][3].each_with_index do |p,i| - text += "\r\n" if i>0 - text += sprintf("%s Lv.%d",GameData::Species.get(p[TrainerData::SPECIES]).name, p[TrainerData::LEVEL]) + if !@includeNew || index > 0 + tr_data = GameData::Trainer.get(@ids[index][0], @ids[index][1], @ids[index][2]) + if tr_data + tr_data.pokemon.each_with_index do |pkmn, i| + text += "\r\n" if i > 0 + text += sprintf("%s Lv.%d", GameData::Species.get(pkmn[:species]).real_name, pkmn[:level]) + end end end @pkmnList.text = text - @pkmnList.resizeHeightToFit(text,Graphics.width/2) - @pkmnList.y = Graphics.height-@pkmnList.height + @pkmnList.resizeHeightToFit(text,Graphics.width / 2) + @pkmnList.y = Graphics.height - @pkmnList.height end end diff --git a/Data/Scripts/021_Debug/009_Editor_Utilities.rb b/Data/Scripts/021_Debug/009_Editor_Utilities.rb index 090a9dca4..a61d64683 100644 --- a/Data/Scripts/021_Debug/009_Editor_Utilities.rb +++ b/Data/Scripts/021_Debug/009_Editor_Utilities.rb @@ -3,7 +3,7 @@ def pbGetLegalMoves(species) moves = [] return moves if !species_data species_data.moves.each { |m| moves.push(m[1]) } - species_data.tutor_moves.each { |m| moves.push(m[1]) } + species_data.tutor_moves.each { |m| moves.push(m) } babyspecies = EvolutionHelper.baby_species(species) GameData::Species.get(babyspecies).egg_moves.each { |m| moves.push(m) } moves |= [] # Remove duplicates @@ -152,7 +152,7 @@ def pbChooseMoveListForSpecies(species, defaultMoveID = nil) GameData::Move.each do |move_data| commands2.push([move_data.id_number, move_data.name, move_data.id]) end - commands2.sort! { |a, b| a[0] <=> b[0] } + commands2.sort! { |a, b| a[1] <=> b[1] } if defaultMoveID commands2.each_with_index do |_item, i| moveDefault = i if moveDefault == 0 && i[2] == defaultMoveID diff --git a/Data/Scripts/022_Compiler/002_Compiler_CompilePBS.rb b/Data/Scripts/022_Compiler/002_Compiler_CompilePBS.rb index 7975a0e13..7a9cb12c8 100644 --- a/Data/Scripts/022_Compiler/002_Compiler_CompilePBS.rb +++ b/Data/Scripts/022_Compiler/002_Compiler_CompilePBS.rb @@ -979,198 +979,120 @@ module Compiler # Compile individual trainer data #============================================================================= def compile_trainers - trainer_info_types = TrainerData::SCHEMA - mLevel = PBExperience.maxLevel - trainerindex = -1 - trainers = [] - trainernames = [] - trainerlosetext = [] - pokemonindex = -2 - oldcompilerline = 0 - oldcompilerlength = 0 - pbCompilerEachCommentedLine("PBS/trainers.txt") { |line,lineno| + schema = GameData::Trainer::SCHEMA + max_level = PBExperience.maxLevel + trainer_names = [] + trainer_lose_texts = [] + trainer_hash = nil + trainer_id = -1 + current_pkmn = nil + # Read each line of trainers.txt at a time and compile it as a trainer property + pbCompilerEachPreppedLine("PBS/trainers.txt") { |line, line_no| + # New section [trainer_type, name] or [trainer_type, name, version] 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) + if trainer_hash + if !current_pkmn + raise _INTL("Started new trainer while previous trainer has no Pokémon.\r\n{1}", FileLineData.linereport) + end + # Add trainer's data to records + key = [trainer_hash[:trainer_type], trainer_hash[:name], trainer_hash[:version]] + GameData::Trainer::DATA[trainer_id] = GameData::Trainer::DATA[key] = GameData::Trainer.new(trainer_hash) 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",:TrainerType]) - trainerindex += 1 - trainertype = section[0] - trainername = section[1] - partyid = section[2] || 0 - trainers[trainerindex] = [trainertype,trainername,[],[],partyid,nil] - trainernames[trainerindex] = trainername - pokemonindex = -1 + trainer_id += 1 + line_data = pbGetCsvRecord($~[1], line_no, [0, "esU", :TrainerType]) + # Construct trainer hash + trainer_hash = { + :id => trainer_id, + :trainer_type => line_data[0], + :name => line_data[1], + :version => line_data[2] || 0, + :pokemon => [] + } + current_pkmn = nil + trainer_names[trainer_id] = trainer_hash[:name] + # XXX=YYY lines 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) + if !trainer_hash + 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 = trainer_info_types[settingname] - next if !schema - record = pbGetCsvRecord($~[2],lineno,schema) + property_name = $~[1] + line_schema = schema[property_name] + next if !line_schema + property_value = pbGetCsvRecord($~[2], line_no, line_schema) # Error checking in XXX=YYY lines - case settingname + case property_name + when "Items" + property_value = [property_value] if !property_value.is_a?(Array) + property_value.compact! when "Pokemon" - if record[1]>mLevel - raise _INTL("Bad level: {1} (must be 1-{2}).\r\n{3}",record[1],mLevel,FileLineData.linereport) + if property_value[1] > max_level + raise _INTL("Bad level: {1} (must be 1-{2}).\r\n{3}", property_value[1], max_level, FileLineData.linereport) + end + when "Name" + if property_value.length > Pokemon::MAX_NAME_SIZE + raise _INTL("Bad nickname: {1} (must be 1-{2} characters).\r\n{3}", property_value, Pokemon::MAX_NAME_SIZE, FileLineData.linereport) end when "Moves" - record = [record] if record.is_a?(Symbol) - 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 + property_value = [property_value] if !property_value.is_a?(Array) + property_value.uniq! + property_value.compact! when "IV" - record = [record] if record.is_a?(Integer) - record.compact! - for i in record - next if i<=Pokemon::IV_STAT_LIMIT - raise _INTL("Bad IV: {1} (must be 0-{2}).\r\n{3}", i, Pokemon::IV_STAT_LIMIT, FileLineData.linereport) + property_value = [property_value] if !property_value.is_a?(Array) + property_value.compact! + property_value.each do |iv| + next if iv <= Pokemon::IV_STAT_LIMIT + raise _INTL("Bad IV: {1} (must be 0-{2}).\r\n{3}", iv, Pokemon::IV_STAT_LIMIT, FileLineData.linereport) end when "EV" - record = [record] if record.is_a?(Integer) - record.compact! - for i in record - next if i<=Pokemon::EV_STAT_LIMIT - raise _INTL("Bad EV: {1} (must be 0-{2}).\r\n{3}", i, Pokemon::EV_STAT_LIMIT, FileLineData.linereport) + property_value = [property_value] if !property_value.is_a?(Array) + property_value.compact! + property_value.each do |ev| + next if ev <= Pokemon::EV_STAT_LIMIT + raise _INTL("Bad EV: {1} (must be 0-{2}).\r\n{3}", ev, Pokemon::EV_STAT_LIMIT, FileLineData.linereport) end - evtotal = 0 - for i in 0...6 - evtotal += (iPokemon::EV_LIMIT + if ev_total > Pokemon::EV_LIMIT raise _INTL("Total EVs are greater than allowed ({1}).\r\n{2}", Pokemon::EV_LIMIT, FileLineData.linereport) end when "Happiness" - if record>255 - raise _INTL("Bad happiness: {1} (must be 0-255).\r\n{2}",record,FileLineData.linereport) - end - when "Name" - if record.length>Pokemon::MAX_NAME_SIZE - raise _INTL("Bad nickname: {1} (must be 1-{2} characters).\r\n{3}", record, Pokemon::MAX_NAME_SIZE, FileLineData.linereport) + if property_value > 255 + raise _INTL("Bad happiness: {1} (must be 0-255).\r\n{2}", property_value, 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 + case property_name + when "Items", "LoseText" + trainer_hash[line_schema[0]] = property_value + trainer_lose_texts[trainer_id] = property_value if property_name == "LoseText" when "Pokemon" - pokemonindex += 1 - trainers[trainerindex][3][pokemonindex] = [] - trainers[trainerindex][3][pokemonindex][TrainerData::SPECIES] = record[0] - trainers[trainerindex][3][pokemonindex][TrainerData::LEVEL] = record[1] + current_pkmn = { + :species => property_value[0], + :level => property_value[1] + } + trainer_hash[line_schema[0]].push(current_pkmn) else - if pokemonindex<0 - raise _INTL("Pokémon hasn't been defined yet!\r\n{1}",FileLineData.linereport) + if !current_pkmn + raise _INTL("Pokémon hasn't been defined yet!\r\n{1}", FileLineData.linereport) end - trainers[trainerindex][3][pokemonindex][schema[0]] = record + current_pkmn[line_schema[0]] = property_value 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",:TrainerType]) - 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, - Item,Item,Item,Item,Item,Item,Item,Item]) - 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",Species,nil,:Item,:Move,:Move,:Move,:Move, - 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 TrainerData::LEVEL - if record[i]>mLevel - raise _INTL("Bad level: {1} (must be 1-{2}).\r\n{3}",record[i],mLevel,FileLineData.linereport) - end - when TrainerData::ABILITY+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 TrainerData::IV+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 TrainerData::EV+3 - if record[i]>Pokemon::EV_STAT_LIMIT - raise _INTL("Bad EV: {1} (must be 0-{2}).\r\n{3}", record[i], Pokemon::EV_STAT_LIMIT, FileLineData.linereport) - end - record[i] = [record[i]] - when TrainerData::HAPPINESS+3 - if record[i]>255 - raise _INTL("Bad happiness: {1} (must be 0-255).\r\n{2}",record[i],FileLineData.linereport) - end - when TrainerData::NAME+3 - if record[i].length>Pokemon::MAX_NAME_SIZE - raise _INTL("Bad nickname: {1} (must be 1-{2} characters).\r\n{3}", record[i], Pokemon::MAX_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>=TrainerData::MOVES && i=TrainerData::MOVES+4) ? i-3 : i - trainers[trainerindex][3][pokemonindex][d] = record[i] - end - end - end - oldcompilerline = 0 if oldcompilerline>=oldcompilerlength + raise _INTL("Expected a new section or a line like XXX=YYY, got:\r\n{1}\r\n{2}", line, FileLineData.linereport) end } - save_data(trainers,"Data/trainers.dat") - MessageTypes.setMessagesAsHash(MessageTypes::TrainerNames,trainernames) - MessageTypes.setMessagesAsHash(MessageTypes::TrainerLoseText,trainerlosetext) + # Add last trainer's data to records + if trainer_hash + key = [trainer_hash[:trainer_type], trainer_hash[:name], trainer_hash[:version]] + GameData::Trainer::DATA[trainer_id] = GameData::Trainer::DATA[key] = GameData::Trainer.new(trainer_hash) + end + # Save all data + GameData::Trainer.save + MessageTypes.setMessagesAsHash(MessageTypes::TrainerNames, trainer_names) + MessageTypes.setMessagesAsHash(MessageTypes::TrainerLoseText, trainer_lose_texts) + Graphics.update end #============================================================================= diff --git a/Data/Scripts/022_Compiler/003_Compiler_WritePBS.rb b/Data/Scripts/022_Compiler/003_Compiler_WritePBS.rb index 810996e1d..53659aab2 100644 --- a/Data/Scripts/022_Compiler/003_Compiler_WritePBS.rb +++ b/Data/Scripts/022_Compiler/003_Compiler_WritePBS.rb @@ -573,96 +573,40 @@ module Compiler # Save individual trainer data to PBS file #=============================================================================== def write_trainers - data = pbLoadTrainersData - return if !data - File.open("PBS/trainers.txt","wb") { |f| + File.open("PBS/trainers.txt", "wb") { |f| add_PBS_header_to_file(f) - for trainer in data - trtypename = trainer[0].to_s - next if !trtypename + GameData::Trainer.each do |trainer| + pbSetWindowText(_INTL("Writing trainer {1}...", trainer.id_number)) + Graphics.update if trainer.id_number % 50 == 0 f.write("\#-------------------------------\r\n") - # Section - trainername = trainer[1] ? trainer[1].gsub(/,/,";") : "???" - if trainer[4]==0 - f.write(sprintf("[%s,%s]\r\n",trtypename,trainername)) + if trainer.version > 0 + f.write(sprintf("[%s,%s,%d]\r\n", trainer.trainer_type, trainer.real_name, trainer.version)) else - f.write(sprintf("[%s,%s,%d]\r\n",trtypename,trainername,trainer[4])) + f.write(sprintf("[%s,%s]\r\n", trainer.trainer_type, trainer.real_name)) end - # Trainer's items - if trainer[2] && trainer[2].length>0 - itemstring = "" - for i in 0...trainer[2].length - itemstring.concat(",") if i > 0 - itemstring.concat(trainer[2][i].to_s) - end - f.write(sprintf("Items = %s\r\n",itemstring)) if itemstring!="" + f.write(sprintf("Items = %s\r\n", trainer.items.join(","))) if trainer.items.length > 0 + if trainer.real_lose_text && !trainer.real_lose_text.empty? + f.write(sprintf("LoseText = %s\r\n", csvQuoteAlways(trainer.real_lose_text))) end - # Lose texts - if trainer[5] && trainer[5]!="" - f.write(sprintf("LoseText = %s\r\n",csvQuoteAlways(trainer[5]))) - end - # Pokémon - for poke in trainer[3] - f.write(sprintf("Pokemon = %s,%d\r\n",poke[TrainerData::SPECIES],poke[TrainerData::LEVEL])) - if poke[TrainerData::NAME] && poke[TrainerData::NAME]!="" - f.write(sprintf(" Name = %s\r\n",poke[TrainerData::NAME])) + trainer.pokemon.each do |pkmn| + f.write(sprintf("Pokemon = %s,%d\r\n", pkmn[:species], pkmn[:level])) + f.write(sprintf(" Name = %s\r\n", pkmn[:name])) if pkmn[:name] && !pkmn[:name].empty? + f.write(sprintf(" Form = %d\r\n", pkmn[:form])) if pkmn[:form] && pkmn[:form] > 0 + f.write(sprintf(" Gender = %s\r\n", (pkmn[:gender] == 1) ? "female" : "male")) if pkmn[:gender] + f.write(" Shiny = yes\r\n") if pkmn[:shininess] + f.write(" Shadow = yes\r\n") if pkmn[:shadowness] + f.write(sprintf(" Moves = %s\r\n", pkmn[:moves].join(","))) if pkmn[:moves] && pkmn[:moves].length > 0 + f.write(sprintf(" Ability = %d\r\n", pkmn[:ability_flag])) if pkmn[:ability_flag] + f.write(sprintf(" Item = %s\r\n", pkmn[:item])) if pkmn[:item] + f.write(sprintf(" Nature = %s\r\n", getConstantName(PBNatures, pkmn[:nature]))) if pkmn[:nature] + if pkmn[:iv] && pkmn[:iv].length > 0 + f.write(sprintf(" IV = %s\r\n", (pkmn[:iv].uniq.length == 1) ? pkmn[:iv][0] : pkmn[:iv].join(","))) end - if poke[TrainerData::FORM] - f.write(sprintf(" Form = %d\r\n",poke[TrainerData::FORM])) - end - if poke[TrainerData::GENDER] - f.write(sprintf(" Gender = %s\r\n",(poke[TrainerData::GENDER]==1) ? "female" : "male")) - end - if poke[TrainerData::SHINY] - f.write(" Shiny = yes\r\n") - end - if poke[TrainerData::SHADOW] - f.write(" Shadow = yes\r\n") - end - if poke[TrainerData::MOVES] && poke[TrainerData::MOVES].length>0 - movestring = "" - for i in 0...poke[TrainerData::MOVES].length - movename = GameData::Move.get(poke[TrainerData::MOVES][i]).id.to_s - next if !movename - movestring.concat(",") if i>0 - movestring.concat(movename) - end - f.write(sprintf(" Moves = %s\r\n",movestring)) if movestring!="" - end - if poke[TrainerData::ABILITY] - f.write(sprintf(" Ability = %s\r\n",poke[TrainerData::ABILITY].to_s)) - end - if poke[TrainerData::ITEM] - f.write(sprintf(" Item = %s\r\n",poke[TrainerData::ITEM].to_s)) - end - if poke[TrainerData::NATURE] - nature = getConstantName(PBNatures,poke[TrainerData::NATURE]) rescue nil - f.write(sprintf(" Nature = %s\r\n",nature)) if nature - end - if poke[TrainerData::IV] && poke[TrainerData::IV].length>0 - f.write(sprintf(" IV = %d",poke[TrainerData::IV][0])) - if poke[TrainerData::IV].length>1 - for i in 1...6 - f.write(sprintf(",%d",(i0 - f.write(sprintf(" EV = %d",poke[TrainerData::EV][0])) - if poke[TrainerData::EV].length>1 - for i in 1...6 - f.write(sprintf(",%d",(i 0 + f.write(sprintf(" EV = %s\r\n", (pkmn[:ev].uniq.length == 1) ? pkmn[:ev][0] : pkmn[:ev].join(","))) end + f.write(sprintf(" Happiness = %d\r\n", pkmn[:happiness])) if pkmn[:happiness] + f.write(sprintf(" Ball = %d\r\n", pkmn[:poke_ball])) if pkmn[:poke_ball] end end } diff --git a/Data/Scripts/022_Compiler/004_Compiler_MapsAndEvents.rb b/Data/Scripts/022_Compiler/004_Compiler_MapsAndEvents.rb index f80967e7d..9cef385bd 100644 --- a/Data/Scripts/022_Compiler/004_Compiler_MapsAndEvents.rb +++ b/Data/Scripts/022_Compiler/004_Compiler_MapsAndEvents.rb @@ -384,7 +384,6 @@ module Compiler #============================================================================= class TrainerChecker def initialize - @trainers = nil @dontaskagain = false end @@ -396,26 +395,20 @@ module Compiler end end - def pbTrainerBattleCheck(tr_type, tr_name, tr_id) + def pbTrainerBattleCheck(tr_type, tr_name, tr_version) return if !$DEBUG || @dontaskagain # Check for existence of trainer type pbTrainerTypeCheck(tr_type) return if !GameData::TrainerType.exists?(tr_type) tr_type = GameData::TrainerType.get(tr_type).id # Check for existence of trainer - @trainers = load_data("Data/trainers.dat") if !@trainers - if @trainers - for trainer in @trainers - return if trainer[0]==tr_type && trainer[1]==tr_name && trainer[4]==tr_id - end - end + return if GameData::Trainer.exists?(tr_type, tr_name, tr_version) # Add new trainer - cmd = pbMissingTrainer(tr_type,tr_name,tr_id) - if cmd==2 + cmd = pbMissingTrainer(tr_type, tr_name, tr_version) + if cmd == 2 @dontaskagain = true Graphics.update end - @trainers = nil end end