Kaysser Kayyali 2f6acc0da1 v0.3.0: strip combat HUD; integrate with combat-hud-hub
- Deleted scripts/hud.js, scripts/event-translation.js, styles/hud.css,
  templates/hud.html.
- Removed mod.api.getHud/openHud/closeHud/buildHudUpdatePayload exports.
- Removed hudPosition setting (moved to combat-hud-hub).
- Added hub integration: at ready, if combat-hud-hub is installed,
  register a 'pinned-achievements' section. The chatBubble listener
  now also pushes entries into that section via hub.api.pushFeedEntry.
- Soft-dep on combat-hud-hub (optional); popover still works without
  the hub.
- Tests: 57/57 passing covering sections A-G (rule engine, catalog,
  awarding, hooks wiring, hub integration, graceful degradation).
2026-06-22 12:46:57 -04:00

It's Achievable (its-achievable)

Foundry VTT module: achievements engine, custom rules, rewards, achievement wall, and combat HUD. Consumes the generic Foundry hook facade from foundry-hooks-lib and the encounter state from battle-focus.

Status

v0.1.0 — first release as a standalone repo. Sourced from battle-focus/scripts/{achievements.js, achievement-wall.js, custom-achievements-app.js, hud.js, achievement-rules.js} at battle-focus v0.5.0-alpha.12 (99cf757 on Gitea).

Stage 2 of the Foundry module split. The achievement code is now an independent module with its own:

  • Settings namespace (its-achievable.*)
  • Module id (its-achievable, lowercase kebab)
  • Achievements catalog and rule engine
  • HUD subscription to hooks-lib's v0.2.0 envelope stream
  • Chat-bar popover and form application

battle-focus retains its own copies of these files until Stage 3 of the split ships (which will delete the copies and add its-achievable as a soft dependency of battle-focus).

Dependencies

  • foundry-hooks-lib (≥0.2.0) — provides the Foundry event stream via the generic {ts, hook, args} envelope facade. See hooks-lib/docs/HOOK_CONTRACT.md.
  • battle-focus (soft) — provides the encounter singleton via game.modules.get("battle-focus").api.getActiveEncounter().

If either is missing, its-achievable logs a warning and degrades gracefully (achievements inactive).

Public API (on game.modules.get("its-achievable").api)

const api = game.modules.get("its-achievable").api;

// Catalog
api.getAchievementCatalog();
api.getActorAchievements(actorKey);

// Rule engine
api.evaluateRulesForEvent(event, encounter, actor, targetActor);
api.evaluateRulesForEncounterEnd(encounter);
api.evaluateRulesForCareerUpdate(career);

// Awarding
api.processEventForAchievements(event, encounter);
api.evaluateCombatAchievements(stats);
api.evaluateCareerAchievements(pcName, career, encounterId);
api.awardAchievement(actorKey, achievementId, encounterId);

// Wall + HUD
api.renderAchievementWall(actorId, actorName, opts);
api.getAchievementWallProgress(actorId, actorName);
api.renderAchievementPopover(unlocks, viewerName);
api.buildHudUpdatePayload(encounter, event);
api.openCustomAchievementsApp();

Settings namespace

Old (battle-focus.*) New (its-achievable.*)
achievementsByActor achievementsByActor
customAchievementRules customAchievementRules
enableRewards enableRewards

No automatic migration. Per the Stage 2 decision, users with existing worlds will need to re-create their custom rules and re-trigger any past achievement awards. Documented in CHANGELOG.

Tests

npm test    # smoke test, no Foundry needed

tests/PLAN.md describes what we test and what we don't. Real-Foundry integration testing happens when battle-focus migrates in Stage 3 and the existing E2E suite exercises the moved code.

Architecture notes

  • Hooks-lib first. its-achievable subscribes to foundry-hooks-lib's envelope stream. Combat lifecycle, document CRUD, dnd5e rolls — all via hooksLib.api.subscribeMany({...}). No direct Hooks.on(...) calls.
  • Encounter via battle-focus's API. its-achievable does not import battle-focus's encounter.js directly; it calls battle-focus.api.getActiveEncounter() to resolve the singleton.
  • HUD derives its payload locally. buildHudUpdatePayload lives in its-achievable (moved from battle-focus). It derives the HUD state from hooks-lib envelopes, not from a battle-focus broadcast.

Maintained by Kaysser Taylor + Hermes

Description
Hax's Tools � achievements + rewards + wall + HUD (battle-focus slice 2)
Readme 229 KiB
Languages
JavaScript 93.3%
HTML 6.7%