Diablo2D — Shadows of Tristram: complete browser ARPG

- Isometric canvas renderer (depth-sorted, FOV/fog, additive lighting)
- 3 classes x 20 skills, 4 acts x 4 floors + boss lairs, torment I-X
- Diablo-style loot: rarities, affix tiers, 14 legendaries, vendor, stash
- Rogue camp with 6 NPCs: Charsi/Akara/Kashya/Cain/Gheed/storage
- NPC quest chain (accept -> hunt -> turn in) with rewards & gating
- Procedural WebAudio SFX + generative music, EN/VI localization
- Saves, settings, waypoints, hardcore mode, PWA manifest
- 93-assertion headless suite + browser E2E via CDP
This commit is contained in:
2026-08-23 06:59:36 +00:00
commit fc1fa2d51e
42 changed files with 11784 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
/* ============================================================
* Diablo2D — fov.js : raycast visibility & fog of war
* ============================================================ */
'use strict';
window.D2 = window.D2 || {};
(function (D2) {
const RAY_COUNT = 160;
/**
* Update world.visible / world.explored from (cx, cy) within radius.
* world must expose: w, h, transparent(x,y), visible(Uint8), explored(Uint8)
*/
function compute(world, cx, cy, radius) {
const { w, h } = world;
world.visible.fill(0);
const r2 = radius * radius;
const mark = (x, y) => {
if (x < 0 || y < 0 || x >= w || y >= h) return;
const i = y * w + x;
world.visible[i] = 1;
world.explored[i] = 1;
};
mark(cx, cy);
for (let i = 0; i < RAY_COUNT; i++) {
const ang = (i / RAY_COUNT) * Math.PI * 2;
const dx = Math.cos(ang), dy = Math.sin(ang);
let x = cx + 0.5, y = cy + 0.5;
for (let d = 0; d < radius; d += 0.5) {
x += dx * 0.5; y += dy * 0.5;
const tx = x | 0, ty = y | 0;
if (tx < 0 || ty < 0 || tx >= w || ty >= h) break;
const ddx = x - cx - 0.5, ddy = y - cy - 0.5;
if (ddx * ddx + ddy * ddy > r2) break;
mark(tx, ty);
if (!world.transparent(tx, ty)) break;
}
}
}
D2.fov = { compute };
})(window.D2);