1. module GameData
  2. class Species
  3. attr_reader :id
  4. attr_reader :species
  5. attr_reader :form
  6. attr_reader :real_name
  7. attr_reader :real_form_name
  8. attr_reader :real_category
  9. attr_reader :real_pokedex_entry
  10. attr_reader :pokedex_form
  11. attr_reader :types
  12. attr_reader :base_stats
  13. attr_reader :evs
  14. attr_reader :base_exp
  15. attr_reader :growth_rate
  16. attr_reader :gender_ratio
  17. attr_reader :catch_rate
  18. attr_reader :happiness
  19. attr_reader :moves
  20. attr_reader :tutor_moves
  21. attr_reader :egg_moves
  22. attr_reader :abilities
  23. attr_reader :hidden_abilities
  24. attr_reader :wild_item_common
  25. attr_reader :wild_item_uncommon
  26. attr_reader :wild_item_rare
  27. attr_reader :egg_groups
  28. attr_reader :hatch_steps
  29. attr_reader :incense
  30. attr_reader :offspring
  31. attr_reader :evolutions
  32. attr_reader :height
  33. attr_reader :weight
  34. attr_reader :color
  35. attr_reader :shape
  36. attr_reader :habitat
  37. attr_reader :generation
  38. attr_reader :flags
  39. attr_reader :mega_stone
  40. attr_reader :mega_move
  41. attr_reader :unmega_form
  42. attr_reader :mega_message
  43. attr_reader :pbs_file_suffix
  44.  
  45. DATA = {}
  46. DATA_FILENAME = "species.dat"
  47. PBS_BASE_FILENAME = ["pokemon", "pokemon_forms"]
  48.  
  49. extend ClassMethodsSymbols
  50. include InstanceMethods
  51.  
  52. def self.schema(compiling_forms = false)
  53. ret = {}
  54. if compiling_forms
  55. ret["SectionName"] = [:id, "ev", :Species]
  56. else
  57. ret["SectionName"] = [:id, "m"]
  58. ret["Name"] = [:real_name, "s"]
  59. end
  60. ret["FormName"] = [:real_form_name, "q"]
  61. if compiling_forms
  62. ret["PokedexForm"] = [:pokedex_form, "u"]
  63. ret["MegaStone"] = [:mega_stone, "e", :Item]
  64. ret["MegaMove"] = [:mega_move, "e", :Move]
  65. ret["UnmegaForm"] = [:unmega_form, "u"]
  66. ret["MegaMessage"] = [:mega_message, "u"]
  67. end
  68. ret["Types"] = [:types, "*e", :Type]
  69. ret["BaseStats"] = [:base_stats, "vvvvvv"]
  70. if !compiling_forms
  71. ret["GenderRatio"] = [:gender_ratio, "e", :GenderRatio]
  72. ret["GrowthRate"] = [:growth_rate, "e", :GrowthRate]
  73. end
  74. ret["BaseExp"] = [:base_exp, "v"]
  75. ret["EVs"] = [:evs, "*ev", :Stat]
  76. ret["CatchRate"] = [:catch_rate, "u"]
  77. ret["Happiness"] = [:happiness, "u"]
  78. ret["Abilities"] = [:abilities, "*e", :Ability]
  79. ret["HiddenAbilities"] = [:hidden_abilities, "*e", :Ability]
  80. ret["Moves"] = [:moves, "*ue", nil, :Move]
  81. ret["TutorMoves"] = [:tutor_moves, "*e", :Move]
  82. ret["EggMoves"] = [:egg_moves, "*e", :Move]
  83. ret["EggGroups"] = [:egg_groups, "*e", :EggGroup]
  84. ret["HatchSteps"] = [:hatch_steps, "v"]
  85. if compiling_forms
  86. ret["Offspring"] = [:offspring, "*e", :Species]
  87. else
  88. ret["Incense"] = [:incense, "e", :Item]
  89. ret["Offspring"] = [:offspring, "*s"]
  90. end
  91. ret["Height"] = [:height, "f"]
  92. ret["Weight"] = [:weight, "f"]
  93. ret["Color"] = [:color, "e", :BodyColor]
  94. ret["Shape"] = [:shape, "e", :BodyShape]
  95. ret["Habitat"] = [:habitat, "e", :Habitat]
  96. ret["Category"] = [:real_category, "s"]
  97. ret["Pokedex"] = [:real_pokedex_entry, "q"]
  98. ret["Generation"] = [:generation, "i"]
  99. ret["Flags"] = [:flags, "*s"]
  100. ret["WildItemCommon"] = [:wild_item_common, "*e", :Item]
  101. ret["WildItemUncommon"] = [:wild_item_uncommon, "*e", :Item]
  102. ret["WildItemRare"] = [:wild_item_rare, "*e", :Item]
  103. if compiling_forms
  104. ret["Evolutions"] = [:evolutions, "*ees", :Species, :Evolution, nil]
  105. else
  106. ret["Evolutions"] = [:evolutions, "*ses", nil, :Evolution, nil]
  107. end
  108. return ret
  109. end
  110.  
  111. def self.editor_properties
  112. return [
  113. ["ID", ReadOnlyProperty, _INTL("The ID of the Pokémon.")],
  114. ["Name", LimitStringProperty.new(Pokemon::MAX_NAME_SIZE), _INTL("Name of the Pokémon.")],
  115. ["FormName", StringProperty, _INTL("Name of this form of the Pokémon.")],
  116. ["Types", GameDataPoolProperty.new(:Type, false), _INTL("The Pokémon's type(s).")],
  117. ["BaseStats", BaseStatsProperty, _INTL("Base stats of the Pokémon.")],
  118. ["GenderRatio", GameDataProperty.new(:GenderRatio), _INTL("Proportion of males to females for this species.")],
  119. ["GrowthRate", GameDataProperty.new(:GrowthRate), _INTL("Pokémon's growth rate.")],
  120. ["BaseExp", LimitProperty.new(9999), _INTL("Base experience earned when this species is defeated.")],
  121. ["EVs", EffortValuesProperty, _INTL("Effort Value points earned when this species is defeated.")],
  122. ["CatchRate", LimitProperty.new(255), _INTL("Catch rate of this species (0-255).")],
  123. ["Happiness", LimitProperty.new(255), _INTL("Base happiness of this species (0-255).")],
  124. ["Abilities", AbilitiesProperty.new, _INTL("Abilities which the Pokémon can have (max. 2).")],
  125. ["HiddenAbilities", AbilitiesProperty.new, _INTL("Secret abilities which the Pokémon can have.")],
  126. ["Moves", LevelUpMovesProperty, _INTL("Moves which the Pokémon learns while levelling up.")],
  127. ["TutorMoves", EggMovesProperty.new, _INTL("Moves which the Pokémon can be taught by TM/HM/Move Tutor.")],
  128. ["EggMoves", EggMovesProperty.new, _INTL("Moves which the Pokémon can learn via breeding.")],
  129. ["EggGroups", EggGroupsProperty.new, _INTL("Egg groups that the Pokémon belongs to for breeding purposes.")],
  130. ["HatchSteps", LimitProperty.new(99_999), _INTL("Number of steps until an egg of this species hatches.")],
  131. ["Incense", ItemProperty, _INTL("Item needed to be held by a parent to produce an egg of this species.")],
  132. ["Offspring", GameDataPoolProperty.new(:Species), _INTL("All possible species that an egg can be when breeding for an egg of this species (if blank, the egg can only be this species).")],
  133. ["Height", NonzeroLimitProperty.new(999), _INTL("Height of the Pokémon in 0.1 metres (e.g. 42 = 4.2m).")],
  134. ["Weight", NonzeroLimitProperty.new(9999), _INTL("Weight of the Pokémon in 0.1 kilograms (e.g. 42 = 4.2kg).")],
  135. ["Color", GameDataProperty.new(:BodyColor), _INTL("Pokémon's body color.")],
  136. ["Shape", GameDataProperty.new(:BodyShape), _INTL("Body shape of this species.")],
  137. ["Habitat", GameDataProperty.new(:Habitat), _INTL("The habitat of this species.")],
  138. ["Category", StringProperty, _INTL("Kind of Pokémon species.")],
  139. ["Pokedex", StringProperty, _INTL("Description of the Pokémon as displayed in the Pokédex.")],
  140. ["Generation", LimitProperty.new(99_999), _INTL("The number of the generation the Pokémon debuted in.")],
  141. ["Flags", StringListProperty, _INTL("Words/phrases that distinguish this species from others.")],
  142. ["WildItemCommon", GameDataPoolProperty.new(:Item), _INTL("Item(s) commonly held by wild Pokémon of this species.")],
  143. ["WildItemUncommon", GameDataPoolProperty.new(:Item), _INTL("Item(s) uncommonly held by wild Pokémon of this species.")],
  144. ["WildItemRare", GameDataPoolProperty.new(:Item), _INTL("Item(s) rarely held by wild Pokémon of this species.")],
  145. ["Evolutions", EvolutionsProperty.new, _INTL("Evolution paths of this species.")]
  146. ]
  147. end
  148.  
  149. # @param species [Symbol, self, String]
  150. # @param form [Integer]
  151. # @return [self, nil]
  152. def self.get_species_form(species, form)
  153. return nil if !species || !form
  154. validate species => [Symbol, self, String]
  155. validate form => Integer
  156. species = species.species if species.is_a?(self)
  157. species = species.to_sym if species.is_a?(String)
  158. trial = sprintf("%s_%d", species, form).to_sym
  159. species_form = (DATA[trial].nil?) ? species : trial
  160. return (DATA.has_key?(species_form)) ? DATA[species_form] : nil
  161. end
  162.  
  163. def self.each_species
  164. DATA.each_value { |species| yield species if species.form == 0 }
  165. end
  166.  
  167. def self.species_count
  168. ret = 0
  169. self.each_species { |species| ret += 1 }
  170. return ret
  171. end
  172.  
  173. def initialize(hash)
  174. @id = hash[:id]
  175. @species = hash[:species] || @id
  176. @form = hash[:form] || 0
  177. @real_name = hash[:real_name] || "Unnamed"
  178. @real_form_name = hash[:real_form_name]
  179. @real_category = hash[:real_category] || "???"
  180. @real_pokedex_entry = hash[:real_pokedex_entry] || "???"
  181. @pokedex_form = hash[:pokedex_form] || @form
  182. @types = hash[:types] || [:NORMAL]
  183. @base_stats = hash[:base_stats] || {}
  184. @evs = hash[:evs] || {}
  185. GameData::Stat.each_main do |s|
  186. @base_stats[s.id] = 1 if !@base_stats[s.id] || @base_stats[s.id] <= 0
  187. @evs[s.id] = 0 if !@evs[s.id] || @evs[s.id] < 0
  188. end
  189. @base_exp = hash[:base_exp] || 100
  190. @growth_rate = hash[:growth_rate] || :Medium
  191. @gender_ratio = hash[:gender_ratio] || :Female50Percent
  192. @catch_rate = hash[:catch_rate] || 255
  193. @happiness = hash[:happiness] || 70
  194. @moves = hash[:moves] || []
  195. @tutor_moves = hash[:tutor_moves] || []
  196. @egg_moves = hash[:egg_moves] || []
  197. @abilities = hash[:abilities] || []
  198. @hidden_abilities = hash[:hidden_abilities] || []
  199. @wild_item_common = hash[:wild_item_common] || []
  200. @wild_item_uncommon = hash[:wild_item_uncommon] || []
  201. @wild_item_rare = hash[:wild_item_rare] || []
  202. @egg_groups = hash[:egg_groups] || [:Undiscovered]
  203. @hatch_steps = hash[:hatch_steps] || 1
  204. @incense = hash[:incense]
  205. @offspring = hash[:offspring] || []
  206. @evolutions = hash[:evolutions] || []
  207. @height = hash[:height] || 1
  208. @weight = hash[:weight] || 1
  209. @color = hash[:color] || :Red
  210. @shape = hash[:shape] || :Head
  211. @habitat = hash[:habitat] || :None
  212. @generation = hash[:generation] || 0
  213. @flags = hash[:flags] || []
  214. @mega_stone = hash[:mega_stone]
  215. @mega_move = hash[:mega_move]
  216. @unmega_form = hash[:unmega_form] || 0
  217. @mega_message = hash[:mega_message] || 0
  218. @pbs_file_suffix = hash[:pbs_file_suffix] || ""
  219. end
  220.  
  221. # @return [String] the translated name of this species
  222. def name
  223. return pbGetMessageFromHash(MessageTypes::SPECIES_NAMES, @real_name)
  224. end
  225.  
  226. # @return [String] the translated name of this form of this species
  227. def form_name
  228. return pbGetMessageFromHash(MessageTypes::SPECIES_FORM_NAMES, @real_form_name)
  229. end
  230.  
  231. # @return [String] the translated Pokédex category of this species
  232. def category
  233. return pbGetMessageFromHash(MessageTypes::SPECIES_CATEGORIES, @real_category)
  234. end
  235.  
  236. # @return [String] the translated Pokédex entry of this species
  237. def pokedex_entry
  238. return pbGetMessageFromHash(MessageTypes::POKEDEX_ENTRIES, @real_pokedex_entry)
  239. end
  240.  
  241. def default_form
  242. @flags.each do |flag|
  243. return $~[1].to_i if flag[/^DefaultForm_(\d+)$/i]
  244. end
  245. return -1
  246. end
  247.  
  248. def base_form
  249. default = default_form
  250. return (default >= 0) ? default : @form
  251. end
  252.  
  253. def single_gendered?
  254. return GameData::GenderRatio.get(@gender_ratio).single_gendered?
  255. end
  256.  
  257. def base_stat_total
  258. return @base_stats.values.sum
  259. end
  260.  
  261. def has_flag?(flag)
  262. return @flags.any? { |f| f.downcase == flag.downcase }
  263. end
  264.  
  265. def apply_metrics_to_sprite(sprite, index, shadow = false)
  266. metrics_data = GameData::SpeciesMetrics.get_species_form(@species, @form)
  267. metrics_data.apply_metrics_to_sprite(sprite, index, shadow)
  268. end
  269.  
  270. def shows_shadow?
  271. metrics_data = GameData::SpeciesMetrics.get_species_form(@species, @form)
  272. return metrics_data.shows_shadow?
  273. end
  274.  
  275. def get_evolutions(exclude_invalid = false)
  276. ret = []
  277. @evolutions.each do |evo|
  278. next if evo[3] # Is the prevolution
  279. next if evo[1] == :None && exclude_invalid
  280. ret.push([evo[0], evo[1], evo[2]]) # [Species, method, parameter]
  281. end
  282. return ret
  283. end
  284.  
  285. def get_family_evolutions(exclude_invalid = true)
  286. evos = get_evolutions(exclude_invalid)
  287. evos = evos.sort { |a, b| GameData::Species.keys.index(a[0]) <=> GameData::Species.keys.index(b[0]) }
  288. ret = []
  289. evos.each do |evo|
  290. ret.push([@species].concat(evo)) # [Prevo species, evo species, method, parameter]
  291. evo_array = GameData::Species.get(evo[0]).get_family_evolutions(exclude_invalid)
  292. ret.concat(evo_array) if evo_array && evo_array.length > 0
  293. end
  294. return ret
  295. end
  296.  
  297. def get_previous_species
  298. return @species if @evolutions.length == 0
  299. @evolutions.each { |evo| return evo[0] if evo[3] } # Is the prevolution
  300. return @species
  301. end
  302.  
  303. def get_baby_species(check_items = false, item1 = nil, item2 = nil)
  304. ret = @species
  305. return ret if @evolutions.length == 0
  306. @evolutions.each do |evo|
  307. next if !evo[3] # Check only the prevolution
  308. if check_items
  309. incense = GameData::Species.get(evo[0]).incense
  310. ret = evo[0] if !incense || item1 == incense || item2 == incense
  311. else
  312. ret = evo[0] # Species of prevolution
  313. end
  314. break
  315. end
  316. ret = GameData::Species.get(ret).get_baby_species(check_items, item1, item2) if ret != @species
  317. return ret
  318. end
  319.  
  320. # Returns an array of all the species in this species' evolution family.
  321. def get_family_species
  322. sp = get_baby_species
  323. evos = GameData::Species.get(sp).get_family_evolutions(false)
  324. return [sp] if evos.length == 0
  325. return [sp].concat(evos.map { |e| e[1] }).uniq
  326. end
  327.  
  328. # This takes into account whether other_species is evolved.
  329. def breeding_can_produce?(other_species)
  330. other_family = GameData::Species.get(other_species).get_family_species
  331. if @offspring.length > 0
  332. return (other_family & @offspring).length > 0
  333. end
  334. return other_family.include?(@species)
  335. end
  336.  
  337. # If this species doesn't have egg moves, looks at prevolutions one at a
  338. # time and returns theirs instead.
  339. def get_egg_moves
  340. return @egg_moves if !@egg_moves.empty?
  341. prevo = get_previous_species
  342. return GameData::Species.get_species_form(prevo, @form).get_egg_moves if prevo != @species
  343. return @egg_moves
  344. end
  345.  
  346. def family_evolutions_have_method?(check_method, check_param = nil)
  347. sp = get_baby_species
  348. evos = GameData::Species.get(sp).get_family_evolutions
  349. return false if evos.length == 0
  350. evos.each do |evo|
  351. if check_method.is_a?(Array)
  352. next if !check_method.include?(evo[2])
  353. elsif evo[2] != check_method
  354. next
  355. end
  356. return true if check_param.nil? || evo[3] == check_param
  357. end
  358. return false
  359. end
  360.  
  361. # Used by the Moon Ball when checking if a Pokémon's evolution family
  362. # includes an evolution that uses the Moon Stone.
  363. def family_item_evolutions_use_item?(check_item = nil)
  364. sp = get_baby_species
  365. evos = GameData::Species.get(sp).get_family_evolutions
  366. return false if !evos || evos.length == 0
  367. evos.each do |evo|
  368. next if GameData::Evolution.get(evo[2]).use_item_proc.nil?
  369. return true if check_item.nil? || evo[3] == check_item
  370. end
  371. return false
  372. end
  373.  
  374. def minimum_level
  375. return 1 if @evolutions.length == 0
  376. @evolutions.each do |evo|
  377. next if !evo[3] # Check only the prevolution
  378. prevo_data = GameData::Species.get_species_form(evo[0], base_form)
  379. return 1 if !prevo_data.incense.nil?
  380. prevo_min_level = prevo_data.minimum_level
  381. evo_method_data = GameData::Evolution.get(evo[1])
  382. return prevo_min_level if evo_method_data.level_up_proc.nil? && evo_method_data.id != :Shedinja
  383. any_level_up = evo_method_data.any_level_up
  384. return (any_level_up) ? prevo_min_level + 1 : evo[2]
  385. end
  386. return 1
  387. end
  388.  
  389. alias __orig__get_property_for_PBS get_property_for_PBS unless method_defined?(:__orig__get_property_for_PBS)
  390. def get_property_for_PBS(key, writing_form = false)
  391. key = "SectionName" if key == "ID"
  392. ret = nil
  393. if self.class.schema(writing_form).include?(key)
  394. ret = self.send(self.class.schema(writing_form)[key][0])
  395. ret = nil if ret == false || (ret.is_a?(Array) && ret.length == 0)
  396. end
  397. case key
  398. when "SectionName"
  399. ret = [@species, @form] if writing_form
  400. when "FormName"
  401. ret = nil if nil_or_empty?(ret)
  402. when "PokedexForm"
  403. ret = nil if ret == @form
  404. when "UnmegaForm", "MegaMessage", "Generation"
  405. ret = nil if ret == 0
  406. when "BaseStats"
  407. new_ret = []
  408. GameData::Stat.each_main do |s|
  409. new_ret[s.pbs_order] = ret[s.id] if s.pbs_order >= 0
  410. end
  411. ret = new_ret
  412. when "EVs"
  413. new_ret = []
  414. GameData::Stat.each_main do |s|
  415. new_ret.push([s.id, ret[s.id]]) if ret[s.id] > 0 && s.pbs_order >= 0
  416. end
  417. ret = new_ret
  418. when "Height", "Weight"
  419. ret = ret.to_f / 10
  420. when "Habitat"
  421. ret = nil if ret == :None
  422. when "Evolutions"
  423. if ret
  424. ret = ret.reject { |evo| evo[3] } # Remove prevolutions
  425. ret.each do |evo|
  426. param_type = GameData::Evolution.get(evo[1]).parameter
  427. if !param_type.nil?
  428. if param_type.is_a?(Symbol) && !GameData.const_defined?(param_type)
  429. evo[2] = getConstantName(param_type, evo[2])
  430. else
  431. evo[2] = evo[2].to_s
  432. end
  433. end
  434. end
  435. ret.each_with_index { |evo, i| ret[i] = evo[0, 3] }
  436. ret = nil if ret.length == 0
  437. end
  438. end
  439. if writing_form && !ret.nil?
  440. base_form = GameData::Species.get(@species)
  441. if !["WildItemCommon", "WildItemUncommon", "WildItemRare"].include?(key) ||
  442. (base_form.wild_item_common == @wild_item_common &&
  443. base_form.wild_item_uncommon == @wild_item_uncommon &&
  444. base_form.wild_item_rare == @wild_item_rare)
  445. ret = nil if base_form.get_property_for_PBS(key) == ret
  446. end
  447. end
  448. return ret
  449. end
  450. end
  451. end