mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-18 14:51:26 +02:00
The engine behind 'add more 2D tilesets / iso packs / 3D skins as products'. A pack is a self-contained render environment for a projection (topdown/iso/3d); because scenes are kind-based, the SAME pack renders both town and dungeon (interchangeable), and each maps to a catalog id (monetizable, entitlement-gated). - packRegistry.js: registerPack / packsForProjection / unlockedPacks (canUsePack) / activePackId (saved-if-unlocked else first unlocked) / setActivePack / activePackAssets. Per-projection active-pack selection, persisted. In-memory store fallback so it's testable under Node. - assetPacks: registers the 3 built-ins (roguelike-interior topdown, iso-dungeon, kenney-3d-characters) + activeIsoAssets()/activeThreeAssets() resolvers; RK.theme() now defaults to the active topdown pack. - isoRenderer + avatarVisuals (iso/3d character lookup) read the ACTIVE pack. - packRegistry loaded before assetPacks in tavern + game. Backward-compatible: one pack per projection resolves to today's defaults — nothing changes visually. Adding a pack now = registerPack(...) + assets + a catalog row. Tests: +5 (register/list, unlock filter, active/saved/fallback, refuse locked). Suite 58 suites / 419 tests green.
76 lines
3.4 KiB
JavaScript
76 lines
3.4 KiB
JavaScript
// Pack registry — the engine behind "add more 2D tilesets / iso packs / 3D skins as products".
|
|
//
|
|
// A PACK is a rich, self-contained render environment for a projection (topdown | iso | 3d). Because
|
|
// every scene (tavern OR dungeon) is kind-based (floor/wall/table/torch/monster…), the SAME pack
|
|
// renders both — packs are interchangeable across town and dungeon. Each pack maps 1:1 to a catalog
|
|
// entry (id/tier/threshold), so it's a monetizable product gated by entitlements.
|
|
//
|
|
// This module makes packs MULTI (like RK.THEMES already is for topdown) and adds active-pack
|
|
// selection per projection. Renderers ask for the active pack's assets; a picker lets an unlocked
|
|
// user switch. Adding a pack then = register(def) + drop assets + a catalog row.
|
|
(function (root) {
|
|
'use strict';
|
|
var RK = root.RK = root.RK || {};
|
|
|
|
// id -> { id, label, projection: 'topdown'|'iso'|'3d', kind, assets }
|
|
// `assets` is the render-kit payload for that projection (theme tiles / iso set / 3d models).
|
|
RK.PACK_REGISTRY = RK.PACK_REGISTRY || {};
|
|
|
|
// Storage: localStorage in the browser, an in-memory map under Node/tests.
|
|
var mem = {};
|
|
function store() {
|
|
try { if (root.localStorage) return root.localStorage; } catch (_) {}
|
|
return { getItem: function (k) { return k in mem ? mem[k] : null; }, setItem: function (k, v) { mem[k] = String(v); } };
|
|
}
|
|
function key(projection) { return 'rk_pack_' + projection; }
|
|
|
|
RK.registerPack = function (def) {
|
|
if (!def || !def.id || !def.projection) return null;
|
|
RK.PACK_REGISTRY[def.id] = def;
|
|
return def;
|
|
};
|
|
RK.getPackDef = function (id) { return (id && RK.PACK_REGISTRY[id]) || null; };
|
|
|
|
RK.packsForProjection = function (projection) {
|
|
var out = [];
|
|
for (var id in RK.PACK_REGISTRY) {
|
|
if (RK.PACK_REGISTRY[id].projection === projection) out.push(RK.PACK_REGISTRY[id]);
|
|
}
|
|
return out;
|
|
};
|
|
|
|
// Packs the user can actually use for a projection (free ones + entitlement-unlocked ones).
|
|
RK.unlockedPacks = function (projection) {
|
|
return RK.packsForProjection(projection).filter(function (p) {
|
|
return !RK.canUsePack || RK.canUsePack(p.id);
|
|
});
|
|
};
|
|
|
|
// The user's chosen pack if it's registered for this projection AND unlocked; otherwise the
|
|
// first unlocked pack; otherwise null.
|
|
RK.activePackId = function (projection) {
|
|
var saved = store().getItem(key(projection));
|
|
var def = saved && RK.PACK_REGISTRY[saved];
|
|
if (def && def.projection === projection && (!RK.canUsePack || RK.canUsePack(saved))) return saved;
|
|
var unlocked = RK.unlockedPacks(projection);
|
|
return unlocked.length ? unlocked[0].id : null;
|
|
};
|
|
|
|
RK.activePack = function (projection) { return RK.getPackDef(RK.activePackId(projection)); };
|
|
RK.activePackAssets = function (projection) {
|
|
var def = RK.activePack(projection);
|
|
return def ? def.assets : null;
|
|
};
|
|
|
|
// Select a pack (persisted per projection). Refused if unregistered or locked. Returns success.
|
|
RK.setActivePack = function (id) {
|
|
var def = RK.getPackDef(id);
|
|
if (!def) return false;
|
|
if (RK.canUsePack && !RK.canUsePack(id)) return false;
|
|
store().setItem(key(def.projection), id);
|
|
return true;
|
|
};
|
|
|
|
if (typeof module !== 'undefined' && module.exports) module.exports = RK;
|
|
})(typeof window !== 'undefined' ? window : this);
|