mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-18 06:41:27 +02:00
feat(packs): Medieval Town iso pack (2nd iso environment) + pack picker
Proves the packs-as-products loop end to end: - Copied Kenney Isometric Medieval Town wood tiles (floor/floor2/wall/window/ door/banner) into assets/kenney/iso-medieval/. - Registered 'iso-medieval' as a 2nd iso RENDER pack (its own tile geometry — Medieval tiles are shorter than the dungeon set; reuses the dungeon characters). Strong on architecture; no medieval furniture at this scale, so furniture kinds fall back to floor for now (shines most in the dungeon). - Catalog product: DEFAULT_CATALOG + migration 026, iso tier 2 / 15 credits. - PACK PICKER in the tavern: when a projection has >1 unlocked pack, a selector appears to switch live (setActivePack -> re-render). Uses ?unlock=1 to preview. So: switch Iso ★, and the pack picker lets you flip iso-dungeon <-> Medieval Town live. Adding the next pack = assets + registerPack + a catalog row. Suite 58/419 green.
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 765 B |
Binary file not shown.
|
After Width: | Height: | Size: 1004 B |
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@@ -294,6 +294,28 @@
|
||||
}
|
||||
};
|
||||
|
||||
// Second iso pack — Kenney Isometric Medieval Town (a coherent, DIFFERENT environment). Strong on
|
||||
// architecture (floor/walls/door/window/banner); no medieval furniture at this scale, so furniture
|
||||
// kinds fall back to floor for now. Reuses the dungeon-pack characters. Its tiles are shorter
|
||||
// (210x244) than the dungeon set, so its own tile geometry.
|
||||
RK.isoMedievalAssets = {
|
||||
pack: 'iso-medieval',
|
||||
avatar: 'char-villager',
|
||||
tile: { w: 84, h: 42, imageW: 84, imageH: 98 },
|
||||
tiles: {
|
||||
floor: 'assets/kenney/iso-medieval/floor.png',
|
||||
floor2: 'assets/kenney/iso-medieval/floor2.png',
|
||||
wall: 'assets/kenney/iso-medieval/wall.png',
|
||||
window: 'assets/kenney/iso-medieval/window.png',
|
||||
door: 'assets/kenney/iso-medieval/door.png',
|
||||
banner: 'assets/kenney/iso-medieval/banner.png',
|
||||
fallback: 'assets/kenney/iso-medieval/floor.png'
|
||||
},
|
||||
character: RK.isoAssets.character,
|
||||
directions: RK.isoAssets.directions,
|
||||
characters: RK.isoAssets.characters
|
||||
};
|
||||
|
||||
RK.threeAssets = {
|
||||
pack: 'kenney-3d-characters',
|
||||
models: {
|
||||
@@ -319,6 +341,7 @@
|
||||
if (RK.registerPack) {
|
||||
RK.registerPack({ id: 'roguelike-interior', label: 'Roguelike Interior', projection: 'topdown', kind: 'tiles', assets: RK.THEMES['roguelike-interior'] });
|
||||
RK.registerPack({ id: 'iso-dungeon', label: 'Isometric Dungeon', projection: 'iso', kind: 'tiles', assets: RK.isoAssets });
|
||||
RK.registerPack({ id: 'iso-medieval', label: 'Medieval Town', projection: 'iso', kind: 'tiles', assets: RK.isoMedievalAssets });
|
||||
RK.registerPack({ id: 'kenney-3d-characters', label: 'Animated 3D', projection: '3d', kind: 'skin', assets: RK.threeAssets });
|
||||
}
|
||||
// Active-pack resolvers the renderers read (fall back to the single default if the registry is absent).
|
||||
|
||||
@@ -49,6 +49,10 @@
|
||||
.modebtn { background: #0a0c0f; color: var(--text); border: 1px solid var(--line); font-weight: 500; }
|
||||
.modebtn.active { background: var(--accent); color: #08130a; border-color: var(--accent); }
|
||||
.modebtn.locked { opacity: 0.55; }
|
||||
#packbar { display: flex; gap: 6px; margin-bottom: 8px; align-items: center; }
|
||||
#packbar .packlabel { color: var(--muted); font-size: 12px; margin-right: 2px; }
|
||||
.packbtn { background: #0a0c0f; color: var(--text); border: 1px solid var(--line); font-size: 12px; padding: 3px 10px; border-radius: 5px; cursor: pointer; }
|
||||
.packbtn.active { background: var(--accent); color: #08130a; border-color: var(--accent); }
|
||||
#chatPanel { margin-top: 12px; }
|
||||
#chatLog { height: 160px; overflow-y: auto; border: 1px solid var(--line); border-radius: 4px;
|
||||
padding: 8px; background: #0a0c0f; font-size: 13px; line-height: 1.45; }
|
||||
@@ -72,6 +76,7 @@
|
||||
</div>
|
||||
|
||||
<div id="modebar" class="hidden"></div>
|
||||
<div id="packbar" class="hidden"></div>
|
||||
<div id="stage" class="hidden"></div>
|
||||
<p id="status" class="muted"></p>
|
||||
<p class="muted">Move with arrow keys or WASD. ★ modes are premium (credit unlock).</p>
|
||||
@@ -131,6 +136,7 @@
|
||||
var joinBtn = document.getElementById('joinBtn');
|
||||
var stageEl = document.getElementById('stage');
|
||||
var modebar = document.getElementById('modebar');
|
||||
var packbar = document.getElementById('packbar');
|
||||
var chatLog = document.getElementById('chatLog');
|
||||
var chatForm = document.getElementById('chatForm');
|
||||
var chatInput = document.getElementById('chatInput');
|
||||
@@ -219,6 +225,7 @@
|
||||
currentRenderer = r;
|
||||
draw();
|
||||
if (RK.attachZoom) { RK.attachZoom(stageEl); RK.applyZoom(stageEl); } // wheel/pinch zoom, all modes
|
||||
buildPackbar(); // show pack choices for this mode's projection
|
||||
var active = r.name || mode;
|
||||
setStatus(active === mode
|
||||
? 'Render mode: ' + active
|
||||
@@ -237,6 +244,39 @@
|
||||
modebar.appendChild(b);
|
||||
});
|
||||
updateModeButtons();
|
||||
buildPackbar();
|
||||
}
|
||||
|
||||
// The render projection a mode belongs to (topdown themes / iso packs / 3d skins).
|
||||
function projForMode(mode) {
|
||||
if (mode === 'iso') return 'iso';
|
||||
if (mode === '3d') return '3d';
|
||||
return 'topdown';
|
||||
}
|
||||
|
||||
// Pack picker: when the current projection has more than one UNLOCKED pack, show a selector
|
||||
// to switch between them. This is the "packs are products" engine made visible.
|
||||
function buildPackbar() {
|
||||
if (!packbar || !RK.unlockedPacks) return;
|
||||
packbar.innerHTML = '';
|
||||
var proj = projForMode(currentMode || 'tiles');
|
||||
var packs = RK.unlockedPacks(proj);
|
||||
if (packs.length < 2) { packbar.classList.add('hidden'); return; }
|
||||
packbar.classList.remove('hidden');
|
||||
var activeId = RK.activePackId(proj);
|
||||
var lbl = document.createElement('span');
|
||||
lbl.className = 'packlabel';
|
||||
lbl.textContent = 'Pack:';
|
||||
packbar.appendChild(lbl);
|
||||
packs.forEach(function (p) {
|
||||
var b = document.createElement('button');
|
||||
b.className = 'packbtn' + (p.id === activeId ? ' active' : '');
|
||||
b.textContent = p.label;
|
||||
b.addEventListener('click', function () {
|
||||
if (RK.setActivePack(p.id)) { buildPackbar(); setMode(currentMode); }
|
||||
});
|
||||
packbar.appendChild(b);
|
||||
});
|
||||
}
|
||||
function updateModeButtons() {
|
||||
Array.prototype.forEach.call(modebar.children, function (b) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
-- 026: add the Medieval Town isometric pack as a catalog product.
|
||||
-- A second iso environment (interchangeable across tavern + dungeon), sold at iso-tier: unlock by
|
||||
-- 15 lifetime credits OR premium (tier 2). Idempotent.
|
||||
INSERT INTO cosmetic_catalog (pack_id, label, kind, projection, tier, unlock_min_credits, grant_only, active, sort_order, metadata)
|
||||
VALUES ('iso-medieval', 'Medieval Town (Isometric)', 'render-pack', 'iso', 2, 15, false, true, 40, '{}'::jsonb)
|
||||
ON CONFLICT (pack_id) DO UPDATE
|
||||
SET label = EXCLUDED.label, projection = EXCLUDED.projection, tier = EXCLUDED.tier,
|
||||
unlock_min_credits = EXCLUDED.unlock_min_credits, active = true;
|
||||
@@ -25,6 +25,10 @@ const DEFAULT_CATALOG = Object.freeze({
|
||||
id: 'iso-dungeon', label: 'Kenney Isometric Dungeon', kind: 'render-pack',
|
||||
projection: 'iso', tier: 2, unlockMinCredits: 10, grantOnly: false, premium: true
|
||||
}),
|
||||
'iso-medieval': Object.freeze({
|
||||
id: 'iso-medieval', label: 'Medieval Town (Isometric)', kind: 'render-pack',
|
||||
projection: 'iso', tier: 2, unlockMinCredits: 15, grantOnly: false, premium: true
|
||||
}),
|
||||
'kenney-3d-characters': Object.freeze({
|
||||
id: 'kenney-3d-characters', label: 'Kenney Animated 3D Characters', kind: 'render-pack',
|
||||
projection: '3d', tier: 3, unlockMinCredits: 25, grantOnly: false, premium: true
|
||||
|
||||
Reference in New Issue
Block a user