diff --git a/app/blueprints/api/v1/conflict_blueprint.rb b/app/blueprints/api/v1/conflict_blueprint.rb index fa036e5..eccfab1 100644 --- a/app/blueprints/api/v1/conflict_blueprint.rb +++ b/app/blueprints/api/v1/conflict_blueprint.rb @@ -18,8 +18,8 @@ module Api end view :weapons do - field :conflicts, if: ->(_fn, _obj, options) { options.key?(:conflict_weapon) } do |_, options| - GridWeaponBlueprint.render_as_hash(options[:conflict_weapon], view: :nested) + field :conflicts, if: ->(_fn, _obj, options) { options.key?(:conflict_weapons) } do |_, options| + GridWeaponBlueprint.render_as_hash(options[:conflict_weapons], view: :nested) end field :incoming, if: ->(_fn, _obj, options) { options.key?(:incoming_weapon) } do |_, options| diff --git a/app/blueprints/api/v1/grid_weapon_blueprint.rb b/app/blueprints/api/v1/grid_weapon_blueprint.rb index 7ab9355..ecbe643 100644 --- a/app/blueprints/api/v1/grid_weapon_blueprint.rb +++ b/app/blueprints/api/v1/grid_weapon_blueprint.rb @@ -15,7 +15,7 @@ module Api association :weapon_keys, blueprint: WeaponKeyBlueprint, if: lambda { |_field_name, w, _options| - [2, 3, 17, 24].include?(w.weapon.series) + [2, 3, 17, 24, 34].include?(w.weapon.series) } field :ax, if: ->(_field_name, w, _options) { w.weapon.ax } do |w| diff --git a/app/controllers/api/v1/grid_weapons_controller.rb b/app/controllers/api/v1/grid_weapons_controller.rb index f68e011..3887e95 100644 --- a/app/controllers/api/v1/grid_weapons_controller.rb +++ b/app/controllers/api/v1/grid_weapons_controller.rb @@ -93,7 +93,7 @@ module Api # Check if the incoming weapon is compatible with the specified position def compatible_with_position?(incoming_weapon, position) - false if [9, 10, 11].include?(position.to_i) && ![11, 16, 17, 28, 29].include?(incoming_weapon.series) + false if [9, 10, 11].include?(position.to_i) && ![11, 16, 17, 28, 29, 34].include?(incoming_weapon.series) true end @@ -126,9 +126,9 @@ module Api end # Render the conflict view as a string - def render_conflict_view(conflict_weapon, incoming_weapon, incoming_position) + def render_conflict_view(conflict_weapons, incoming_weapon, incoming_position) ConflictBlueprint.render(nil, view: :weapons, - conflict_weapon: conflict_weapon, + conflict_weapons: conflict_weapons, incoming_weapon: incoming_weapon, incoming_position: incoming_position) end @@ -166,12 +166,14 @@ module Api end def handle_conflict(weapon) - conflict_weapon = weapon.conflicts(party) + conflict_weapons = weapon.conflicts(party) - if conflict_weapon.weapon.id != incoming_weapon.id + # Map conflict weapon IDs into an array + conflict_weapon_ids = conflict_weapons.map(&:id) + if !conflict_weapon_ids.include?(incoming_weapon.id) # Render conflict view if the underlying canonical weapons # are not identical - output = render_conflict_view([conflict_weapon], incoming_weapon, weapon_params[:position]) + output = render_conflict_view(conflict_weapons, incoming_weapon, weapon_params[:position]) render json: output else # Move the original grid weapon to the new position diff --git a/app/models/grid_weapon.rb b/app/models/grid_weapon.rb index b2196ae..c24dcbe 100644 --- a/app/models/grid_weapon.rb +++ b/app/models/grid_weapon.rb @@ -17,7 +17,7 @@ class GridWeapon < ApplicationRecord validate :compatible_with_position, on: :create validate :no_conflicts, on: :create - before_save :is_mainhand + before_save :mainhand? ##### Amoeba configuration amoeba do @@ -44,14 +44,20 @@ class GridWeapon < ApplicationRecord def conflicts(party) return unless weapon.limit - party.weapons.find do |party_weapon| - return unless party_weapon.id + conflicting_weapons = [] + + party.weapons.each do |party_weapon| + next unless party_weapon.id id_match = weapon.id == party_weapon.id series_match = weapon.series == party_weapon.weapon.series both_opus_or_draconic = weapon.opus_or_draconic? && party_weapon.weapon.opus_or_draconic? - weapon if (series_match || both_opus_or_draconic) && !id_match + both_draconic = weapon.draconic_or_providence? && party_weapon.weapon.draconic_or_providence? + + conflicting_weapons << party_weapon if (series_match || both_opus_or_draconic || both_draconic) && !id_match end + + conflicting_weapons end private @@ -60,9 +66,15 @@ class GridWeapon < ApplicationRecord # Validates whether the weapon can be added to the desired position def compatible_with_position - return unless [9, 10, 11].include?(position.to_i) && ![11, 16, 17, 28, 29, 32].include?(weapon.series) + is_extra_position = [9, 10, 11].include?(position.to_i) + is_extra_weapon = [11, 16, 17, 28, 29, 32, 34].include?(weapon.series.to_i) + + return unless is_extra_position + + return true if is_extra_weapon errors.add(:series, 'must be compatible with position') + false end # Validates whether the desired weapon key can be added to the weapon @@ -75,11 +87,13 @@ class GridWeapon < ApplicationRecord # Validates whether there is a conflict with the party def no_conflicts # Check if the grid weapon conflicts with any of the other grid weapons in the party - errors.add(:series, 'must not conflict with existing weapons') unless conflicts(party).nil? + return unless !conflicts(party).nil? && !conflicts(party).empty? + + errors.add(:series, 'must not conflict with existing weapons') end # Checks if the weapon should be a mainhand before saving the model - def is_mainhand + def mainhand? self.mainhand = position == -1 end end diff --git a/app/models/weapon.rb b/app/models/weapon.rb index 8b330b1..321c5c4 100644 --- a/app/models/weapon.rb +++ b/app/models/weapon.rb @@ -48,11 +48,16 @@ class Weapon < ApplicationRecord end def compatible_with_key?(key) - key.series == series + key.series.include?(series) end # Returns whether the weapon is included in the Draconic or Dark Opus series def opus_or_draconic? [2, 3].include?(series) end + + # Returns whether the weapon belongs to the Draconic Weapon series or the Draconic Weapon Providence series + def draconic_or_providence? + [3, 34].include?(series) + end end diff --git a/db/data/20231119051223_migrate_series.rb b/db/data/20231119051223_migrate_series.rb new file mode 100644 index 0000000..cb8f0c0 --- /dev/null +++ b/db/data/20231119051223_migrate_series.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class MigrateSeries < ActiveRecord::Migration[7.0] + def up + WeaponKey.find_each do |weapon_key| + weapon_key.update(new_series: [weapon_key.series]) + end + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/data_schema.rb b/db/data_schema.rb index d620ac0..4a66c96 100644 --- a/db/data_schema.rb +++ b/db/data_schema.rb @@ -1 +1 @@ -DataMigrate::Data.define(version: 20230816061005) +DataMigrate::Data.define(version: 20231119051223) diff --git a/db/migrate/20231119051213_add_new_series_to_weapon_keys.rb b/db/migrate/20231119051213_add_new_series_to_weapon_keys.rb new file mode 100644 index 0000000..71278db --- /dev/null +++ b/db/migrate/20231119051213_add_new_series_to_weapon_keys.rb @@ -0,0 +1,5 @@ +class AddNewSeriesToWeaponKeys < ActiveRecord::Migration[7.0] + def change + add_column :weapon_keys, :new_series, :integer, null: false, default: [], array: true + end +end diff --git a/db/migrate/20231119051231_rename_new_series_and_delete_series.rb b/db/migrate/20231119051231_rename_new_series_and_delete_series.rb new file mode 100644 index 0000000..61dcb4c --- /dev/null +++ b/db/migrate/20231119051231_rename_new_series_and_delete_series.rb @@ -0,0 +1,6 @@ +class RenameNewSeriesAndDeleteSeries < ActiveRecord::Migration[7.0] + def change + remove_column :weapon_keys, :series, :integer + rename_column :weapon_keys, :new_series, :series + end +end diff --git a/db/schema.rb b/db/schema.rb index 8d4f9ab..1211378 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do +ActiveRecord::Schema[7.0].define(version: 2023_11_19_051231) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gin" enable_extension "pg_trgm" @@ -30,50 +30,6 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do t.integer "order", default: 0, null: false end - create_table "character_charge_attacks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.uuid "character_id" - t.string "name_en", null: false - t.string "name_jp", null: false - t.string "description_en", null: false - t.string "description_jp", null: false - t.integer "order", null: false - t.string "form" - t.uuid "effects", array: true - t.index ["character_id"], name: "index_character_charge_attacks_on_character_id" - end - - create_table "character_skills", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.uuid "character_id" - t.string "name_en", null: false - t.string "name_jp", null: false - t.string "description_en", null: false - t.string "description_jp", null: false - t.integer "type", null: false - t.integer "position", null: false - t.string "form" - t.integer "cooldown", default: 0, null: false - t.integer "lockout", default: 0, null: false - t.integer "duration", array: true - t.boolean "recast", default: false, null: false - t.integer "obtained_at", default: 1, null: false - t.uuid "effects", array: true - t.index ["character_id"], name: "index_character_skills_on_character_id" - end - - create_table "character_support_skills", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.uuid "character_id" - t.string "name_en", null: false - t.string "name_jp", null: false - t.string "description_en", null: false - t.string "description_jp", null: false - t.integer "position", null: false - t.integer "obtained_at" - t.boolean "emp", default: false, null: false - t.boolean "transcendence", default: false, null: false - t.uuid "effects", array: true - t.index ["character_id"], name: "index_character_support_skills_on_character_id" - end - create_table "characters", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "name_en" t.string "name_jp" @@ -101,8 +57,6 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do t.integer "max_hp_ulb" t.integer "max_atk_ulb" t.integer "character_id", default: [], null: false, array: true - t.string "nicknames_en", default: [], null: false, array: true - t.string "nicknames_jp", default: [], null: false, array: true t.string "wiki_en", default: "", null: false t.date "release_date" t.date "flb_date" @@ -110,29 +64,11 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do t.string "wiki_ja", default: "", null: false t.string "gamewith", default: "", null: false t.string "kamigame", default: "", null: false + t.string "nicknames_en", default: [], null: false, array: true + t.string "nicknames_jp", default: [], null: false, array: true t.index ["name_en"], name: "index_characters_on_name_en", opclass: :gin_trgm_ops, using: :gin end - create_table "data_migrations", primary_key: "version", id: :string, force: :cascade do |t| - end - - create_table "effects", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.string "name_en", null: false - t.string "name_jp", null: false - t.string "description_en", null: false - t.string "description_jp", null: false - t.integer "accuracy_value" - t.string "accuracy_suffix" - t.string "accuracy_comparator" - t.jsonb "strength", array: true - t.integer "healing_cap" - t.boolean "duration_indefinite", default: false, null: false - t.integer "duration_value" - t.string "duration_unit" - t.string "notes_en" - t.string "notes_jp" - end - create_table "favorites", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.uuid "user_id" t.uuid "party_id" @@ -179,10 +115,6 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do t.jsonb "ring3", default: {"modifier"=>nil, "strength"=>nil}, null: false t.jsonb "ring4", default: {"modifier"=>nil, "strength"=>nil}, null: false t.jsonb "earring", default: {"modifier"=>nil, "strength"=>nil}, null: false - t.boolean "skill0_enabled", default: true, null: false - t.boolean "skill1_enabled", default: true, null: false - t.boolean "skill2_enabled", default: true, null: false - t.boolean "skill3_enabled", default: true, null: false t.uuid "awakening_id" t.integer "awakening_level", default: 1 t.index ["awakening_id"], name: "index_grid_characters_on_awakening_id" @@ -200,7 +132,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "transcendence_step", default: 0, null: false - t.boolean "quick_summon", default: false, null: false + t.boolean "quick_summon", default: false t.index ["party_id"], name: "index_grid_summons_on_party_id" t.index ["summon_id"], name: "index_grid_summons_on_summon_id" end @@ -302,7 +234,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do t.datetime "revoked_at", precision: nil t.datetime "created_at", precision: nil, null: false t.string "scopes" - t.string "previous_refresh_token", default: "" + t.string "previous_refresh_token", default: "", null: false t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id" t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true @@ -353,7 +285,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do t.uuid "guidebook3_id" t.uuid "guidebook1_id" t.uuid "guidebook2_id" - t.boolean "auto_summon", default: false, null: false + t.boolean "auto_summon", default: false t.boolean "remix", default: false, null: false t.integer "visibility", default: 1, null: false t.index ["accessory_id"], name: "index_parties_on_accessory_id" @@ -440,8 +372,6 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do t.boolean "xlb", default: false, null: false t.integer "max_atk_xlb" t.integer "max_hp_xlb" - t.string "nicknames_en", default: [], null: false, array: true - t.string "nicknames_jp", default: [], null: false, array: true t.integer "summon_id" t.date "release_date" t.date "flb_date" @@ -451,6 +381,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do t.string "gamewith", default: "" t.string "kamigame", default: "" t.date "xlb_date" + t.string "nicknames_en", default: [], null: false, array: true + t.string "nicknames_jp", default: [], null: false, array: true t.index ["name_en"], name: "index_summons_on_name_en", opclass: :gin_trgm_ops, using: :gin end @@ -480,12 +412,12 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do create_table "weapon_keys", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "name_en" t.string "name_jp" - t.integer "series" t.integer "slot" t.integer "group" t.integer "order" t.string "slug" t.integer "granblue_id" + t.integer "series", default: [], null: false, array: true end create_table "weapons", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| @@ -512,8 +444,6 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do t.integer "ax_type" t.boolean "limit", default: false, null: false t.boolean "ax", default: false, null: false - t.string "nicknames_en", default: [], null: false, array: true - t.string "nicknames_jp", default: [], null: false, array: true t.uuid "recruits_id" t.integer "max_awakening_level" t.date "release_date" @@ -523,6 +453,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_24_222107) do t.string "wiki_ja", default: "" t.string "gamewith", default: "" t.string "kamigame", default: "" + t.string "nicknames_en", default: [], null: false, array: true + t.string "nicknames_jp", default: [], null: false, array: true t.index ["name_en"], name: "index_weapons_on_name_en", opclass: :gin_trgm_ops, using: :gin t.index ["recruits_id"], name: "index_weapons_on_recruits_id" end