diff --git a/app/models/collection_weapon.rb b/app/models/collection_weapon.rb index 8df620d..e4c4808 100644 --- a/app/models/collection_weapon.rb +++ b/app/models/collection_weapon.rb @@ -23,7 +23,7 @@ class CollectionWeapon < ApplicationRecord validate :validate_transcendence_requirements scope :by_weapon, ->(weapon_id) { where(weapon_id: weapon_id) } - scope :by_series, ->(series) { joins(:weapon).where(weapons: { series: series }) } + scope :by_series, ->(series_id) { joins(:weapon).where(weapons: { weapon_series_id: series_id }) } scope :with_keys, -> { where.not(weapon_key1_id: nil) } scope :with_ax, -> { where.not(ax_modifier1: nil) } scope :by_element, ->(element) { joins(:weapon).where(weapons: { element: element }) } @@ -45,7 +45,7 @@ class CollectionWeapon < ApplicationRecord return unless weapon.present? # Validate weapon_key4 is only on Opus/Draconic weapons - if weapon_key4.present? && ![3, 27].include?(weapon.series) + if weapon_key4.present? && !weapon.opus_or_draconic? errors.add(:weapon_key4, "can only be set on Opus or Draconic weapons") end @@ -78,7 +78,7 @@ class CollectionWeapon < ApplicationRecord def validate_element_change return unless element.present? && weapon.present? - unless Weapon.element_changeable?(weapon.series) + unless Weapon.element_changeable?(weapon) errors.add(:element, "can only be set on element-changeable weapons") end end diff --git a/app/models/grid_weapon.rb b/app/models/grid_weapon.rb index beb05e5..ef85d9c 100644 --- a/app/models/grid_weapon.rb +++ b/app/models/grid_weapon.rb @@ -21,9 +21,8 @@ # @!attribute [r] awakening # @return [Awakening, nil] the associated awakening, if any. class GridWeapon < ApplicationRecord - # Allowed extra positions and allowed weapon series when in an extra position. + # Allowed extra positions (9, 10, 11 are the "extra" grid slots) EXTRA_POSITIONS = [9, 10, 11].freeze - ALLOWED_EXTRA_SERIES = [11, 16, 17, 28, 29, 32, 34].freeze belongs_to :weapon, foreign_key: :weapon_id, primary_key: :id @@ -92,7 +91,8 @@ class GridWeapon < ApplicationRecord next false unless party_weapon.id.present? id_match = weapon.id == party_weapon.id - series_match = weapon.series == party_weapon.weapon.series + series_match = weapon.weapon_series_id.present? && + weapon.weapon_series_id == party_weapon.weapon.weapon_series_id both_opus_or_draconic = weapon.opus_or_draconic? && party_weapon.weapon.opus_or_draconic? both_draconic = weapon.draconic_or_providence? && party_weapon.weapon.draconic_or_providence? @@ -105,14 +105,14 @@ class GridWeapon < ApplicationRecord ## # Validates whether the grid weapon is compatible with the desired position. # - # For positions 9, 10, or 11 (considered extra positions), the weapon's series must belong to the allowed set. + # For positions 9, 10, or 11 (considered extra positions), the weapon's series must have the `extra` flag set. # If the weapon is in an extra position but does not match an allowed series, an error is added. # # @return [void] def compatible_with_position return unless weapon.present? - if EXTRA_POSITIONS.include?(position.to_i) && !ALLOWED_EXTRA_SERIES.include?(weapon.series.to_i) + if EXTRA_POSITIONS.include?(position.to_i) && !weapon.weapon_series&.extra errors.add(:series, 'must be compatible with position') end end diff --git a/app/models/weapon.rb b/app/models/weapon.rb index b9c8c28..93415f8 100644 --- a/app/models/weapon.rb +++ b/app/models/weapon.rb @@ -36,7 +36,10 @@ class Weapon < ApplicationRecord has_many :weapon_awakenings has_many :awakenings, through: :weapon_awakenings + belongs_to :weapon_series, optional: true + # Legacy mapping - kept for backwards compatibility during migration + # TODO: Remove after data migration is complete SERIES_SLUGS = { 1 => 'seraphic', 2 => 'grand', @@ -94,21 +97,36 @@ class Weapon < ApplicationRecord end def compatible_with_key?(key) - key.series.include?(series) + return false unless weapon_series.present? + + key.weapon_series.include?(weapon_series) end # Returns whether the weapon is included in the Draconic or Dark Opus series def opus_or_draconic? - [3, 27].include?(series) + return false unless weapon_series.present? + + [WeaponSeries::DARK_OPUS, WeaponSeries::DRACONIC].include?(weapon_series.slug) end # Returns whether the weapon belongs to the Draconic Weapon series or the Draconic Weapon Providence series def draconic_or_providence? - [27, 40].include?(series) + return false unless weapon_series.present? + + [WeaponSeries::DRACONIC, WeaponSeries::DRACONIC_PROVIDENCE].include?(weapon_series.slug) end - def self.element_changeable?(series) - [4, 13, 17, 19].include?(series.to_i) + def self.element_changeable?(weapon_or_series) + if weapon_or_series.is_a?(Weapon) + weapon_or_series.weapon_series&.element_changeable || false + elsif weapon_or_series.is_a?(WeaponSeries) + weapon_or_series.element_changeable + elsif weapon_or_series.is_a?(Integer) + # Legacy support for integer series IDs during transition + [4, 13, 17, 19].include?(weapon_or_series) + else + false + end end # Promotion scopes @@ -135,11 +153,7 @@ class Weapon < ApplicationRecord promotions.filter_map { |p| GranblueEnums::PROMOTIONS.key(p)&.to_s } end - private - def series_slug - # Assuming series is an array, take the first value - series_number = series.first - SERIES_SLUGS[series_number] + weapon_series&.slug || SERIES_SLUGS[series] end end diff --git a/app/models/weapon_key.rb b/app/models/weapon_key.rb index cfce439..057303a 100644 --- a/app/models/weapon_key.rb +++ b/app/models/weapon_key.rb @@ -1,7 +1,16 @@ # frozen_string_literal: true class WeaponKey < ApplicationRecord + has_many :weapon_key_series, dependent: :destroy + has_many :weapon_series, through: :weapon_key_series + def blueprint WeaponKeyBlueprint end + + def compatible_with_weapon?(weapon) + return false unless weapon.weapon_series.present? + + weapon_series.include?(weapon.weapon_series) + end end