diff --git a/lib/granblue/importers/character_importer.rb b/lib/granblue/importers/character_importer.rb index c1743e5..09f7ba7 100644 --- a/lib/granblue/importers/character_importer.rb +++ b/lib/granblue/importers/character_importer.rb @@ -59,6 +59,9 @@ module Granblue # @option attributes [String] :kamigame Kamigame link # @option attributes [Array] :nicknames_en English nicknames # @option attributes [Array] :nicknames_jp Japanese nicknames + # @option attributes [Integer] :season Character season (gacha availability window) + # @option attributes [Array] :series Character series (identity/pool membership) + # @option attributes [Boolean] :gacha_available Whether character can be pulled from gacha # # @raise [ImportError] If required attributes are missing or invalid def build_attributes(row) @@ -97,7 +100,10 @@ module Granblue gamewith: parse_value(row['gamewith']), kamigame: parse_value(row['kamigame']), nicknames_en: parse_array(row['nicknames_en']), - nicknames_jp: parse_array(row['nicknames_jp']) + nicknames_jp: parse_array(row['nicknames_jp']), + season: parse_integer(row['season']), + series: parse_integer_array(row['series']), + gacha_available: parse_boolean(row['gacha_available']) } end end diff --git a/lib/granblue/parsers/character_parser.rb b/lib/granblue/parsers/character_parser.rb index ec44cc3..a86448c 100644 --- a/lib/granblue/parsers/character_parser.rb +++ b/lib/granblue/parsers/character_parser.rb @@ -194,6 +194,10 @@ module Granblue kamigame: hash['link_kamigame'] } + info[:series] = series_from_hash(hash) + info[:season] = season_from_hash(hash) + info[:gacha_available] = gacha_available_from_hash(hash) + info.compact end @@ -207,6 +211,10 @@ module Granblue @character.gamewith = hash[:links][:gamewith] if hash[:links].key?(:gamewith) @character.kamigame = hash[:links][:kamigame] if hash[:links].key?(:kamigame) + @character.series = hash[:series] if hash[:series].present? + @character.season = hash[:season] if hash[:season].present? + @character.gacha_available = hash[:gacha_available] unless hash[:gacha_available].nil? + if @character.save ap "#{@character.granblue_id}: Successfully saved info for #{@character.name_en}" if @debug puts @@ -230,6 +238,86 @@ module Granblue end.reduce({}, :merge) end + # Extracts series (identity/pool membership) from wiki hash + # Returns an array of series IDs based on |series= and |obtain= fields + def series_from_hash(hash) + series = [] + + # Primary series from |series= field + wiki_series = hash['series'].to_s.downcase.strip + primary_series = Granblue::Parsers::Wiki.character_series[wiki_series] + series << primary_series if primary_series + + # Additional series indicators from |obtain= field + obtain = hash['obtain'].to_s.downcase + series << 2 if obtain.include?('grand') && !series.include?(2) # Grand + series << 3 if obtain.include?('zodiac') && !series.include?(3) # Zodiac + + # Seasonal series based on page name or obtain field + page_name = @character.wiki_en.to_s.downcase + if page_name.include?('summer') || page_name.include?('(swimsuit)') + series << 10 unless series.include?(10) # Summer + end + if page_name.include?('yukata') + series << 11 unless series.include?(11) # Yukata + end + if page_name.include?('valentine') + series << 12 unless series.include?(12) # Valentine + end + if page_name.include?('halloween') + series << 13 unless series.include?(13) # Halloween + end + if page_name.include?('(formal)') || page_name.include?('formal ') + series << 14 unless series.include?(14) # Formal + end + if page_name.include?('holiday') || page_name.include?('(holiday)') + series << 1 unless series.include?(1) # Standard for now, Holiday chars usually just standard series + end + + # Default to Standard if no series found and character is gacha-available + series << 1 if series.empty? && gacha_available_from_hash(hash) + + series.uniq.sort + end + + # Extracts season (gacha availability window) from wiki hash + # Returns a single season ID based on seasonal indicators + def season_from_hash(hash) + page_name = @character.wiki_en.to_s.downcase + obtain = hash['obtain'].to_s.downcase + + # Check page name for seasonal indicators + return 2 if page_name.include?('valentine') + return 3 if page_name.include?('(formal)') || page_name.include?('formal ') + return 4 if page_name.include?('summer') || page_name.include?('yukata') || page_name.include?('(swimsuit)') + return 5 if page_name.include?('halloween') + return 6 if page_name.include?('holiday') || page_name.include?('(holiday)') + + # Check obtain field for seasonal banners + return 2 if obtain.include?('valentine') + return 3 if obtain.include?('formal') + return 4 if obtain.include?('summer') + return 5 if obtain.include?('halloween') + return 6 if obtain.include?('holiday') + + # Default to Standard for gacha-available characters + 1 if gacha_available_from_hash(hash) + end + + # Determines if character can be pulled from gacha based on obtain field and series + def gacha_available_from_hash(hash) + wiki_series = hash['series'].to_s.downcase.strip + obtain = hash['obtain'].to_s.downcase + + # Non-gacha series + non_gacha_series = %w[eternal evoker archangel event promo collab] + return false if non_gacha_series.include?(wiki_series) + + # Check obtain field for gacha indicators + gacha_indicators = %w[premium flash legend classic grand zodiac valentine summer halloween holiday formal] + gacha_indicators.any? { |indicator| obtain.include?(indicator) } + end + # Parses a date string into a Date object def parse_date(date_str) Date.parse(date_str) unless date_str.blank? diff --git a/lib/granblue/parsers/wiki.rb b/lib/granblue/parsers/wiki.rb index eca1b02..c4c24b4 100644 --- a/lib/granblue/parsers/wiki.rb +++ b/lib/granblue/parsers/wiki.rb @@ -15,6 +15,8 @@ module Granblue class_attribute :races class_attribute :bullets class_attribute :boolean + class_attribute :character_series + class_attribute :character_seasons self.base_uri = 'https://gbf.wiki/api.php' @@ -74,6 +76,37 @@ module Granblue 'no' => false }.freeze + # Maps wiki |series= values to CHARACTER_SERIES enum values + # Wiki uses lowercase, single values like "grand", "zodiac", etc. + self.character_series = { + 'normal' => 1, # Standard + 'grand' => 2, # Grand + 'zodiac' => 3, # Zodiac + 'promo' => 4, # Promo + 'collab' => 5, # Collab + 'eternal' => 6, # Eternal + 'evoker' => 7, # Evoker + 'archangel' => 8, # Saint (Archangels) + 'fantasy' => 9, # Fantasy + 'summer' => 10, # Summer + 'yukata' => 11, # Yukata + 'valentine' => 12, # Valentine + 'halloween' => 13, # Halloween + 'formal' => 14, # Formal + 'event' => 15 # Event + }.freeze + + # Maps wiki seasonal indicators to CHARACTER_SEASONS enum values + # Determined from page name suffix or |obtain= field + self.character_seasons = { + 'standard' => 1, # Standard (year-round in their pool) + 'valentine' => 2, # Valentine + 'formal' => 3, # Formal + 'summer' => 4, # Summer (includes Yukata) + 'halloween' => 5, # Halloween + 'holiday' => 6 # Holiday + }.freeze + def initialize(props: ['wikitext'], debug: false) @debug = debug @props = props.join('|')