diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..fc9d415 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,20 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu +{ + "name": "weakauras", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/base:jammy", + "features": { + "ghcr.io/devcontainers/features/node:1": {} + } + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + // Configure tool-specific properties. + // "customizations": {}, + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..f33a02c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for more information: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +# https://containers.dev/guide/dependabot + +version: 2 +updates: + - package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: weekly diff --git a/.mise.toml b/.mise.toml index 19f6f7b..cdc3371 100644 --- a/.mise.toml +++ b/.mise.toml @@ -1,3 +1,3 @@ [tools] -ruby = "latest" node = "latest" +ruby = "latest" diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..822e5d1 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${file}" + } + ] +} \ No newline at end of file diff --git a/Gemfile b/Gemfile index b53eebf..ab237af 100644 --- a/Gemfile +++ b/Gemfile @@ -1,12 +1,14 @@ source 'https://rubygems.org' -gem 'ruby_wasm', github: 'ruby/ruby.wasm' +# gem 'ruby_wasm', github: 'ruby/ruby.wasm' +gem 'ruby-lsp' group :development do gem 'rubocop' end group :test do + gem 'debug' gem 'guard' gem 'guard-rspec', require: false gem 'rspec' diff --git a/Gemfile.lock b/Gemfile.lock index 1a90e8b..7de6d67 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,15 +1,12 @@ -GIT - remote: https://github.com/ruby/ruby.wasm.git - revision: 0bab190cd87d533096ad98eefd3132b93fbe9068 - specs: - ruby_wasm (2.4.1) - GEM remote: https://rubygems.org/ specs: ast (2.4.2) casting (1.0.2) coderay (1.1.3) + debug (1.9.2) + irb (~> 1.10) + reline (>= 0.3.8) deep_merge (1.2.2) diff-lcs (1.5.1) docile (1.4.0) @@ -30,12 +27,17 @@ GEM guard (~> 2.1) guard-compat (~> 1.1) rspec (>= 2.99.0, < 4.0) + io-console (0.7.2) + irb (1.14.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) json (2.7.1) json_pure (2.7.1) language_server-protocol (3.17.0.3) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) + logger (1.6.1) lumberjack (1.2.10) method_source (1.1.0) nenv (0.3.0) @@ -46,15 +48,24 @@ GEM parser (3.3.0.2) ast (~> 2.4.1) racc + prism (1.0.0) pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) + psych (5.1.2) + stringio racc (1.7.3) rainbow (3.1.1) rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) + rbs (3.5.3) + logger + rdoc (6.7.0) + psych (>= 4.0.0) regexp_parser (2.9.0) + reline (0.5.10) + io-console (~> 0.5) rexml (3.2.6) rspec (3.13.0) rspec-core (~> 3.13.0) @@ -82,6 +93,11 @@ GEM unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.30.0) parser (>= 3.2.1.0) + ruby-lsp (0.18.1) + language_server-protocol (~> 3.17.0) + prism (~> 1.0) + rbs (>= 3, < 4) + sorbet-runtime (>= 0.5.10782) ruby-progressbar (1.13.0) shellany (0.0.1) simplecov (0.22.0) @@ -90,6 +106,8 @@ GEM simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) + sorbet-runtime (0.5.11577) + stringio (3.1.1) thor (1.3.1) unicode-display_width (2.5.0) @@ -99,13 +117,14 @@ PLATFORMS DEPENDENCIES casting + debug deep_merge guard guard-rspec json_pure rspec rubocop - ruby_wasm! + ruby-lsp simplecov BUNDLED WITH diff --git a/public/examples/mage/frost.rb b/public/examples/mage/frost.rb new file mode 100644 index 0000000..582a26e --- /dev/null +++ b/public/examples/mage/frost.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# --- +# title: 'Mage: Frost' +# --- + +title 'Mage: Frost' +load spec: :frost_mage +hide_ooc! + +dynamic_group 'Frost Mage WhackAuras' do + action_usable 'Comet Storm' + action_usable 'Glacial Spike' do + glow! + end + action_usable 'Shifting Power' + action_usable 'Frozen Orb' + action_usable({ spell_name: 'Flurry', spell_count: 1 }) +end diff --git a/public/examples/warrior/fury.rb b/public/examples/warrior/fury.rb index 526f91c..4f3ca03 100644 --- a/public/examples/warrior/fury.rb +++ b/public/examples/warrior/fury.rb @@ -4,17 +4,27 @@ # title: 'Warrior: Fury' # --- +title 'Warrior: Fury' load spec: :fury_warrior hide_ooc! dynamic_group 'Fury WhackAuras' do + offset y: -100 action_usable 'Bloodthirst' action_usable 'Raging Blow' - action_usable 'Rampage', if_missing: ['Enrage'] do + action_usable 'Rampage' + action_usable 'Execute', if_stacks: { 'Ashen Juggernaut' => '>= 2' } do glow! end - action_usable 'Rampage', requires: { auras: ['Enrage'] } - action_usable 'Execute' + action_usable 'Execute', if_stacks: { 'Ashen Juggernaut' => '< 2' } action_usable 'Bladestorm' action_usable 'Thunderous Roar' + action_usable "Odyn's Fury" + action_usable 'Whirlwind', if_missing: ['Whirlwind'] +end + +dynamic_group 'Fury Offensive Cooldowns' do + offset y: -40 + action_usable 'Recklessness' + action_usable 'Avatar' end diff --git a/public/node.rb b/public/node.rb index 81195f3..ed5e818 100644 --- a/public/node.rb +++ b/public/node.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +TOC_VERSION = 110_002 + WOW_SPECS = { blood_deathknight: 250, frost_deathknight: 251, @@ -243,6 +245,7 @@ def hide_ooc! # rubocop:disable Metrics/MethodLength end def as_json - { load: load, triggers: triggers, actions: actions, conditions: conditions } + { load: load, triggers: triggers, actions: actions, conditions: conditions, + tocversion: TOC_VERSION } end end diff --git a/public/weak_aura.rb b/public/weak_aura.rb index ceea338..724cdb5 100644 --- a/public/weak_aura.rb +++ b/public/weak_aura.rb @@ -65,7 +65,6 @@ def as_json # rubocop:disable Metrics/MethodLength }, internalVersion: 70, yOffset: 99.999755859375, - tocversion: 100_200, id: id, borderOffset: 4, frameStrata: 1, diff --git a/public/weak_aura/dynamic_group.rb b/public/weak_aura/dynamic_group.rb index 131b710..2b1d746 100644 --- a/public/weak_aura/dynamic_group.rb +++ b/public/weak_aura/dynamic_group.rb @@ -118,7 +118,6 @@ def as_json # rubocop:disable Metrics/MethodLength uid: uid, constantFactor: 'RADIUS', borderOffset: 4, - tocversion: 100_200, id: id, rotation: 0, frameStrata: 1, diff --git a/public/weak_aura/group.rb b/public/weak_aura/group.rb index ef64d3a..5b862a9 100644 --- a/public/weak_aura/group.rb +++ b/public/weak_aura/group.rb @@ -64,7 +64,6 @@ def as_json # rubocop:disable Metrics/MethodLength }, internalVersion: 70, yOffset: 99.999755859375, - tocversion: 100_200, id: id, borderOffset: 4, frameStrata: 1, diff --git a/public/weak_aura/icon.rb b/public/weak_aura/icon.rb index 2f4c028..4e57d37 100644 --- a/public/weak_aura/icon.rb +++ b/public/weak_aura/icon.rb @@ -109,7 +109,6 @@ def as_json # rubocop:disable Metrics/MethodLength 1, 1 ], - tocversion: 100_200, id: id, config: [], alpha: 1, diff --git a/public/weak_aura/triggers.rb b/public/weak_aura/triggers.rb index 2c4fce6..b632180 100644 --- a/public/weak_aura/triggers.rb +++ b/public/weak_aura/triggers.rb @@ -10,6 +10,14 @@ def initialize(**options) spell_name: options[:spell] }.merge(options) end + + def parse_count_operator(count, default_operator = '==') + return [count, default_operator] if count.is_a?(Integer) + + operator = count.to_s.match(/^[<>!=]+/)&.[](0) || default_operator + count = count.to_s.gsub(/^[<>!=]+/, '').to_i + [count, operator] + end end end diff --git a/public/weak_aura/triggers/action_usable.rb b/public/weak_aura/triggers/action_usable.rb index ed86307..38b74cb 100644 --- a/public/weak_aura/triggers/action_usable.rb +++ b/public/weak_aura/triggers/action_usable.rb @@ -11,24 +11,45 @@ def initialize(**_options) end def as_json # rubocop:disable Metrics/MethodLength + trigger = { + type: 'spell', + subeventSuffix: '_CAST_START', + spellName: options[:spell], + use_exact_spellName: !!options[:exact], + use_genericShowOn: true, + event: 'Action Usable', + names: [], + realSpellName: options[:spell_name], + use_spellName: true, + spellIds: [], + genericShowOn: 'showOnCooldown', + subeventPrefix: 'SPELL', + unit: 'player', + use_track: true, + debuffType: 'HELPFUL' + } + + if options[:spell_count] + spell_count_operator = options[:spell_count].to_s.match(/[<>=]+/)&.[](0) || '==' + spell_count = if options[:spell_count].is_a?(Numeric) + options[:spell_count] + else + options[:spell_count] + .match(/[0-9]+/)&.[](0) + end.to_i + + if spell_count + trigger + .merge!({ + spellCount: spell_count, + use_spellCount: true, + spellCount_operator: spell_count_operator + }) + end + end + { - trigger: { - type: 'spell', - subeventSuffix: '_CAST_START', - spellName: options[:spell], - use_exact_spellName: !!options[:exact], - use_genericShowOn: true, - event: 'Action Usable', - names: [], - realSpellName: options[:spell_name], - use_spellName: true, - spellIds: [], - genericShowOn: 'showOnCooldown', - subeventPrefix: 'SPELL', - unit: 'player', - use_track: true, - debuffType: 'HELPFUL' - } + trigger: trigger } end end diff --git a/public/weak_aura/triggers/action_usable_spec.rb b/public/weak_aura/triggers/action_usable_spec.rb new file mode 100644 index 0000000..7007dfc --- /dev/null +++ b/public/weak_aura/triggers/action_usable_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require './spec/spec_helper' + +RSpec.describe Trigger::ActionUsable do + it 'should accept spell_count and default to the equality operator' do + trigger = Trigger::ActionUsable.new(spell_count: 1).as_json[:trigger] + expect(trigger[:spellCount]).to eq(1) + expect(trigger[:spellCount_operator]).to eq('==') + end + + it 'should accept spell_count w/ gte operator' do + trigger = Trigger::ActionUsable.new(spell_count: '>= 1').as_json[:trigger] + expect(trigger[:spellCount]).to eq(1) + expect(trigger[:spellCount_operator]).to eq('>=') + end +end diff --git a/public/weak_aura/triggers/auras.rb b/public/weak_aura/triggers/auras.rb index c4f1ed0..f455bee 100644 --- a/public/weak_aura/triggers/auras.rb +++ b/public/weak_aura/triggers/auras.rb @@ -15,7 +15,7 @@ def initialize(**options) @options[:aura_names] = [@options[:aura_names]] unless @options[:aura_names].is_a?(Array) end - def as_json # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/AbcSize + def as_json # rubocop:disable Metrics/MethodLength data = { trigger: { useName: true, @@ -38,22 +38,24 @@ def as_json # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity, untrigger: [] } - if options[:remaining_time]&.positive? + rem, rem_operator = parse_count_operator(options[:remaining_time], '<=') + if rem data.deep_merge!({ trigger: { rem: options[:remaining_time].to_s, - remOperator: '<=', + remOperator: rem_operator, useRem: true } }) end - if options[:stacks]&.positive? + stacks, stacks_operator = parse_count_operator(options[:stacks], '>=') + if stacks data.deep_merge!({ trigger: { "useStacks": true, - "stacksOperator": '>=', - "stacks": options[:stacks].to_s + "stacksOperator": stacks_operator, + "stacks": stacks } }) end diff --git a/public/weak_aura/triggers/auras_spec.rb b/public/weak_aura/triggers/auras_spec.rb new file mode 100644 index 0000000..f9ba02d --- /dev/null +++ b/public/weak_aura/triggers/auras_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require './spec/spec_helper' + +RSpec.describe Trigger::Auras do + it 'should accept stacks and default to the gte operator' do + trigger = Trigger::Auras.new(aura_names: ['test'], stacks: 1).as_json[:trigger] + expect(trigger[:stacks]).to eq(1) + expect(trigger[:stacksOperator]).to eq('>=') + end + + it 'should accept stacks and with equality operator' do + trigger = Trigger::Auras.new(aura_names: ['test'], stacks: '== 1').as_json[:trigger] + expect(trigger[:stacks]).to eq(1) + expect(trigger[:stacksOperator]).to eq('==') + end +end diff --git a/public/whack_aura.rb b/public/whack_aura.rb index ce598b4..4e01250 100644 --- a/public/whack_aura.rb +++ b/public/whack_aura.rb @@ -44,6 +44,7 @@ def action_usable( if_missing: [], if_stacks: {}, on_show: {}, + spell_count: nil, title: nil, &block ) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2cb4c60..04c76b0 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -10,3 +10,5 @@ require 'optparse' require_relative '../public/weak_aura' require_relative '../public/whack_aura' +require 'debug' +require 'deep_merge'