diff --git a/html/assets/cats/cat1-idle.png b/html/assets/cats/cat1-idle.png new file mode 100644 index 0000000..cdecebd Binary files /dev/null and b/html/assets/cats/cat1-idle.png differ diff --git a/html/assets/cats/cat2-idle.png b/html/assets/cats/cat2-idle.png new file mode 100644 index 0000000..6ff89d8 Binary files /dev/null and b/html/assets/cats/cat2-idle.png differ diff --git a/html/assets/cats/cat3-idle.png b/html/assets/cats/cat3-idle.png new file mode 100644 index 0000000..54b20a3 Binary files /dev/null and b/html/assets/cats/cat3-idle.png differ diff --git a/html/assets/cats/cat4-idle.png b/html/assets/cats/cat4-idle.png new file mode 100644 index 0000000..537b019 Binary files /dev/null and b/html/assets/cats/cat4-idle.png differ diff --git a/html/assets/cats/cat5-idle.png b/html/assets/cats/cat5-idle.png new file mode 100644 index 0000000..e0cfd21 Binary files /dev/null and b/html/assets/cats/cat5-idle.png differ diff --git a/html/assets/cats/cat6-idle.png b/html/assets/cats/cat6-idle.png new file mode 100644 index 0000000..ad3b6f4 Binary files /dev/null and b/html/assets/cats/cat6-idle.png differ diff --git a/html/js/render/catSprites.js b/html/js/render/catSprites.js new file mode 100644 index 0000000..a7b2b39 --- /dev/null +++ b/html/js/render/catSprites.js @@ -0,0 +1,44 @@ +(function (root) { + 'use strict'; + var RK = root.RK = root.RK || {}; + + // Pet Cats Pack (CC-0). Each idle strip is 10 frames of 50x50 laid out horizontally. + var FRAMES = 10, FW = 50, FH = 50, FRAME_MS = 150; + var CATS = ['cat1', 'cat2', 'cat3', 'cat4', 'cat5', 'cat6']; + var images = {}; + + function imgFor(id) { + if (!CATS.includes(id)) id = 'cat3'; + if (!images[id]) { + var im = new Image(); + im.src = 'assets/cats/' + id + '-idle.png'; + images[id] = im; + } + return images[id]; + } + + RK.catIds = function () { return CATS.slice(); }; + RK.randomCatId = function () { return CATS[Math.floor(Math.random() * CATS.length)]; }; + RK.isCat = function (id) { return CATS.indexOf(id) !== -1; }; + + // Draw an animated cat centered in its cell, feet near the bottom of the tile. Flips to face left. + RK.drawCatCanvas = function (ctx, e, cell, now) { + var im = imgFor(e.catSprite || 'cat3'); + if (!im.complete || !im.naturalWidth) return false; + var frame = Math.floor((now || 0) / FRAME_MS) % FRAMES; + var sx = frame * FW; + var size = cell * 1.25; // a touch bigger than a tile + var dx = e.x * cell + (cell - size) / 2; + var dy = e.y * cell + cell - size + cell * 0.12; + ctx.save(); + ctx.imageSmoothingEnabled = false; + if (e.facing === 'left') { + ctx.translate(dx + size, dy); ctx.scale(-1, 1); + ctx.drawImage(im, sx, 0, FW, FH, 0, 0, size, size); + } else { + ctx.drawImage(im, sx, 0, FW, FH, dx, dy, size, size); + } + ctx.restore(); + return true; + }; +})(window); diff --git a/html/js/render/tavernLife.js b/html/js/render/tavernLife.js index 7b09adb..556bc1e 100644 --- a/html/js/render/tavernLife.js +++ b/html/js/render/tavernLife.js @@ -78,7 +78,8 @@ return { minY: 3, maxY: rows - 2, minX: 1, maxX: cols - 2 }; } function catArea(cols, rows) { - return { minY: 1, maxY: rows - 1, minX: 1, maxX: cols - 2 }; + // The customer floor (in front of the bar) — not behind the counter, not the walls. + return { minY: 4, maxY: rows - 2, minX: 1, maxX: cols - 2 }; } // ---- Speech bubbles --------------------------------------------------------- @@ -220,8 +221,13 @@ })); } - // (No "cat": it used the char-goblin sprite, which read as a green monster stuck in the - // wall. Left out until there's an actual pet/critter sprite.) + // A tavern cat — a random pixel cat from the Pet Cats Pack that wanders the floor. + var catSpot = findFloor(4, rows - 4); + var cat = makeNPC('cat', 'cat', null, catSpot.x, catSpot.y, { + label: null, color: '#e8a060', role: 'cat', roamArea: catArea(cols, rows) + }); + cat.catSprite = (RK.randomCatId ? RK.randomCatId() : 'cat3'); + this.npcs.push(cat); }; TavernLife.prototype._pickTarget = function (npc, scene) { @@ -303,9 +309,10 @@ scene.entities.push({ id: npc.id, x: npc.x, y: npc.y, - kind: 'avatar', + kind: npc.role === 'cat' ? 'cat' : 'avatar', avatar: npc.avatar, appearance: npc.appearance, + catSprite: npc.catSprite || null, color: npc.color, char: npc.role === 'cat' ? 'c' : '@', facing: npc.facing, diff --git a/html/js/render/tileRenderer.js b/html/js/render/tileRenderer.js index ca08242..bf5f78b 100644 --- a/html/js/render/tileRenderer.js +++ b/html/js/render/tileRenderer.js @@ -188,6 +188,11 @@ ctx.stroke(); continue; } + // Tavern cat — a standalone animated sprite (Pet Cats Pack), not a char-atlas avatar. + if (e.kind === 'cat') { + drawEntityShadow(ctx, e.x * cell + cell / 2, e.y * cell + cell * 0.9, cell * 0.28, cell * 0.11); + if (window.RK && RK.drawCatCanvas && RK.drawCatCanvas(ctx, e, cell, now)) continue; + } // Character-like entity: soft ground shadow, then the sprite (or fallback circle). drawEntityShadow(ctx, e.x * cell + cell / 2, e.y * cell + cell * 0.92, cell * 0.34, cell * 0.14); // Roguelike character sprite, or premium animated skin; else the fallback circle. diff --git a/html/tavern.html b/html/tavern.html index ccb64ef..538e121 100644 --- a/html/tavern.html +++ b/html/tavern.html @@ -13,6 +13,7 @@ +