API updates for Draconic Weapons Providence (#138)

* Make weapon key series an array

Draconic Weapons Providence can have original Draconic Weapon keys, but also have a new key that can only be equipped to them. Thanks, Cygames.

* Update weapon.rb

* Update to check key compatibility against an array instead of an int
* Add convenience function to check if the weapon is part of a Draconic Weapon series

* Update grid_weapon.rb

Update conflict detection to:
* Detect Draconic Weapons Providence
* Add multiple weapons to conflicting weapons instead of just one

* (WIP) Update conflict view rendering

Conflict blueprints should render multiple conflict weapons instead of just one.

Also adds Draconic Weapon Providence series to various places that check series by number

* Finish last bugs

We tested to ensure that conflict resolution appears for

* Opus and Draconic
* Draconic and Draconic 2
* Draconic 2 + Opus and Draconic 1
This commit is contained in:
Justin Edmund 2023-12-26 03:21:06 -08:00 committed by GitHub
parent 92f29dfa08
commit 00e5ec8c4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 74 additions and 97 deletions

View file

@ -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|

View file

@ -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|

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1 +1 @@
DataMigrate::Data.define(version: 20230816061005)
DataMigrate::Data.define(version: 20231119051223)

View file

@ -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

View file

@ -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

View file

@ -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