Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require 'active_support/all'
- class Object
- def not_nil!
- self
- end
- end
- class NilClass
- def not_nil!
- raise "Called #not_nil! on nil"
- end
- end
- def parse_supplementary_file(file)
- File.read(file).split(/\n/).map { _1.split(/,/)[1..2] }.to_h
- end
- ABILITIES = parse_supplementary_file('abilities.pbs')
- MOVES = parse_supplementary_file('moves.pbs')
- ITEMS = parse_supplementary_file('items.pbs')
- SHAPES = {
- 1 => 'Head',
- 7 => 'HeadLegs',
- 3 => 'Fins',
- 14 => 'Insectoid',
- 8 => 'Quadruped',
- 13 => 'MultiWings',
- 11 => 'MultiBody',
- 10 => 'Tentacles',
- 5 => 'HeadBase',
- 6 => 'BipedalTail',
- 12 => 'BipedalNoTail',
- 9 => 'SingleWings',
- 2 => 'Serpentine',
- 4 => 'HeadArms',
- 0 => 'Varies',
- }
- RATIOS = {
- 'Female50Percent' => { female: 0.5, male: 0.5 },
- 'Female25Percent' => { female: 0.25, male: 0.75 },
- 'FemaleOneEighth' => { female: 0.125, male: 0.875 },
- 'Genderless' => { genderless: 1 },
- 'Female75Percent' => { female: 0.75, male: 0.25 },
- 'AlwaysFemale' => { female: 1 },
- 'AlwaysMale' => { male: 1 },
- }
- def id2gen(id)
- case id
- when 1..151
- 1
- when 152..251
- 2
- when 252..386
- 3
- when 387..493
- 4
- when 494..649
- 5
- when 650..721
- 6
- when 722..809
- 7
- when 810..893
- 8
- end
- end
- def initial_hash(line)
- value = line.gsub(/\[|\]/, '')
- if value.match?(/^\d+$/)
- num = value.to_i
- { 'number' => num, 'generation' => id2gen(num) }
- else
- { 'baseForm' => value.sub(/\-\d+$/, '').downcase }
- end
- end
- BASE_STATS = %w[health attack defense speed specialAttack specialDefense]
- def to_stats_hash(str)
- BASE_STATS.zip(str.split(/,/).map(&:to_i)).to_h
- end
- def to_learnset(str)
- str.split(/,/).in_groups_of(2).inject([]) do |moves, (level_str, move_id)|
- level = level_str.to_i
- move = MOVES.fetch(move_id)
- if moves.last && moves.last[0] == level
- moves[0...-1] + [[moves.last[0], Array(moves.last[1]) + [move]]]
- else
- moves + [[level, move]]
- end
- end.to_h
- end
- EVO_METHODS = {
- Level: -> value {
- { type: 'level', level: value.to_i }
- },
- Item: -> value {
- { type: 'item', item: ITEMS.fetch(value) }
- },
- Happiness: -> {
- { type: 'happiness' }
- },
- TradeItem: -> value {
- { type: 'tradeItem', item: ITEMS.fetch(value) }
- },
- Trade: -> {
- { type: 'trade' }
- },
- HasMove: -> value {
- { type: 'knowsMove', move: MOVES.fetch(value) }
- },
- HappinessMoveType: -> value {
- { type: 'knowsMoveTypeWhileHappy', moveType: value.capitalize }
- },
- HappinessDay: -> {
- { type: 'happinessAtDay' }
- },
- HappinessNight: -> {
- { type: 'happinessAtNight' }
- },
- DayHoldItem: -> value {
- { type: 'holdingItemAtDay', item: ITEMS.fetch(value) }
- },
- NightHoldItem: -> value {
- { type: 'holdingItemAtNight', item: ITEMS.fetch(value) }
- },
- AttackGreater: -> value {
- { type: 'attackGreaterAtLevel', level: value.to_i }
- },
- DefenseGreater: -> value {
- { type: 'defenseGreaterAtLevel', level: value.to_i }
- },
- AtkDefEqual: -> value {
- { type: 'attackDefenseEqualAtLevel', level: value.to_i }
- },
- Silcoon: -> value {
- { type: 'silcoonPersonalityAtLevel', level: value.to_i }
- },
- Cascoon: -> value {
- { type: 'cascoonPersonalityAtLevel', level: value.to_i }
- },
- ItemMale: -> value {
- { type: 'itemWhenMale', item: ITEMS.fetch(value) }
- },
- ItemFemale: -> value {
- { type: 'itemWhenFemale', item: ITEMS.fetch(value) }
- },
- Ninjask: -> value {
- { type: 'ninjask', level: value.to_i }
- },
- Shedinja: -> value {
- { type: 'shedinja', level: value.to_i }
- },
- Location: -> value {
- { type: 'specialLocationAtLevel', level: value.to_i }
- },
- TookDamage: -> value {
- # pbs file says 2, not sure if it's wrong or is represented differently
- { type: 'specialLocationTookDamage', damage: 49 }
- },
- LandCritical: -> value {
- { type: 'landedCriticalHit' }
- },
- Beauty: -> value {
- { type: 'beauty', beauty: value.to_i }
- },
- LevelFemale: -> value {
- { type: 'levelWhenFemale', level: value.to_i }
- },
- LevelMale: -> value {
- { type: 'levelWhenMale', level: value.to_i }
- },
- HasInParty: -> value {
- { type: 'hasInParty', pokemon: value.downcase }
- },
- TradeSpecies: -> value {
- { type: 'tradeFor', pokemon: value.downcase }
- },
- LevelDarkInParty: -> value {
- { type: 'darkInPartyWhileAtLevel', level: value.to_i }
- },
- LevelDay: -> value {
- { type: 'levelAtDay', level: value.to_i }
- },
- LevelNight: -> value {
- { type: 'levelAtNight', level: value.to_i }
- },
- LevelRain: -> value {
- { type: 'levelInRain', level: value.to_i }
- },
- PotItem: -> {
- { type: 'potItem' }
- },
- HoldSweetItem: -> {
- { type: 'holdingSweetItem' }
- },
- }.with_indifferent_access
- def to_evos(str)
- tokens = str.split(/,/).reject(&:empty?)
- i = 0
- output = []
- current_mon = nil
- while i < tokens.size
- token = tokens[i]
- if current_mon.nil?
- current_mon = token.downcase
- i += 1
- else
- callback = EVO_METHODS.fetch(token)
- result =
- if callback.arity == 1
- value = tokens[i + 1]
- i += 2
- callback.call(value)
- else
- i += 1
- callback.call
- end
- output << [current_mon, result]
- current_mon = nil
- end
- end
- output
- end
- IGNORED_KEYS = %w[
- regionalNumbers
- battlerPlayerY battlerEnemyY battlerAltitude
- wildItemUncommon wildItemCommon wildItemRare
- incense megaStone
- ]
- def parse_main_file(file)
- mons = []
- File.open(file, 'r:UTF-8').readlines.each do |line|
- line.strip!
- next if line.match?(/#/)
- next mons.push(initial_hash(line)) if line.match?(/^\[/)
- mon = mons.last
- key, value = line.split('=')
- next unless value # empty field
- key = key.strip.camelize(:lower)
- value = value.strip
- case key
- when 'internalName'
- mon['slug'] = value.downcase
- when 'type1'
- mon['types'] = [value.capitalize]
- when 'type2'
- mon['types'] << value.capitalize
- when 'baseStats'
- mon['baseStats'] = to_stats_hash(value)
- when 'genderRate'
- mon['genderRatio'] = RATIOS.fetch(value)
- when 'shape'
- mon['shape'] = SHAPES.fetch(value.to_i)
- when 'baseEXP'
- mon['baseExp'] = value.to_i
- when 'effortPoints'
- mon['evYield'] = to_stats_hash(value)
- when 'rareness'
- mon['catchRate'] = value.to_i
- when 'happiness'
- mon['happiness'] = value.to_i
- when 'height', 'weight'
- mon[key] = value.to_f
- when 'compatibility'
- mon['eggGroups'] = value.split(/,/)
- when 'pokedex'
- mon['dexEntry'] = value
- when 'stepsToHatch'
- mon['hatchSteps'] = value.to_i
- when 'hiddenAbility'
- # greninja has a second HA listed in this file for some reason
- # i'm hardcoding it because i want any future mons that also have
- # that to raise until i've explicitly double checked them
- if mon['number'] == 658
- mon['hiddenAbility'] = ABILITIES.fetch(value.split(/,/).first)
- else
- mon['hiddenAbility'] = ABILITIES.fetch(value)
- end
- when 'abilities'
- mon['abilities'] = value.split(/,/).collect { ABILITIES.fetch(_1) }
- when 'eggMoves'
- mon['eggMoves'] = value.split(/,/).collect { MOVES.fetch(_1) }
- when 'moves'
- mon['moves'] = to_learnset(value)
- when 'evolutions'
- mon['evolutions'] = to_evos(value)
- when *IGNORED_KEYS
- # ignore
- else
- mon[key] = value
- end
- end
- mons
- end
- ALTFORM_HANDLERS = {
- _mega: -> mon {
- # for some reason this is missing
- mon['formName'] += ' Y' if mon['formName'] == 'Mega Charizard'
- mon['slug'] +=
- case mon['formName']
- when / Y$/
- '-mega-y'
- when / X$/
- '-mega-x'
- else
- '-mega'
- end
- mon['formName'].sub!(/\b#{mon['name']}\b/, '').strip!
- mon['formName'].sub!(/\s+/, ' ')
- },
- _alola: -> mon {
- mon['slug'] += '-alola'
- mon['formName'].delete_suffix!(" #{mon['name']}")
- },
- _galar: -> mon {
- if mon['formName'] =~ /Zen Mode/
- mon['slug'] += '-galarzen'
- else
- mon['slug'] += '-galar'
- end
- mon['formName'].delete_suffix!(" #{mon['name']}")
- },
- deoxys: -> mon {
- mon['slug'] = "Deoxys #{mon['formName'].delete_suffix(' Forme')}".parameterize
- },
- unown: -> mon {
- mon['name'] = 'Unown'
- mon['formName'] = mon['formName'][0]
- case mon['formName']
- when '!'
- mon['slug'] = 'unown-exclamation'
- when '?'
- mon['slug'] = 'unown-question'
- else
- mon['slug'] = "Unown #{mon['formName']}".parameterize
- end
- },
- pichu: -> mon {
- mon['formName'] = 'Spiky-Eared'
- mon['slug'] = 'pichu-spikyeared'
- },
- castform: -> mon {
- mon['formName'].delete_suffix!(' Form')
- mon['slug'] = "Castform #{mon['formName']}".parameterize
- },
- kyogre: -> mon {
- mon['formName'] = 'Primal'
- mon['slug'] = 'kyogre-primal'
- },
- groudon: -> mon {
- mon['formName'] = 'Primal'
- mon['slug'] = 'groudon-primal'
- },
- burmy: -> mon {
- mon['formName'].delete_suffix!(' Cloak')
- mon['slug'] = "Burmy #{mon['formName']}".parameterize
- },
- wormadam: -> mon {
- mon['formName'].delete_suffix!(' Cloak')
- mon['slug'] = "Wormadam #{mon['formName']}".parameterize
- },
- cherrim: -> mon {
- mon['formName'] = 'Sunshine'
- mon['slug'] = 'cherrim-sunshine'
- },
- shellos: -> mon {
- mon['formName'] = 'East Sea'
- mon['slug'] = 'shellos-east'
- },
- gastrodon: -> mon {
- mon['formName'] = 'East Sea'
- mon['slug'] = 'gastrodon-east'
- },
- rotom: -> mon {
- mon['formName'].delete_suffix!(' Rotom')
- mon['slug'] = "Rotom #{mon['formName']}".parameterize
- },
- giratina: -> mon {
- mon['slug'] = 'giratina-origin'
- },
- shaymin: -> mon {
- mon['slug'] = 'shaymin-sky'
- },
- arceus: -> mon {
- mon['formName'].delete_suffix!(' Type')
- mon['slug'] = "Arceus #{mon['formName']}".parameterize
- },
- basculin: -> mon {
- mon['slug'] = 'basculin-bluestriped'
- },
- darmanitan: -> mon {
- # galar form has already been parsed, doesnt hit this func
- mon['slug'] = 'darmanitan-zen'
- },
- deerling: -> mon {
- mon['formName'].delete_suffix!(' Form')
- mon['slug'] = "Deerling #{mon['formName']}".parameterize
- },
- sawsbuck: -> mon {
- mon['formName'].delete_suffix!(' Form')
- mon['slug'] = "Sawsbuck #{mon['formName']}".parameterize
- },
- tornadus: -> mon {
- mon['slug'] = 'tornadus-therian'
- },
- thundurus: -> mon {
- mon['slug'] = 'thundurus-therian'
- },
- landorus: -> mon {
- mon['slug'] = 'landorus-therian'
- },
- kyurem: -> mon {
- mon['formName'].delete_suffix!(' Kyurem')
- mon['slug'] = "Kyurem #{mon['formName']}".parameterize
- },
- keldeo: -> mon {
- mon['slug'] = 'keldeo-resolute'
- },
- meloetta: -> mon {
- mon['slug'] = 'meloetta-pirouette'
- },
- genesect: -> mon {
- mon['slug'] = "Genesect #{mon['formName'].delete_suffix(' Drive')}".parameterize
- },
- greninja: -> mon {
- mon['slug'] = 'greninja-ash'
- },
- vivillon: -> mon {
- mon['formName'].delete_suffix!(' Pattern')
- mon['slug'] = "Vivillon #{mon['formName'].sub(' ', '')}".parameterize
- },
- flabebe: -> mon {
- mon['formName'].delete_suffix!(' Flower')
- mon['slug'] = "Flabebe #{mon['formName']}".parameterize
- },
- floette: -> mon {
- mon['formName'].delete_suffix!(' Flower')
- mon['slug'] = "Floette #{mon['formName']}".parameterize
- },
- florges: -> mon {
- mon['formName'].delete_suffix!(' Flower')
- mon['slug'] = "Florges #{mon['formName']}".parameterize
- },
- furfrou: -> mon {
- mon['formName'].delete_suffix!(' Trim')
- mon['slug'] = "Furfrou #{mon['formName']}".parameterize
- },
- meowstic: -> mon {
- mon['slug'] = 'meowstic-female'
- },
- aegislash: -> mon {
- mon['slug'] = 'aegislash-blade'
- },
- pumpkaboo: -> mon {
- mon['formName'].delete_suffix!(' Size')
- mon['slug'] = "Pumpkaboo #{mon['formName']}".parameterize
- },
- gourgeist: -> mon {
- mon['formName'].delete_suffix!(' Size')
- mon['slug'] = "Gourgeist #{mon['formName']}".parameterize
- },
- zygarde: -> mon {
- if mon['formName'] =~ /Complete/
- mon['slug'] = 'zygarde-complete'
- else
- mon['slug'] = 'zygarde-10'
- end
- },
- hoopa: -> mon {
- mon['slug'] = 'hoopa-unbound'
- },
- oricorio: -> mon {
- mon['formName'].delete_suffix!(' Style')
- mon['slug'] = "Oricorio #{mon['formName'].sub(/[\-\']/, '')}".parameterize
- },
- lycanroc: -> mon {
- mon['formName'].delete_suffix!(' Form')
- mon['slug'] = "Lycanroc #{mon['formName']}".parameterize
- },
- wishiwashi: -> mon {
- mon['formName'].delete_suffix!(' Form')
- mon['slug'] = "Wishiwashi #{mon['formName']}".parameterize
- },
- silvally: -> mon {
- mon['formName'].delete_suffix!(' Type')
- mon['slug'] = "Silvally #{mon['formName']}".parameterize
- },
- minior: -> mon {
- mon['formName'] = 'Indigo Core' if mon['formName'] == 'Gray Core'
- mon['formName'].delete_suffix!(' Core')
- mon['slug'] = "Minior #{mon['formName']}".parameterize
- },
- mimikyu: -> mon {
- mon['formName'].delete_suffix!(' Form')
- mon['slug'] = "Mimikyu #{mon['formName']}".parameterize
- },
- necrozma: -> mon {
- mon['formName'].delete_suffix!(' Necrozma')
- mon['slug'] = "Necrozma #{mon['formName'].tr(' ', '')}".parameterize
- },
- cramorant: -> mon {
- mon['formName'].delete_suffix!(' Form')
- mon['slug'] = "Cramorant #{mon['formName']}".parameterize
- },
- toxtricity: -> mon {
- mon['formName'].delete_suffix!(' Form')
- mon['slug'] = "Toxtricity #{mon['formName'].tr(' ', '')}".parameterize
- },
- sinistea: -> mon {
- mon['formName'] = 'Antique'
- mon['slug'] = 'sinistea-antique'
- },
- polteageist: -> mon {
- mon['formName'] = 'Antique'
- mon['slug'] = 'polteageist-antique'
- },
- alcremie: -> mon {
- if mon['formName'] =~ /Strawberry/ # base case
- mon['slug'] = "Alcremie #{mon['formName'].delete_prefix('Strawberry').tr(' ', '')}".parameterize
- else
- # put the item name at the end for files
- item, *flavor = mon['formName'].split(/\s+/)
- mon['slug'] = "Alcremie #{flavor.join(' ')} #{item}".parameterize
- end
- },
- eiscue: -> mon {
- mon['slug'] = 'eiscue-noice'
- },
- indeedee: -> mon {
- mon['slug'] = 'indeedee-female'
- },
- morpeko: -> mon {
- mon['formName'] = 'Hangry'
- mon['slug'] = 'morpeko-hangry'
- },
- zacian: -> mon {
- mon['slug'] = 'zacian-crowned'
- },
- zamazenta: -> mon {
- mon['slug'] = 'zamazenta-crowned'
- },
- urshifu: -> mon {
- # this will need to change once you get gmax
- mon['slug'] = 'urshifu-rapidstrike'
- },
- }.with_indifferent_access
- $pumpkin_base_form_cache = {}
- mons = parse_main_file('input.pbs') + parse_main_file('altforms.pbs')
- # one of the miniors is missing, add it
- mons.push(
- mons.detect { _1['formName'] == 'Red Core' }
- .dup
- .tap { _1['formName'] = 'Orange Core' }
- )
- mons = mons.map { |mon|
- # fix nidoran inconsistencies
- mon['slug'] = 'nidoran-female' if mon['slug'] == 'nidoranfe'
- mon['slug'] = 'nidoran' if mon['slug'] == 'nidoranma'
- next mon unless mon['baseForm']
- # some mons have "forms" just for the purposes of giving them
- # additional data in essentials code, which we don't care about,
- # so we skip them entirely
- next if mon.keys == ['baseForm']
- base_mon = mons.detect { _1['slug'] == mon['baseForm'] }.not_nil!
- mon.reverse_merge!(base_mon)
- ALTFORM_HANDLERS[:_mega].call(mon) if mon['formName'] =~ /^Mega /
- ALTFORM_HANDLERS[:_galar].call(mon) if mon['formName'] =~ /^Galarian /
- ALTFORM_HANDLERS[:_alola].call(mon) if mon['formName'] =~ /^Alolan /
- ALTFORM_HANDLERS[mon['slug']].call(mon) if ALTFORM_HANDLERS[mon['slug']]
- mon
- }.compact
- mons = mons.map { |mon| mon.sort_by { |key| key }.to_h }
- mons = mons.sort_by { |mon| [mon['number'], mon['name'].size] }
- # slugs = mons.collect { _1['slug'] }
- # dupes = slugs.select { slugs.count(_1) > 1 }
- # puts "#{dupes.size} unresolved conflicts"
- # p dupes
- File.write('./output.json', JSON.pretty_generate(mons))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement