feat: make items consumable #73

Open
Athemis wants to merge 85 commits from feature/consume-items into main
Owner

This PR makes items consumable.

Fixes #51

This PR makes items consumable. Fixes #51
Add consumable flag and gated consume overlay for items.
feat(packs): add consumable flag to suitable items
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
61990e0a72
This includes all potions, light sources and herbs
feat: track item uses for consumables and support multi-use items
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
332814534b
feat: track consumable uses and prevent zero-qty with remaining uses
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
95afb39733
feat: restore uses to max when refilling empty item stacks
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
10e17839cb
overlays
refactor: prepare item change handling for future improvements
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
e5936c90a5
refactor: change pre-update-item hook from TypeScript to JavaScript
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
cc0dd6a689
test: cover preUpdateItem hook edge cases
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
61908b7fc7
feat: switch consumable uses to max/spent and add hook coverage
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
e2a9535ef5
Merge branch 'main' into feature/consume-items
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
8023cb10dc
refactor: sorting icons use shared utility function
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
2e9497d72c
style(ui): indicate "consume" by hand icon
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
0ddfadb1a2
feat: add uses column for consumables
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
3e491140d6
style: rename remaining uses variable to avoid confusion
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
54dbf57dc8
feat: add consume target selection for effects
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
85f46f401d
refactor: remove uses column and related flags from equipment inventory
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
837c4dba40
list display

- currently no equipment item has a limited amount of uses -> drop the
  column to not waste space
fix(tests): adjust render-chat globals stubs
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
5ca78f54b7
feat: add consume effect type selector and default to roll
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
d1c6ff0df5
- Add allowTargetChange flag for consume effects with checkbox UI
- Display target info and allow changing target via chat messages
- Implement undo button to revert item consume with permission checks
- Disable buttons after effect applied or undone
- Add related localization strings and styles for chat components
Merge remote-tracking branch 'origin/main' into feature/consume-items
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
ba4a7d9042
refactor(consume): move effect apply into dialog and simplify chat card
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
5ee425f836
refactor: move item description enrichment into a utility function
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
92a8ec6fb5
prompt

Allow users to edit the consume effect formula when selecting a target
token or actor,
and pass the updated formula through the consume effect workflow.
Include item icon and name in the prompt header and improve form layout.
feat(consume): enhance dialog with icons and short formula label
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
a53cec0454
toggle

Set dialog width to 590px to enhance layout and toggle visibility
of the custom modifier input based on selection for better UX.
for layout
fix(ui): add fixed-width class to profile icons for alignment
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
4f9cf2568d
Merge branch 'main' into feature/consume-items
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
e4f76d7c12
Athemis self-assigned this 2026-01-14 16:14:11 +00:00
feat: add damage effect type support for consumables and HP updates
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
744cac45f6
feat(packs): add healing effects to appropriate consumable items
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
8f360953f6
fix(ui): add "No effect" option to consume effect type selectors
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
cc78462541
feat: add support for consume ActiveEffect type with stacking
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
e2927007fe
- Introduce "activeEffect" as a consume effect type option
- Add stacking and stack key configuration for consume effects
- Inject stacking fields into ActiveEffect item effect config UI
- Implement application of consume ActiveEffects on target actor
- Update item sheet logic to handle activeEffect consume type and apply
  effects
- Add localization entries for stacking modes and activeEffect type
feat(active-effect): add consume-driven ActiveEffect stacking and v13
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
8b7f338236
sheet parts
fix(consume): refine consume effect config, labels, and item sheet
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
3ab0a9b4f9
layout
fix(consume): move consume options into dedicated item section
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
cc657265a8
feat(consume): expire consume effects on combat end
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
06c077233f
- add item effect flag to mark combat-end expiry
- remove flagged actor effects on deleteCombat (GM-only)
- expose UI toggle in active effect config
feat(consume): add confirmation dialog for consume effects needing
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
e9d2d0b7d6
active combat
feat(consume): confirm combat-end expiry outside combat
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
5bb13da77c
Merge remote-tracking branch 'origin/main' into feature/consume-items
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
36d7bd20a7
feat(packs): add consumable effects for combat potions
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
b9e7548740
- add active effects for Kampf-, Zauber- und Zieltrank (expire on combat
  end)
- mark Fackel as consumable
- replace consumable flag with usable/consumedOnUse across schema, UI,
  and logic
- migrate item packs to new fields (incl. combat potion effects + torch)
- update usage strings to neutral “use/effect” wording in de/en
refactor(i18n): remove unused consume strings
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
81d9e0ad62
feat(consume): add configurable duration formula and units to consume
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
b15ffdb057
effects
Sets round time to 5 s as per DS4 rule book.
fix(tests): adjust for usable and consumedOnUse flags of items
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
503244eb69
Athemis force-pushed feature/consume-items from 503244eb69
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
to 5dcfd7ec13
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
2026-01-27 10:35:43 +00:00
Compare
Athemis force-pushed feature/consume-items from 5dcfd7ec13
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
to 97de41c15f
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
2026-01-27 10:45:04 +00:00
Compare
feat(effects): add active-effect expiry engine and combat reconciliation
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
42ea815f63
- introduce effect-expiry engine with combat start/end handling
  - set combatId/start fields on combat start and honor expireOnCombatEnd without duration
  - ignore non-transfer item effects in expiry processing
  - register expiry hooks and document new ds4.effectExpiry flags
  - move expire-on-combat-end toggle to the Duration tab
refactor(effects): add fast path check for actors with no effects
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
303a86744c
Helps to minimize backfill amount
fix(hooks): backfill seconds effects for token actors
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
035de17343
- include unlinked token actors from scenes in backfill
  - requeue using update results instead of UUID lookups
  - centralize requeue logic and speed up actor effect checks
Athemis force-pushed feature/consume-items from 035de17343
Some checks failed
ci/woodpecker/pr/checks Pipeline failed
to 597764ab3b
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
2026-01-27 16:10:06 +00:00
Compare
chore(hooks): log backfill duration and warn on slow runs
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
23d0d5b1bd
fix(hooks): stabilize effect expiry outside combat
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
eb71afab5a
- convert rounds to seconds outside combat without losing rounds
- avoid turn-based rounding on combat end
- document new expiry flags
refactor(hooks): simplify effect expiry state flow
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
26035f948c
- document flag transitions
- derive rounds outside combat and reconcile flags
- prefer rounds-based remaining time on combat end
test(hooks): add effect-expiry hook coverage
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
11dfd437c4
Adds local stubs and tests for backfill, seconds expiry, combat conversions, and logging
Merge remote-tracking branch 'origin/main' into feature/consume-items
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
8004a09651
Athemis added this to the 3.3.0 milestone 2026-02-05 12:46:35 +00:00
First-time contributor

Review summary

  • Big feature set: consumables (usable + consumedOnUse + uses + consumeEffect) incl. UI + chat feedback.
  • Adds a centralized ActiveEffect expiry engine (seconds queue + combat start/end reconciliation, expireOnCombatEnd).
  • Local checks on the PR branch: pnpm format:check, pnpm lint, pnpm test

Blockers

  • None found.

Major

  • Very large scope (91 files, ~4k LOC): consumables + expiry engine + ActiveEffect sheet refactor + pack migrations.
    For future work, consider splitting into 2–3 PRs to make review and bisecting easier.
  • Expiry engine is effectively a new core subsystem: the GM-only gating + queue approach looks solid.
    I’d suggest adding 2–3 sentences to the PR description/docs clarifying:
    • Which effects are intended to be covered (consume-driven only vs. any actor effect with duration).
    • Expected rounding semantics for seconds↔rounds conversion (e.g. floor when converting remaining seconds to rounds).

Minor / nit

  • src/apps/actor/base-sheet.js: the consume flow is now quite large; long-term it might be worth extracting into a helper (e.g. src/utils/consume.ts) to keep the sheet lean.
  • For roll/heal/damage consume effects, an empty formula currently results in “no effect” (since hasEffect depends on formula). That’s fine, but a small UI warning could prevent confusion when type is set but formula is empty.

Questions

  • Is expireOnCombatEnd meant to apply only to consume item effects, or more broadly to actor effects in general? (It’s currently wired via flags.ds4.consumeEffect.)
  • On the last stack element you end up with quantity=0 and uses.spent=usesMax (not 0). Is that intentional as an “empty/depleted” signal? Looks consistent, just confirming.

Suggested tests

  • Consumable with uses.max=3, quantity=2, consumedOnUse=true: consume repeatedly → uses decrements, when uses reach max then qty-- and uses reset; final unit ends at qty=0 / depleted.
  • Consume-driven ActiveEffect with durationFormula (rounds/seconds) + expireOnCombatEnd=true: apply effect → start combat → end combat → verify expire/reconversion behavior.

Areas reviewed

  • src/apps/actor/base-sheet.js (consume flow + target prompt + ActiveEffect application)
  • src/hooks/pre-update-item.js (prevent qty=0 while uses remain)
  • src/hooks/effect-expiry.js (queue + combat reconciliation)
  • spec/hooks/effect-expiry.spec.ts, spec/hooks/pre-update-item.spec.ts (test coverage)
## Review summary - Big feature set: **consumables** (`usable` + `consumedOnUse` + `uses` + `consumeEffect`) incl. UI + chat feedback. - Adds a centralized **ActiveEffect expiry engine** (seconds queue + combat start/end reconciliation, `expireOnCombatEnd`). - Local checks on the PR branch: `pnpm format:check`, `pnpm lint`, `pnpm test` ✅ ### Blockers - None found. ### Major - **Very large scope (91 files, ~4k LOC):** consumables + expiry engine + ActiveEffect sheet refactor + pack migrations. For future work, consider splitting into 2–3 PRs to make review and bisecting easier. - **Expiry engine is effectively a new core subsystem:** the GM-only gating + queue approach looks solid. I’d suggest adding 2–3 sentences to the PR description/docs clarifying: - Which effects are intended to be covered (consume-driven only vs. any actor effect with duration). - Expected rounding semantics for seconds↔rounds conversion (e.g. `floor` when converting remaining seconds to rounds). ### Minor / nit - `src/apps/actor/base-sheet.js`: the consume flow is now quite large; long-term it might be worth extracting into a helper (e.g. `src/utils/consume.ts`) to keep the sheet lean. - For `roll/heal/damage` consume effects, an empty formula currently results in “no effect” (since `hasEffect` depends on `formula`). That’s fine, but a small UI warning could prevent confusion when `type` is set but `formula` is empty. ### Questions - Is `expireOnCombatEnd` meant to apply **only** to consume item effects, or more broadly to actor effects in general? (It’s currently wired via `flags.ds4.consumeEffect`.) - On the last stack element you end up with `quantity=0` and `uses.spent=usesMax` (not `0`). Is that intentional as an “empty/depleted” signal? Looks consistent, just confirming. ### Suggested tests - Consumable with `uses.max=3`, `quantity=2`, `consumedOnUse=true`: consume repeatedly → uses decrements, when uses reach max then qty-- and uses reset; final unit ends at qty=0 / depleted. - Consume-driven ActiveEffect with `durationFormula` (rounds/seconds) + `expireOnCombatEnd=true`: apply effect → start combat → end combat → verify expire/reconversion behavior. ### Areas reviewed - `src/apps/actor/base-sheet.js` (consume flow + target prompt + ActiveEffect application) - `src/hooks/pre-update-item.js` (prevent qty=0 while uses remain) - `src/hooks/effect-expiry.js` (queue + combat reconciliation) - `spec/hooks/effect-expiry.spec.ts`, `spec/hooks/pre-update-item.spec.ts` (test coverage)
Merge branch 'main' into feature/consume-items
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
0237556090
- Move consume logic from src/apps/actor/base-sheet.js to src/apps/actor/consume-flow.js
- Keep behavior unchanged and delegate _onConsumeItem to new module
- Remove consume-related helper methods from actor sheet to reduce class size
- Add tests for consume flow in spec/apps/consume-flow.spec.ts
- Document consume flow and helper responsibilities with JSDoc/comments in
  src/apps/actor/consume-flow.js
fix(consume): warn when formula-based effects have no formula
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
a15037ef69
- show a hint in item usage properties for roll/heal/damage without formula
- warn on every use click while still allowing item use
- add de/en i18n strings for hint and runtime warning
- cover missing-formula warning behavior in consume-flow spec
feat(active-effect): show combat-end expiry on actor effects
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
5b24506820
- display a read-only "Expire at combat end" indicator in actor effect duration tab
- render indicator only when expireOnCombatEnd is true
test(consume): document and verify depleted last-stack state
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
e3e958e6ae
- document that last stack consumption keeps uses.spent at uses.max when quantity reaches 0
- add consume-flow spec asserting quantity=0 with uses.spent=max for final stack
test(consume): expand consume-flow and expiry coverage
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
7c56866c95
- add consume-flow tests for damage, selected targets, consumedOnUse=false, stack stacking, and
  duration unit conversion
- add effect-expiry test to ensure non-transfer item effects are ignored
chore(migration): add migration 012 for consume-model item backfill
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
c294d06ea2
- migrate legacy loot/equipment items from ds4 equipment source refs
- backfill usable/consumedOnUse/consumeEffect only for untouched items
- copy consume-related active effects from source items when missing
- process world items, world actors, unlinked token actors, and world compendiums
Athemis changed title from WIP: feat: make items consumable to feat: make items consumable 2026-02-06 15:42:12 +00:00
Author
Owner

@claw-bot review

@claw-bot review
First-time contributor

Ack — ich schaue mir das an.

Ack — ich schaue mir das an.
First-time contributor

Quick review (claw-bot)

CI: Success (ci/woodpecker/pr/checks)

Highlights

  • Consume flow looks solid: quantity/uses handling (incl. depleted marker), permission checks for actor updates, clear chat summary, and inventory-part re-render only.
  • ActiveEffect consume-copy: nice stacking model (replace vs stack) + durationFormula evaluation at consume time + flags normalized.
  • Effect expiry engine: GM-only, queue-based for seconds effects, explicit combat start/end reconciliation; good approach to avoid full-world scans.
  • Migration 012: conservative backfill, respects user edits, uses core.sourceId/_stats.compendiumSource and caches pack lookups.

Nits / things to double-check

  • Formula consume types with missing formula: you warn but still allow “apply”; later Roll(undefined) will error (caught). Consider disabling the action or forcing formula entry when type in {roll/heal/damage}.
  • Ensure Roll evaluation API matches the Foundry version target (some versions prefer evaluate({async:true})).
  • Small HTML safety: uses label in chat summary (item.system.uses.label) isn’t escaped.

Overall: LGTM for merge; main risk area is the expiry engine complexity, but tests + GM-only gating help.

Quick review (claw-bot) ✅ CI: Success (ci/woodpecker/pr/checks) Highlights - Consume flow looks solid: quantity/uses handling (incl. depleted marker), permission checks for actor updates, clear chat summary, and inventory-part re-render only. - ActiveEffect consume-copy: nice stacking model (replace vs stack) + durationFormula evaluation at consume time + flags normalized. - Effect expiry engine: GM-only, queue-based for seconds effects, explicit combat start/end reconciliation; good approach to avoid full-world scans. - Migration 012: conservative backfill, respects user edits, uses core.sourceId/_stats.compendiumSource and caches pack lookups. Nits / things to double-check - Formula consume types with missing formula: you warn but still allow “apply”; later Roll(undefined) will error (caught). Consider disabling the action or forcing formula entry when type in {roll/heal/damage}. - Ensure Roll evaluation API matches the Foundry version target (some versions prefer evaluate({async:true})). - Small HTML safety: uses label in chat summary (item.system.uses.label) isn’t escaped. Overall: LGTM for merge; main risk area is the expiry engine complexity, but tests + GM-only gating help.
First-time contributor

Full review (claw-bot)

CI: Success (ci/woodpecker/pr/checks)

Overall

  • Big feature, but the implementation is surprisingly disciplined: clear separation of concerns (consume-flow vs sheet glue), good test coverage, and the new expiry engine avoids world-wide scans in the hot path.

Highlights

  • Consume flow (src/apps/actor/consume-flow.js)
    • Quantity/uses logic looks consistent, incl. the “depleted marker” (qty=0 + spent=max) for the last stack.
    • Good UX: target picker + optional formula override, permission checks before actor updates, and a concise chat summary.
    • ActiveEffect copy path: stacking (replace vs stack) + per-consume durationFormula is a nice model.
  • Effect expiry engine (src/hooks/effect-expiry.js)
    • GM-only, queue-driven for seconds-based effects; combat start/end reconciliation is centralized.
    • Good guardrails: recursion suppression via options, backfill once on ready, and duplicate combat-end handling guarded.
  • Migration 012
    • Conservative backfill (tries not to overwrite user edits), supports core.sourceId + legacy compendiumSource, caches pack lookups.

Issues / suggestions

  1. Item description enrichment: secrets regression
  • src/utils/enrich-description.js forces secrets: false.
  • Previously the item sheet enriched with secrets: this.item.isOwner (so owners could see secret blocks). With the new helper, owners will no longer see them.
    Suggestion: make enrichItemDescription(item, { secrets }) configurable, or default to secrets: item.isOwner.
  1. Uses sorting key likely broken
  • Actor list displays {{item.usesRemaining}} (computed in _prepareContext).
  • But header uses data-data-path="system.usesRemaining".
    Unless system.usesRemaining exists, sorting by remaining uses won’t work.
    Suggestion: either
    • change header path to usesRemaining, OR
    • put the derived value into item.system.usesRemaining for display-only sorting.
  1. HTML safety in chat summary
  • item.system?.uses?.label is interpolated into HTML without escaping in the chat message.
    Suggestion: wrap with foundry.utils.escapeHTML(...).
  1. Effect expiry: rounding edge (seconds → rounds)
  • buildSecondsToRoundsUpdate uses Math.floor(secondsRemaining / roundTime) and sets turns=1 when rounds=0.
    This is probably fine (avoids giving extra time), but it can shorten effects near boundaries.
    Suggestion: confirm expected semantics for “< 1 round remaining” and add/adjust a test if needed.
  1. Minor UX polish
  • rollable-image.hbs overlay alt text remains “dice overlay” even when using the hand icon.
    Suggestion: allow passing overlayAlt (optional).
  1. CONFIG.time.roundTime = 5
  • src/hooks/init.js sets CONFIG.time.roundTime = 5.
    If DS4 intends 5s rounds: great. If not, this will affect any time/round conversions across the system.

Suggested test scenarios (manual)

  • Item with uses.max=3, quantity=2, consumedOnUse=true: consume repeatedly → uses decrement, then qty-- and uses reset; last unit ends at qty=0/spent=max.
  • Consume-driven ActiveEffect with durationFormula (rounds/seconds) + expireOnCombatEnd: apply → start combat → end combat → verify expiry/reconversion.

Verdict

  • LGTM once (1) secrets enrichment and (2) uses sorting path are addressed; (3) HTML escaping is a low-effort hardening.
Full review (claw-bot) ✅ CI: Success (ci/woodpecker/pr/checks) Overall - Big feature, but the implementation is surprisingly disciplined: clear separation of concerns (consume-flow vs sheet glue), good test coverage, and the new expiry engine avoids world-wide scans in the hot path. Highlights - Consume flow (`src/apps/actor/consume-flow.js`) - Quantity/uses logic looks consistent, incl. the “depleted marker” (qty=0 + spent=max) for the last stack. - Good UX: target picker + optional formula override, permission checks before actor updates, and a concise chat summary. - ActiveEffect copy path: stacking (replace vs stack) + per-consume durationFormula is a nice model. - Effect expiry engine (`src/hooks/effect-expiry.js`) - GM-only, queue-driven for seconds-based effects; combat start/end reconciliation is centralized. - Good guardrails: recursion suppression via options, backfill once on ready, and duplicate combat-end handling guarded. - Migration 012 - Conservative backfill (tries not to overwrite user edits), supports core.sourceId + legacy compendiumSource, caches pack lookups. Issues / suggestions 1) Item description enrichment: secrets regression - `src/utils/enrich-description.js` forces `secrets: false`. - Previously the item sheet enriched with `secrets: this.item.isOwner` (so owners could see secret blocks). With the new helper, owners will no longer see them. Suggestion: make `enrichItemDescription(item, { secrets })` configurable, or default to `secrets: item.isOwner`. 2) Uses sorting key likely broken - Actor list displays `{{item.usesRemaining}}` (computed in `_prepareContext`). - But header uses `data-data-path="system.usesRemaining"`. Unless `system.usesRemaining` exists, sorting by remaining uses won’t work. Suggestion: either - change header path to `usesRemaining`, OR - put the derived value into `item.system.usesRemaining` for display-only sorting. 3) HTML safety in chat summary - `item.system?.uses?.label` is interpolated into HTML without escaping in the chat message. Suggestion: wrap with `foundry.utils.escapeHTML(...)`. 4) Effect expiry: rounding edge (seconds → rounds) - `buildSecondsToRoundsUpdate` uses `Math.floor(secondsRemaining / roundTime)` and sets `turns=1` when rounds=0. This is probably fine (avoids giving extra time), but it can shorten effects near boundaries. Suggestion: confirm expected semantics for “< 1 round remaining” and add/adjust a test if needed. 5) Minor UX polish - `rollable-image.hbs` overlay alt text remains “dice overlay” even when using the hand icon. Suggestion: allow passing overlayAlt (optional). 6) CONFIG.time.roundTime = 5 - `src/hooks/init.js` sets `CONFIG.time.roundTime = 5`. If DS4 intends 5s rounds: great. If not, this will affect any time/round conversions across the system. Suggested test scenarios (manual) - Item with `uses.max=3`, `quantity=2`, `consumedOnUse=true`: consume repeatedly → uses decrement, then qty-- and uses reset; last unit ends at qty=0/spent=max. - Consume-driven ActiveEffect with durationFormula (rounds/seconds) + expireOnCombatEnd: apply → start combat → end combat → verify expiry/reconversion. Verdict - LGTM once (1) secrets enrichment and (2) uses sorting path are addressed; (3) HTML escaping is a low-effort hardening.
First-time contributor

Addendum (claw-bot)

One additional critical issue found by the subagent:

⚠️ High: Consume formula rolls have no roll data

  • src/apps/actor/consume-flow.js: new Roll(resolvedFormula) and duration formula roll are evaluated without actor/item roll data.
  • Formulas with @-references (e.g., @abilities.str.value, @item.level) will not resolve correctly.
  • Affects both the consume formula and the ActiveEffect durationFormula.

Suggestion:

const rollData = targetActor.getRollData();
// merge item data if needed
const roll = new Roll(resolvedFormula, rollData);
await roll.evaluate({ async: true }); // v13 compatibility

Same applies to the durationFormula evaluation when applying ActiveEffects.

Addendum (claw-bot) One additional critical issue found by the subagent: **⚠️ High: Consume formula rolls have no roll data** - `src/apps/actor/consume-flow.js`: `new Roll(resolvedFormula)` and duration formula roll are evaluated without actor/item roll data. - Formulas with `@`-references (e.g., `@abilities.str.value`, `@item.level`) will not resolve correctly. - Affects both the consume formula and the ActiveEffect durationFormula. Suggestion: ```js const rollData = targetActor.getRollData(); // merge item data if needed const roll = new Roll(resolvedFormula, rollData); await roll.evaluate({ async: true }); // v13 compatibility ``` Same applies to the durationFormula evaluation when applying ActiveEffects.
Merge remote-tracking branch 'origin/main' into feature/consume-items
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
54418bf973
fix(consume): resolve @-references in consume and duration formulas
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
09537c2dfd
Formulas containing @-references (e.g. @attributes.body.total) were passed to `new Roll()` without
substitution, causing silent failures.

Use `DS4Actor.replaceFormulaData()` to resolve placeholders against the target actor's system data
before rolling. Unresolvable references now show a user-facing warning instead of failing silently.
perf(effect-expiry): reconcile only new actor on mid-combat combatant add
All checks were successful
ci/woodpecker/pr/checks Pipeline was successful
14bad78854
Extract reconcileActorsForCombat from onCombatStart so the createCombatant hook can reconcile a
single actor instead of iterating all combatants. This avoids redundant work and preserves the
combat-end guard.
Merge remote-tracking branch 'origin/main' into feature/consume-items
All checks were successful
renovate/stability-days Not a Renovate PR - check skipped
ci/woodpecker/pr/auto-approve-renovate-checks Pipeline was successful
ci/woodpecker/pr/checks Pipeline was successful
2161ff8f12
fix(actor-sheet): correct sort path for remaining uses column
All checks were successful
renovate/stability-days Not a Renovate PR - check skipped
ci/woodpecker/pr/auto-approve-renovate-checks Pipeline was successful
ci/woodpecker/pr/checks Pipeline was successful
1b5d9be808
fix(actor-sheet): preserve input focus during quantity edits
All checks were successful
renovate/stability-days Not a Renovate PR - check skipped
ci/woodpecker/pr/auto-approve-renovate-checks Pipeline was successful
ci/woodpecker/pr/checks Pipeline was successful
032dc14ab4
Re-render the inventory tab only when quantity crosses the zero boundary, since that is the only
transition affecting the consume overlay. Other quantity changes (e.g. 3→5) no longer replace the
DOM, so the number input keeps focus.
Merge remote-tracking branch 'origin/main' into feature/consume-items
All checks were successful
renovate/stability-days Not a Renovate PR - check skipped
ci/woodpecker/pr/auto-approve-renovate-checks Pipeline was successful
ci/woodpecker/pr/checks Pipeline was successful
261685f273
chore(assets): Ensure proper line ending in hand.svg
Some checks failed
renovate/stability-days Not a Renovate PR - check skipped
ci/woodpecker/pr/auto-approve-renovate-checks Pipeline was successful
ci/woodpecker/pr/checks Pipeline failed
d1b77c8994
Athemis force-pushed feature/consume-items from d1b77c8994
Some checks failed
renovate/stability-days Not a Renovate PR - check skipped
ci/woodpecker/pr/auto-approve-renovate-checks Pipeline was successful
ci/woodpecker/pr/checks Pipeline failed
to 9838b39acc
All checks were successful
renovate/stability-days Not a Renovate PR - check skipped
ci/woodpecker/pr/auto-approve-renovate-checks Pipeline was successful
ci/woodpecker/pr/checks Pipeline was successful
2026-02-09 13:31:55 +00:00
Compare
All checks were successful
renovate/stability-days Not a Renovate PR - check skipped
Required
ci/woodpecker/pr/auto-approve-renovate-checks Pipeline was successful
ci/woodpecker/pr/checks Pipeline was successful
Required
Details
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feature/consume-items:feature/consume-items
git switch feature/consume-items
Sign in to join this conversation.
No description provided.