Commit graph

80 commits

Author SHA1 Message Date
GaboGG
93c0f85acd v0.14.22 - Survival-first priority chain (simulation-backed, 10/10 survival)
AGY built a full 60-round arena simulator (hv-battle-sim.py) using
the user's actual gear/stats and ran 10 iterations:

  Original: 0/10 survived (0%)
  Improved: 10/10 survived (100%)

Critical changes from simulation findings:
  - Health items + Cure moved to TOP of priority chain (before skills)
  - Dynamic HP threshold: 60% when 7+ mobs, normal threshold otherwise
  - SP threshold raised from 55% to 60% for Spark safety buffer
  - Mana maintenance raised to prevent spell lockout
  - AoE crowd control prioritized for 4+ mobs

Full report in agy_sim_output.txt
2026-07-28 06:19:02 -04:00
GaboGG
229d81b86c v0.14.21 - Show purchasable (buy) items in gearSummary
- logGearSummary() now shows 3 sources: 🟢 equipped, 📦 stored, 🛒 purchasable
- Highlights buy items NOT already in armory inventory
- Summary: Gear DB: 746 total (7 🟢 equipped, 305 📦 stored, 434 🛒 purchasable)
- Works with manual HV.scrapeGear() call on Purchase page
2026-07-27 20:54:16 -04:00
GaboGG
5286f66b3e v0.14.20 - Fix Purchase page scraper: const dynjs_eqstore + screen=purchase
- Bug 1: Purchase tab URL is 'screen=purchase', not 'screen=buy'
- Bug 2: dynjs_eqstore is declared with 'const', not 'var', so it doesn't
  create a window property. getHVEquipStore() now also checks bare names
  which works with @grant none and the IIFE scope chain
- Fixed price parsing: purchase table has 2 td cells (label + price),
  previously required >3 cells so prices were always empty
- Names with 🔺 prefix are cleaned before storage
2026-07-27 20:48:27 -04:00
GaboGG
f2e8ce536a v0.14.19 - Add Bazaar Buy page scraper + 3-source analysis
- scrapeBuyPage() scrapes equipment for sale from Bazaar Buy tab
  (URL: ss=am&screen=buy or ss=bi), marks as source='buy'
- Stores merge with existing: buy items don't overwrite equipped/armory
- Auto-detect routing handles buy page URL patterns
- analyze_gear.py updated with 3-source output:
  🟢 Equipped = currently worn
  📦 Stored = in armory inventory
  🛒 For Sale = purchasable from Bazaar
- Shows level limits (Lv155 + 15 = Lv170 cap), prices where available
- Re-scrape after visiting Buy tab to include market items
2026-07-27 20:38:09 -04:00
GaboGG
94ab29a82c v0.14.18 - Spirit Stance burst toggle for 7+ mob Rending Blow
- When 7+ enemies and OC >= 60: toggles Spirit Stance ON before casting
  Rending Blow, then toggles OFF after one skill
- Uses 3-state flag: press1=toggleON, press2=castSkill, press3=toggleOFF
- Only triggers on normal (non-panic) Rending Blow — step 0e emergency
  skill still fires without spirit to avoid delay
- Resets on battle init and when conditions change
2026-07-27 20:14:21 -04:00
GaboGG
f2f296274c v0.14.17 - Faster weapon skills: lower skillOC to 60, threat to 70%, single-monster emergency
- skillOC default lowered from 75 to 60 — with 300ms Q debounce, it took
  ~6 presses to go from 50 to 70 OC (too slow against IWBTH enemies)
- Threat threshold lowered from 85% (102px) to 70% (84px) — triggers
  earlier when monsters have high SP bars
- Added single-monster emergency: if ANY enemy >90% SP, fire skills
  even without 2+ monsters (catches the lone special attacker)
- Step 0d high-threat check now fires for solitary imminent threats too
2026-07-27 20:05:47 -04:00
GaboGG
4aff813f01 v0.14.16 - Armory scraper now scavenges full store for all items
- Previously only scraped items visible in the current filter tab
  (had to visit each tab: New, Two-Handed, Light, Heavy, etc.)
- Now also scans the full dynjs_equip store for ALL items in your
  account (305 total) — every filter tab's worth of data at once
- Category guessed from tooltip type (Cloth, Light, Heavy, Weapon, etc.)
- One visit to the Armory page + HV.scrapeGear() = complete inventory
2026-07-27 15:58:02 -04:00
GaboGG
d95409026f v0.14.15 - Retry gear scrape until dynjs_equip store loads
- equip-UID.js loads asynchonously after document-end, so dynjs_equip
  might not exist when init() first runs
- Now retries up to 10 times (500ms apart, 5 seconds total) waiting for
  the store to populate before scraping
- Added HV.gearStore() to check whether the store is loaded
- If store never loads, falls back to name/ID scrape without stats
2026-07-27 15:51:22 -04:00
GaboGG
329e9403b4 v0.14.14 - V2 gear scraper: reads from HV in-memory JS store (no hovers)
- Previously: tried equips.set() + 300ms delays + popup_box polling
  which was fragile, async, and often saved stats to wrong slots
- Now: reads window.dynjs_equip / dynjs_eqstore which contains ALL
  item data pre-loaded on page load (name, quality, full tooltip HTML)
- Uses DOMParser to parse the embedded .eq HTML into structured stats
  (type, level, condition, burden, ADB, mit, attributes, etc.)
- Zero hover, zero delays, zero popup_box interaction — instant stats
- Works on Character Equipment page AND Armory pages simultaneously
- Removed triggerAllTooltips() and captureAllTooltips() — obsolete
2026-07-27 15:46:36 -04:00
GaboGG
28457202ba v0.14.13 - Clean scrape flow: basic data on page load, stats via captureAllTooltips
- scrapeCharacterEquip() now only reads names/IDs from DOM slots (no tooltip
  popup reading — that was attaching wrong stats to wrong slots)
- captureAllTooltips() now calls logGearSummary() instead of autoScrapeGear()
  so the tooltip stats aren't wiped by a re-scrape
- Workflow: visit Character Equipment page, then run HV.captureTooltips()
  to populate full stats with 300ms hover delay per item
2026-07-27 15:35:30 -04:00
GaboGG
ce09755fa8 v0.14.12 - Add captureAllTooltips() with async hover-to-popup delay
- captureAllTooltips() iterates each equipment slot, calls equips.set()
  to trigger the tooltip popup, waits 300ms for the DOM to update,
  then reads and saves the full stat block from #popup_box
- Catches 'Popup Box' default text vs real tooltip
- Saves stats directly to localStorage gear DB
- Exposed as HV.captureTooltips() for console use
- For best results: visit Character Equipment page, run HV.captureTooltips()
2026-07-27 15:31:06 -04:00
GaboGG
c632c13818 v0.14.11 - Fix DOM selector: onmouseover is on inner div, not .eqb parent
- .eqb parent has onclick and structure, but the onmouseover with
  equips.set() and the item name text are on a CHILD div within .eqb
- Fixed scrapeCharacterEquip() and triggerAllTooltips() to query
  :scope > div[onmouseover] inside each .eqb slot
- Fixed debugScrapeGear() diagnostic to show inner div content
2026-07-27 15:28:58 -04:00
GaboGG
992c6acc38 v0.14.10 - Add debugScrapeGear() diagnostic + HV.gearDebug()
- New debugScrapeGear() function checks DOM structure:
  - Whether #eqsb exists and its slot count
  - Whether #equiplist exists
  - Whether #popup_box exists and its content
  - Whether equips global is available
- Exposed as HV.gearDebug() for console use
2026-07-27 15:16:03 -04:00
GaboGG
a7a304f5d4 v0.14.9 - Rewrite gear scraper with correct DOM selectors
- Character Equipment page (?s=Character&ss=eq): reads #eqsb > .eqb
  divs with onmouseover='equips.set(ID,...)' for item names and IDs
- triggerAllTooltips() calls equips.set() for each item to populate
  the #popup_box tooltip, then parses full stat blocks (ADB, damage,
  mitigation, attributes, burden, interference, condition)
- Armory Organize page: reads #equiplist table rows with
  onmouseover='hover_equip(ID)' and checkbox values
- Reads right-side #equipinfo preview for condition and stats
- Modify detail page: reads full stat tables
2026-07-27 15:12:28 -04:00
GaboGG
6167df57b4 v0.14.8 - Expose gear API via HV.gear() / HV.gearSummary()
- Added to window.HV public API: gear(), gearSummary(), scrapeGear()
- Now accessible from console as HV.gear(), HV.gearSummary()
- Also keep getGearDB() and logGearSummary() directly available
2026-07-27 15:05:52 -04:00
GaboGG
d60233d205 v0.14.7 - Gear scraper: captures full equipment stats to localStorage
- New module: gear-scraper.js (10K, 200+ lines)
- Auto-scrapes Character page (?ss=ch) for equipped gear with full stat
  blocks: ADB, damage, crit, parry, evade, burden, mitigation, stats
- Auto-scrapes Armory inventory page for all items with IDs, names,
  categories, potency, durability
- Scrapes Modify detail page for one item's complete stat table
- Stores everything in localStorage['hvunified_geardb']
- ParseHV.advice() now includes gear info
- Public API: getGearDB() returns full gear database
2026-07-27 14:55:48 -04:00
GaboGG
91d53e0f1c v0.14.6 - High-threat weapon skills step 0d (before buffs/items)
- Added step 0d in Veteran: if 2+ monsters have SP >85%, fire weapon
  skills BEFORE buffs, items, debuffs, or anything else
- Only needs OC >= 20 (one skill's worth, builds fast from basic attacks)
- Rending Blow > Shatter Strike > Great Cleave, targeting most dangerous monster
- Formerly: weapon skills were at step 11, after all buffs and items.
  Enemies got multiple turns to special attack during the buff-up phase.
  Now dangerous monsters get shut down immediately.
2026-07-27 14:49:50 -04:00
GaboGG
9af0237754 v0.14.5 - Conservative debuffs: Imperil only on bosses/rares or 5+ mobs
- Imperil no longer casts on every 2-mob wave (Estoc's native Penetrated
  Armor handles armor-breaking for <5 targets)
- Imperil threshold raised from MP>20% to MP>35%
- Imperil now only fires on bosses/rares OR 5+ monster waves (Grindfest)
- Weaken now only on high-threat (SP>85%) or bosses, not every 3-mob wave
- Formerly: Imperil on 2+ mobs, Weaken on 3+ mobs — drained MP fast
2026-07-27 14:46:39 -04:00
GaboGG
0a41f9d7c5 v0.14.4 - Sort buff loop by cost (cheapest-first when no channeling)
- Regular buff loop in all 3 tiers now collects candidates then sorts
  by MP cost ascending (cheapest first) when no channeling, or
  descending (most expensive first) when channeling is active
- Previously just iterated BUFF_PRIORITY declaration order (Haste →
  Spark → Heartseeker → Regen → Absorb → Shadow Veil) which wasn't
  cost-ordered
- _reason now shows 'buff' (cheapest first) or 'chBuff' (most expensive)
2026-07-27 14:45:00 -04:00
GaboGG
48e5103655 v0.14.3 - Add reason tags to castInitialBuffs (init/initCh)
- castInitialBuffs now tags actions with _reason='init' (cheapest-first
  sort, no channeling) or _reason='initCh' (most-expensive-first,
  channeling already charged)
- Makes the log clearly show which buff path fired
2026-07-27 14:43:40 -04:00
GaboGG
205f1cd631 v0.14.2 - Double-check cooldown via img opacity:0.5 in hasReadySpell
- Some quickbar/deprecated elements retain onclick even when on cooldown
  if the cooldown indicator is only visual (img opacity:0.5) not structural
- Now also checks img.btqi / img style.opacity !== '0.5'
- This catches cases where the parent div has onclick but the inner image
  is visually dimmed (game cooldown)
2026-07-27 14:08:48 -04:00
GaboGG
7ae6e4855f v0.14.1 - Fix cooldown checks: spells on cooldown no longer selected
- Added hasReadySpell() that checks DOM for onclick attribute (off cooldown)
- Buff loop (all tiers) now uses hasReadySpell instead of hasSpell
- Cure/Full-Cure now checks cooldown before casting
- Channeling target selection checks cooldown
- castInitialBuffs checks cooldown
- Imperil/Weaken debuffs check cooldown
- hasSpell() kept for knowledge checks (do we know this spell at all)
- Prevents silent failures where on-cooldown spells are selected but
  can't actually be cast (btsd[onclick] fails to find them)
2026-07-27 14:05:25 -04:00
GaboGG
c9ad92e28d v0.14.0 - Major strategy overhaul from agy research report
BUG FIXES (P0):
- Spark of Life SP safety: consume spirit items when SP < 55% BEFORE
  buffs, Cure, or any other action (both Adept and Veteran)
- Spirit Stance safety auto-disable: auto-toggle OFF if SP drops below 60%
- useItem() fallback: auto_ slot IDs now lookup by onmouseover attribute
  (on-cooldown items without DOM id were silently failing)
- setTimeout targeting race: removed 50ms delay in castTargetSpell/useSkill
  (was causing targeting failures with fast Q-repeat)
- maxBuffDur pre-seeded with L150+ baseline values (haste=80, heartseeker=120,
  sparklife=50, etc.) so fill-level scoring works from first turn

STRATEGY (P1):
- Channeling waste eliminated for 2H physical builds: no more Fiery Blast
  fallback — let channeling expire on a basic attack (Domino Strike +
  Penetrated Armor do more damage)
- Weapon skill thresholds lowered from 5+ to 3+ enemies (IWBTH survivability)
- Expanded debuffs: Imperil on any 2+ mobs, Weaken on high-threat targets
  (not just bosses anymore)
- Domino Strike optimal targeting: findOptimalDominoTarget() picks center
  monsters to max splash coverage (up to 2 targets each side)

NEW FEATURES:
- Domino Strike splash positioning algorithm added to all tiers
- Full _reason tags on every action return for decision tracing
- agy research report saved at hermes_report.md (554 lines)
2026-07-27 14:01:05 -04:00
GaboGG
467e844aae v0.13.34 - Explicit action names in log + _reason tags per decision
- Log now shows spell names/skill names/item names explicitly:
  '[HV] ▶ spell → Haste (self)' instead of '▶ spell → monster 0'
  '[HV] ▶ spell → Fiery Blast → monster 1 (ch fallback)'
  '[HV] ▶ item → Spirit Draught (self) (sp55)'
- Added _reason tag to every action return: 'hp60', 'sp55', 'buff',
  'ch score 81', 'threat', 'oc', 'boss', 'stun', 'mana', 'gem',
  'mystic', 'fallback', 'dmg'
- Now you can see exactly WHY each action was chosen on every turn
2026-07-27 13:35:45 -04:00
GaboGG
949aab915f v0.13.33 - Persist maxBuffDur to localStorage (no more warm-up)
- maxBuffDur now saved to localStorage['hvunified_maxBuffDur'] on every
  new high observation and loaded on STATE init
- Survives page reloads: Heartseeker's 180-turn max stays learned
- Removed the unreliable-max fallback hack — no longer needed
- First Q press of a fresh session has accurate fill-level scores
  for all buffs that were observed in previous sessions
2026-07-27 13:26:51 -04:00
GaboGG
b8e2e945ec v0.13.32 - Fix channeling waste when maxBuffDur hasn't learned true cap
- When maxBuffDur gap (max - current) is < 10, the cap is unreliable
  (first observation mid-battle, not at full duration)
- In that case, skip the fill-level formula entirely
- Only suggest a buff for channeling if it actually needs refresh
  (dur <= minTurns from BUFF_PRIORITY)
- Once maxBuffDur learns the true cap (after a fresh cast), the
  normal fill-level scoring takes over correctly
2026-07-27 13:22:15 -04:00
GaboGG
533fad252a v0.13.31 - Enhanced battle logging for deep diagnostics
- Q-key log now shows: HP, current MP, MP%, SP%, OC, monster count,
  buff durations, and per-monster SP bar levels (spBars: 0:120 1:95 ...)
- High-threat detection logs a red '⚠ HIGH THREAT' warning
- Emergency skill usage at low OC logs an orange '⚠ emergency' warning
- Now you can paste me the console log and I'll see exact threat levels,
  why skills did/didn't fire, and what the state was before each action
2026-07-27 13:13:59 -04:00
GaboGG
b5a5c3df54 v0.13.30 - Fix spirit item detection, add threat-based targeting
- Fix: items on cooldown (no id attr) were invisible to parser
  Spirit Draught/Potion on cooldown couldn't be auto-consumed
- Fix: spiritPotionSP raised from 30% to 60%
- New: parse monster SP bar widths into STATE.monsterSp[]
- New: findDangerousMonster() — targets highest SP bar monster
- New: hasHighThreat() — true if 2+ monsters >85% SP (about to special)
- Weapon skills now fire on high-threat even without full OC
- Basic attacks prefer dangerous monsters in all tiers
2026-07-27 13:07:39 -04:00
GaboGG
b6d78067ce v0.13.29 - Aggressive SP management for Spark of Life survival
- Raised spiritPotionSP threshold from 30% to 60%
- Added Spirit item check at step 2b in Adept and Veteran tiers:
  if SP < 55%, consume Spirit Draught/Potion immediately
- Spark of Life costs 50% max SP when triggered. If SP is too low,
  Spark fails and you die. Keeping SP above 55% ensures Spark always
  has enough fuel to save you from a killing blow on IWBTH
2026-07-27 11:08:16 -04:00
GaboGG
e1269cd3fe v0.13.28 - Fix difficulty advice: recommend IWBTH for Veteran, not PFUDOR
- Changed Veteran suggestion from PFUDOR (20x) to IWBTH (15x)
- PFUDOR is now only suggested at Master tier (L300+)
- Since you're already on IWBTH, the banner won't show anymore
  (current == suggested, so no nag)
2026-07-27 10:04:02 -04:00
GaboGG
ad2ff4b482 v0.13.27 - Remove auto Spirit Stance toggle from all tiers
- Removed toggle_spirit calls from Novice, Adept, and Veteran
  strategy functions (was auto-toggling stance at OC 60+)
- Spirit Stance is now fully manual (press spirit button yourself)
- Spirit Gem auto-consumption remains (fills SP when dropped)
- Kept the config guards (CFG.autoSpirit) for future opt-in
2026-07-26 15:26:51 -04:00
GaboGG
1a4f9a80a3 v0.13.26 - Stricter Q debounce: reset timer after each successful action
- executeAction now sets STATE._lastActionTime after dispatching
- Q handler checks this instead of a local var
- When an action executes, the Q debounce resets so the next Q press
  waits the full 300ms before attempting again
- Prevents stale-state queueing when game hasn't processed the
  previous action yet (was sending 12+ 'skill' commands to the
  game, though only 1 actually ran)
2026-07-26 15:23:04 -04:00
GaboGG
8c21920d4b v0.13.25 - Debounce Q key to prevent spam on held-key repeat
- Added _lastQTime debounce (300ms) to the Q key handler
- Holding Q now fires at most ~3 actions per second instead
  of ~20, preventing duplicate actions from stale state reads
- The previous issue: 6 identical Haste casts, then 8 identical
  Spark casts, then 12 identical Heartseeker casts — all from
  state not yet updated by the game
2026-07-26 15:17:27 -04:00
GaboGG
86968f531c v0.13.24 - Fix castInitialBuffs sorting (was most-expensive-first, not cheapest-first)
- castInitialBuffs was sorting by mpCost descending (b.mpCost - a.mpCost)
- So it picked Spark of Life (70) before Haste (41), defeating the
  whole purpose of casting cheapest-first to proc channeling
- Changed to ascending sort (a.mpCost - b.mpCost): Haste first, then
  Spark, etc.
2026-07-26 15:16:07 -04:00
GaboGG
0aa268b3f9 v0.13.23 - Fix affordable MP check using actual current MP from DOM
- Was using vrhd (HP element) instead of vrm (current MP)
- Now reads #vrm textContent for current MP value
- Simply compares mpCost > curMp to skip unaffordable spells
- This prevents the infinite Heartseeker loop when you
  don't have enough MP even though the buff is a good target
2026-07-26 15:09:38 -04:00
GaboGG
31799a7261 v0.13.22 - Cache base MP costs at battle start (dynamic, not hardcoded)
- Removed SPELL_COSTS hardcoded table
- Base MP costs are now read from the magic pane's onmouseover
  tooltip at battle init and cached in STATE._baseMpCosts
- Cache is populated during parseBattleState() and persists
  for the entire battle, avoiding channeling's 1-MP display
- Cache resets on new battle, so level-ups or stat changes
  are picked up when starting a new arena
2026-07-26 15:08:23 -04:00
GaboGG
80fc77600a v0.13.21 - Dynamic base cost read + affordable MP check for channeling
- Removed hardcoded SPELL_COSTS table (was brittle)
- Now reads base MP cost directly from the magic pane's
  onmouseover tooltip (always shows true base cost, unaffected
  by channeling's 1-MP display or Mana Conservation)
- Added affordable check: skip spells where base cost exceeds
  current MP, even though channeling would make it cost 1
- The game's native MP check (shown by "You do not have enough")
  checks against base cost, not channeling-reduced cost
2026-07-26 15:05:20 -04:00
GaboGG
e20fe0495c v0.13.20 - Add SPELL_COSTS fallback for Mana Conservation-reduced MP costs
- Some spells show mp=1 in the DOM due to high Mana Conservation
  proficiency, making fill-level scoring produce near-zero values
- Now: if mpCost < 5, look up the base cost from SPELL_COSTS table
- This ensures Heartseeker (141 MP) scores correctly even when the
  DOM shows it costing 1 MP
2026-07-26 15:01:49 -04:00
GaboGG
e914c08475 v0.13.19 - Fix on-cooldown spells missing from spellsKnown
- Magic pane query used '.btsd[onclick]' which excludes
  on-cooldown spells (opacity:0.5, no onclick attribute)
- Heartseeker was invisible to hasSpell() during its cooldown
  period, which is exactly when channeling procs from it
- Changed to '.btsd' with onmouseover fallback
2026-07-26 14:31:38 -04:00
GaboGG
49c7ce9cab v0.13.18 - Add channeling score debug logging
- Logs the top candidate from findBestChannelingTarget() on every Q press
- Shows: spell, score, dur, maxDur, mpCost, emptiness%
- Next time channeling doesn't fire on a buff, the console will show
  the actual computed scores so we can see what's happening
2026-07-26 14:12:48 -04:00
GaboGG
e74c97f87a v0.13.17 - Fix fill-level scoring when maxBuffDur hasn't been learned
- When maxBuffDur for a buff equals its current duration (first observation
  in a battle), the emptiness was 0 — making the script think all buffs
  are full and skipping them
- Now: if maxDur <= current dur, assume a minimum of 30 turns as the max
- This ensures buffs like Shadow Veil at 8/8 are treated as 8/30 (73% empty)
  instead of 8/8 (0% empty)
2026-07-26 14:08:50 -04:00
GaboGG
3f865ee6fd v0.13.16 - Fix buff duration parsing for set_infopane_effect raw turn count
- The regex only matched 'X turns remaining' text format
- Buffs like channeling and freshly cast spells use the raw third
  parameter of set_infopane_effect('Name','desc',X) without 'turns rem'
- These were defaulting to 50 turns, making all fresh buffs appear
  as having 50 turns when they really had 0-5
- Added fallback to parse the last numeric argument of the function call
2026-07-26 14:05:29 -04:00
GaboGG
25ea8b4543 v0.13.15 - Fix stale Mystic Gem state, add debug logging to Q press
- Mystic Gem usage now tracked with STATE._mysticUsed flag
  Prevents re-triggering the gem check after it's been consumed
  (stale STATE.itemsKnown was causing infinite 'item → p' loops)
- Flag resets on new battle initialization
- Added buff durations + channeling status to Q-key console output
  Shows: ch=true/false mp=X% oc=X buffs: heartseeker=47 haste=24 ...
2026-07-26 14:01:48 -04:00
GaboGG
23f00450be v0.13.14 - Fix observer crash, raise channeling threshold to 30
- Removed call to undefined finalizeBattleLog() that was spamming
  ReferenceErrors and potentially corrupting the MutationObserver
- Raised channeling score threshold from 5 to 30: now only picks a
  buff for channeling if it's at least 30% empty on a 100-MP spell
  or 60% empty on a 50-MP spell
- Spark at 30/60 turns (50% empty, score 44) now falls to cheap
  damage fallback instead of wasting channeling
2026-07-26 13:53:01 -04:00
GaboGG
5f9297435d v0.13.13 - Fix channeling detection from effects pane (not just log)
- Channeling detection was ONLY from battle log text entries
- When log entries scroll off (new round starts), the 'gains the effect'
  message is lost and STATE.channeling stays false permanently
- Added effects pane check: if channeling.png is visible, force channeling=true
- This fixes the root cause of channeling being ignored when the log
  has scrolled past the proc message
- Also bumped version properly this time
2026-07-26 13:49:20 -04:00
GaboGG
c0c626c0bf v0.13.12 - Fill-level scoring for channeling consumption
- Score = emptiness_ratio × mp_cost
- emptiness_ratio = (max_dur - current) / max_dur
- max_dur is tracked dynamically per buff in STATE.maxBuffDur
  (learned from the highest duration seen per icon)
- Freshly cast buffs score ~0 regardless of MP cost
- A 100-MP buff at 1/90 turns scores 98.9
- A 40-MP buff at 25/50 turns scores 20.0
- A 140-MP buff at 71/80 turns scores 15.75
- Removed the Heartseeker >50 skip (no longer needed - fill level handles it)
2026-07-26 13:44:17 -04:00
GaboGG
37b502aa65 v0.13.11 - Score threshold for channeling buff consumption
- Reverted the >10 turns cutoff (wrong approach)
- Instead, added a minimum score threshold of 5 to the best candidate
- At score >= 5: a 50-MP spell with <9 turns, a 140-MP spell with <27 turns
- Below score 5: falls through to cheap damage spell fallback
- This prevents recasting fresh buffs while still considering all spells
2026-07-26 13:39:32 -04:00
GaboGG
e13b4c5206 v0.13.10 - Only consume channeling on buffs that need refresh (<10 turns)
- findBestChannelingTarget: skip buffs with >10 remaining turns
- When all buffs are fresh, falls through to cheap damage spell
  instead of wasting channeling on a nearly-full duration buff
- This prevents recasting Spark of Life at 15 turns just because
  its score happens to be highest among all fresh buffs
2026-07-26 13:38:31 -04:00
GaboGG
71da9b1214 v0.13.9 - Fix ReferenceError: battleLog is not defined
- The vitals observer check 'battleLog && !battleLog.summary' referenced
  an undefined variable, throwing on every observer tick
- Simplified to just check for pane_completion existence
- This crash may have been interfering with state parsing on the observer
2026-07-26 13:35:12 -04:00
GaboGG
47c42ea5fe v0.13.8 - Actually bump version in config.js and header.user.js
- config.js: 0.13.0 -> 0.13.8
- header.user.js: 0.12.0 -> 0.13.8 (was never bumped past 0.12.0)
- Now the @version tag in the userscript header matches the internal VERSION
2026-07-26 13:31:09 -04:00