Spaces:
Running
Running
Cities pill: rebuild bundle + carry Medieval City & Mountain Stronghold assets (LFS)
Browse filesPicks up the new Cities sandbox pill (two skins, decoded clickable catalogues)
and curates each pack's runtime sheets + premade-exterior layers into web/assets.
City-pack PNGs are LFS/Xet-tracked per HF's binary-storage policy.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- .gitattributes +2 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_a-night_effect.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_b-pennant_flags.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_c-shadows.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_d-props_on_city_walls.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_e-city_walls.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_f-chimneys.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_g-turrets_and_annexes.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_h-roof.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_i-props.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_j-stairs_and_terraces_2.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_k-walls_2.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_l-stairs_and_terraces_1.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_m-walls_1.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_n-fences.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_o-floor.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Props/Props.png +3 -0
- web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Tileset/Tileset.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_a-shadows.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_b-human.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_c-stairs.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_d-doors_windows.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_e-snow_2.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_f-battlements_and_rooftops.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_g-bridges.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_h-props.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_i-structures_built_into_cliffs.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_j-snow_1.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_k-jagged_cliffs.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_l-bg.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Props/Props.png +3 -0
- web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Tileset/Tileset.png +3 -0
- web/mapSandbox.js +338 -65
.gitattributes
CHANGED
|
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/**/*.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/**/*.png filter=lfs diff=lfs merge=lfs -text
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_a-night_effect.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_b-pennant_flags.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_c-shadows.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_d-props_on_city_walls.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_e-city_walls.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_f-chimneys.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_g-turrets_and_annexes.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_h-roof.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_i-props.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_j-stairs_and_terraces_2.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_k-walls_2.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_l-stairs_and_terraces_1.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_m-walls_1.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_n-fences.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Premade/Premade_Exterior/Separate_Layers/Premade_Exterior_o-floor.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Props/Props.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets/Tileset/Tileset.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_a-shadows.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_b-human.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_c-stairs.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_d-doors_windows.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_e-snow_2.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_f-battlements_and_rooftops.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_g-bridges.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_h-props.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_i-structures_built_into_cliffs.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_j-snow_1.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_k-jagged_cliffs.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Premade/Premade_Exterior/_Separate_Layers/Premade_Exterior_l-bg.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Props/Props.png
ADDED
|
Git LFS Details
|
web/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets/Tileset/Tileset.png
ADDED
|
Git LFS Details
|
web/mapSandbox.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
| 1 |
// ../auto-battler/src/render/chunkedMap.js
|
| 2 |
function createChunkedMap(pixi, host, config) {
|
| 3 |
const { Application, Assets, Sprite, Container, Texture, Rectangle, RenderTexture } = pixi;
|
| 4 |
-
const
|
| 5 |
-
const
|
| 6 |
-
const CHUNKPX =
|
| 7 |
const BG = config.background ?? "#69636f";
|
| 8 |
const Z_DEFAULT = config.zoomDefault ?? 1;
|
| 9 |
const Z_MIN = config.zoomMin ?? 1 / 32;
|
|
@@ -17,10 +17,10 @@ function createChunkedMap(pixi, host, config) {
|
|
| 17 |
const DETAIL_BUDGET = config.detailBudget ?? 1;
|
| 18 |
const MACRO_BUDGET = config.macroBudget ?? 8;
|
| 19 |
const bounds = config.bounds ? {
|
| 20 |
-
x0: config.bounds.x0 *
|
| 21 |
-
y0: config.bounds.y0 *
|
| 22 |
-
x1: config.bounds.x1 *
|
| 23 |
-
y1: config.bounds.y1 *
|
| 24 |
tx0: config.bounds.x0,
|
| 25 |
ty0: config.bounds.y0,
|
| 26 |
tx1: config.bounds.x1,
|
|
@@ -47,12 +47,12 @@ function createChunkedMap(pixi, host, config) {
|
|
| 47 |
const pinch = { on: false, dist: 0 };
|
| 48 |
const handlers = {};
|
| 49 |
const emit = () => listeners.forEach((fn) => fn(getSnapshot()));
|
| 50 |
-
const getSnapshot = () => ({ seed, zoom, cx: Math.round(camera.x /
|
| 51 |
function tex(source, c, r) {
|
| 52 |
const k = source.uid + ":" + c + "," + r;
|
| 53 |
let t = texCache.get(k);
|
| 54 |
if (!t) {
|
| 55 |
-
t = new Texture({ source, frame: new Rectangle(c *
|
| 56 |
texCache.set(k, t);
|
| 57 |
}
|
| 58 |
return t;
|
|
@@ -67,16 +67,16 @@ function createChunkedMap(pixi, host, config) {
|
|
| 67 |
return t;
|
| 68 |
}
|
| 69 |
function makeChunk(cx, cy) {
|
| 70 |
-
const x0 = cx *
|
| 71 |
const tmp = new Container();
|
| 72 |
const add = (source, c, r, tx, ty) => {
|
| 73 |
const sp = new Sprite(tex(source, c, r));
|
| 74 |
-
sp.x = tx *
|
| 75 |
-
sp.y = ty *
|
| 76 |
tmp.addChild(sp);
|
| 77 |
return sp;
|
| 78 |
};
|
| 79 |
-
const res = config.bake({ cx, cy, x0, y0, seed, chunk:
|
| 80 |
const rt = RenderTexture.create({ width: CHUNKPX, height: CHUNKPX, autoGenerateMipmaps: true, scaleMode: "nearest" });
|
| 81 |
rt.source.minFilter = "linear";
|
| 82 |
rt.source.mipmapFilter = "linear";
|
|
@@ -84,12 +84,12 @@ function createChunkedMap(pixi, host, config) {
|
|
| 84 |
rt.source.updateMipmaps();
|
| 85 |
tmp.destroy({ children: true });
|
| 86 |
const sprite = new Sprite(rt);
|
| 87 |
-
sprite.x = x0 *
|
| 88 |
-
sprite.y = y0 *
|
| 89 |
return { sprite, rt, meta: res.meta ?? null, live: res.live ?? null };
|
| 90 |
}
|
| 91 |
function chooseMacroLevel(z) {
|
| 92 |
-
return Math.max(0, Math.min(MACRO_LEVEL_MAX, Math.round(Math.log2(MACRO_TEXEL_PX / (
|
| 93 |
}
|
| 94 |
function makeMacroChunk(L, mcx, mcy) {
|
| 95 |
const step = 1 << L, t0x = mcx * MCHUNK * step, t0y = mcy * MCHUNK * step;
|
|
@@ -110,9 +110,9 @@ function createChunkedMap(pixi, host, config) {
|
|
| 110 |
const t = Texture.from(cv);
|
| 111 |
t.source.scaleMode = "linear";
|
| 112 |
const sprite = new Sprite(t);
|
| 113 |
-
sprite.x = t0x *
|
| 114 |
-
sprite.y = t0y *
|
| 115 |
-
sprite.width = sprite.height = MCHUNK * step *
|
| 116 |
return { sprite, tex: t };
|
| 117 |
}
|
| 118 |
function coverZoom() {
|
|
@@ -169,10 +169,10 @@ function createChunkedMap(pixi, host, config) {
|
|
| 169 |
let c0 = Math.floor((camera.x - halfW) / CHUNKPX) - 1, c1 = Math.floor((camera.x + halfW) / CHUNKPX) + 1;
|
| 170 |
let r0 = Math.floor((camera.y - halfH) / CHUNKPX) - 1, r1 = Math.floor((camera.y + halfH) / CHUNKPX) + 1;
|
| 171 |
if (bounds) {
|
| 172 |
-
c0 = Math.max(c0, Math.floor(bounds.tx0 /
|
| 173 |
-
c1 = Math.min(c1, Math.floor((bounds.tx1 - 1) /
|
| 174 |
-
r0 = Math.max(r0, Math.floor(bounds.ty0 /
|
| 175 |
-
r1 = Math.min(r1, Math.floor((bounds.ty1 - 1) /
|
| 176 |
}
|
| 177 |
for (const [key, ch] of chunks) {
|
| 178 |
const [cx, cy] = key.split(",").map(Number);
|
|
@@ -199,7 +199,7 @@ function createChunkedMap(pixi, host, config) {
|
|
| 199 |
return missing.length > DETAIL_BUDGET;
|
| 200 |
}
|
| 201 |
function reconcileMacro(L) {
|
| 202 |
-
const px = MCHUNK * (1 << L) *
|
| 203 |
const halfW = app.screen.width / 2 / zoom, halfH = app.screen.height / 2 / zoom;
|
| 204 |
let c0 = Math.floor((camera.x - halfW) / px) - 1, c1 = Math.floor((camera.x + halfW) / px) + 1;
|
| 205 |
let r0 = Math.floor((camera.y - halfH) / px) - 1, r1 = Math.floor((camera.y + halfH) / px) + 1;
|
|
@@ -403,7 +403,7 @@ function createChunkedMap(pixi, host, config) {
|
|
| 403 |
if (cameraDirty || genPending) {
|
| 404 |
reconcile();
|
| 405 |
cameraDirty = false;
|
| 406 |
-
const tk2 = Math.round(camera.x /
|
| 407 |
if (tk2 !== lastEmitTile) {
|
| 408 |
lastEmitTile = tk2;
|
| 409 |
emit();
|
|
@@ -464,7 +464,7 @@ function createChunkedMap(pixi, host, config) {
|
|
| 464 |
}
|
| 465 |
function tileIndexAt(wx, wy) {
|
| 466 |
if (!config.tileIndexAt) return null;
|
| 467 |
-
const cx = Math.floor(wx /
|
| 468 |
const ch = chunks.get(cx + "," + cy);
|
| 469 |
if (!ch) return null;
|
| 470 |
return config.tileIndexAt(wx, wy, ch.meta);
|
|
@@ -523,7 +523,7 @@ function createChunkedMap(pixi, host, config) {
|
|
| 523 |
ctx = null;
|
| 524 |
texCache.clear();
|
| 525 |
}
|
| 526 |
-
return { ready, regenerate, destroy, onChange, getSnapshot, getCamera, tileIndexAt, biomeAt: biomeAt2, getBounds, zoomBy, flyTo, setEnabled, onTick, getEntityLayer, getApp, screenToWorld, worldToScreen, tile:
|
| 527 |
}
|
| 528 |
|
| 529 |
// ../auto-battler/src/engine/rng.js
|
|
@@ -3313,6 +3313,239 @@ function createDesolateDesertMap(pixi, host, opts = {}) {
|
|
| 3313 |
return createChunkedMap(pixi, host, { ...desolateDesertConfig(opts.seed ?? 1), keyboardPan: opts.keyboardPan });
|
| 3314 |
}
|
| 3315 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3316 |
// ../auto-battler/src/render/sceneViewer.js
|
| 3317 |
function createSceneViewer(pixi, host, { layers, dir, sceneW, sceneH, background = "#15121b", pulse = null }) {
|
| 3318 |
const { Application, Assets, Sprite, Container } = pixi;
|
|
@@ -3651,10 +3884,10 @@ function createTileViewer(pixi, host, cfg) {
|
|
| 3651 |
root = new Container();
|
| 3652 |
app.stage.addChild(root);
|
| 3653 |
const skin = skins[skinKey];
|
| 3654 |
-
const
|
| 3655 |
-
const res = render3({ app, root, skin, seed, TILE:
|
| 3656 |
lastBounds = res.bounds || null;
|
| 3657 |
-
lastTile = res.tile ??
|
| 3658 |
lastSnapshot = res.snapshot || {};
|
| 3659 |
if (res.tick) {
|
| 3660 |
tick = res.tick;
|
|
@@ -3728,19 +3961,19 @@ function createInteriorViewer(pixi, host, opts = {}) {
|
|
| 3728 |
fit
|
| 3729 |
});
|
| 3730 |
}
|
| 3731 |
-
function render({ root, skin, seed, TILE:
|
| 3732 |
const src = sources.get(skin.url);
|
| 3733 |
const { W, H, floor, rooms, bounds } = generateRooms(seed);
|
| 3734 |
const isF = (x, y) => x >= 0 && y >= 0 && x < W && y < H && floor[y * W + x] === 1;
|
| 3735 |
const addS = (source, coord, x, y) => {
|
| 3736 |
-
const sp = new Sprite(tex(source, coord[0], coord[1],
|
| 3737 |
-
sp.x = x *
|
| 3738 |
-
sp.y = y *
|
| 3739 |
root.addChild(sp);
|
| 3740 |
return sp;
|
| 3741 |
};
|
| 3742 |
const add = (coord, x, y) => addS(src, coord, x, y);
|
| 3743 |
-
const c = { skin, TILE:
|
| 3744 |
drawWalls(c);
|
| 3745 |
drawFloor(c);
|
| 3746 |
drawShadows(c);
|
|
@@ -3750,18 +3983,18 @@ function render({ root, skin, seed, TILE: TILE8, tex, sources, Sprite, Graphics
|
|
| 3750 |
const tick = torch.flames.length && torch.flameSrc ? (ticker) => {
|
| 3751 |
animPhase += 0.14 * ticker.deltaTime;
|
| 3752 |
const fi = Math.floor(animPhase) % torch.flameFrames;
|
| 3753 |
-
for (const fl of torch.flames) fl.sp.texture = tex(torch.flameSrc, fl.col0 + torch.flameStride * fi, fl.row,
|
| 3754 |
if (torch.glowG) torch.glowG.alpha = 0.78 + 0.22 * Math.sin(animPhase * 0.9);
|
| 3755 |
} : null;
|
| 3756 |
-
return { bounds, tile:
|
| 3757 |
}
|
| 3758 |
-
function fit(app, root, b,
|
| 3759 |
const sw = app.screen.width, sh = app.screen.height;
|
| 3760 |
-
const cw = (b.x1 - b.x0 + 3) *
|
| 3761 |
const s = Math.max(1, Math.floor(Math.min(sw / cw, sh / ch)));
|
| 3762 |
root.scale.set(s);
|
| 3763 |
-
root.x = Math.round((sw - cw * s) / 2 - (b.x0 - 1) *
|
| 3764 |
-
root.y = Math.round((sh - ch * s) / 2 - (b.y0 - 2) *
|
| 3765 |
}
|
| 3766 |
function drawWalls(c) {
|
| 3767 |
if (c.skin.wall && !c.skin.walls) drawBackWall(c);
|
|
@@ -3869,15 +4102,15 @@ function drawFloor(c) {
|
|
| 3869 |
}
|
| 3870 |
}
|
| 3871 |
function drawShadows(c) {
|
| 3872 |
-
const { W, H, TILE:
|
| 3873 |
const shade = new Graphics();
|
| 3874 |
for (let y = 0; y < H; y++) for (let x = 0; x < W; x++) {
|
| 3875 |
if (!isF(x, y)) continue;
|
| 3876 |
if (!isF(x, y - 1)) {
|
| 3877 |
-
shade.rect(x *
|
| 3878 |
-
if (isF(x, y + 1)) shade.rect(x *
|
| 3879 |
} else if (!isF(x - 1, y) || !isF(x + 1, y)) {
|
| 3880 |
-
shade.rect(x *
|
| 3881 |
}
|
| 3882 |
}
|
| 3883 |
root.addChild(shade);
|
|
@@ -3924,7 +4157,7 @@ function drawProps(c) {
|
|
| 3924 |
}
|
| 3925 |
}
|
| 3926 |
function drawTorches(c) {
|
| 3927 |
-
const { skin, W, H, TILE:
|
| 3928 |
const torch = skin.torch, torchSrc = torch && sources.get(torch.url);
|
| 3929 |
if (!(torch && torchSrc)) return { flames: [], glowG: null, flameSrc: null, flameStride: 1, flameFrames: 1 };
|
| 3930 |
const flames = [];
|
|
@@ -3933,8 +4166,8 @@ function drawTorches(c) {
|
|
| 3933 |
for (let y = 0; y < H; y++) for (let x = 0; x < W; x++) {
|
| 3934 |
if (!isF(x, y) || isF(x, y - 1)) continue;
|
| 3935 |
if ((x * 7 + y * 13) % 5 !== 0) continue;
|
| 3936 |
-
const cx = (x + f.w / 2) *
|
| 3937 |
-
for (const [r, a] of [[3.2, 0.05], [2.1, 0.08], [1.2, 0.13]]) glow.circle(cx, cy, r *
|
| 3938 |
spots.push([x, y]);
|
| 3939 |
}
|
| 3940 |
root.addChild(glow);
|
|
@@ -3975,7 +4208,7 @@ function createTowerViewer(pixi, host, opts = {}) {
|
|
| 3975 |
fit: fit2
|
| 3976 |
});
|
| 3977 |
}
|
| 3978 |
-
function render2({ root, skin, seed, TILE:
|
| 3979 |
const src = sources.get(skin.url);
|
| 3980 |
const shaftW = skin.crown ? skin.crown.shaftW : (skin.roof?.w ?? 7) - 2;
|
| 3981 |
const winH = skin.window?.h ?? 2, doorH = skin.door?.h ?? 2;
|
|
@@ -3992,14 +4225,14 @@ function render2({ root, skin, seed, TILE: TILE8, tex, sources, Sprite, Graphics
|
|
| 3992 |
const corn = spec.roof === "none" ? 0 : 1;
|
| 3993 |
const dy = -(h2 + PLINTH - 1);
|
| 3994 |
const add = (coord, x, y) => {
|
| 3995 |
-
const sp = new Sprite(tex(src, coord[0], coord[1],
|
| 3996 |
-
sp.x = (x + ox) *
|
| 3997 |
-
sp.y = (y + dy) *
|
| 3998 |
root.addChild(sp);
|
| 3999 |
return sp;
|
| 4000 |
};
|
| 4001 |
const shadow = new Graphics();
|
| 4002 |
-
shadow.ellipse((ox + w / 2) *
|
| 4003 |
root.addChild(shadow);
|
| 4004 |
for (let y = 0; y < h2; y++) for (let x = 0; x < w; x++) {
|
| 4005 |
const top = y === 0, bot = y === h2 - 1, left = x === 0, right = x === w - 1;
|
|
@@ -4061,19 +4294,34 @@ function render2({ root, skin, seed, TILE: TILE8, tex, sources, Sprite, Graphics
|
|
| 4061 |
ox += w + GAP;
|
| 4062 |
}
|
| 4063 |
const bounds = { x0: Math.min(x0, 0), y0, x1: Math.max(x1, ox - GAP), y1: 2 };
|
| 4064 |
-
return { bounds, tile:
|
| 4065 |
}
|
| 4066 |
-
function fit2(app, root, b,
|
| 4067 |
const sw = app.screen.width, sh = app.screen.height;
|
| 4068 |
-
const cw = (b.x1 - b.x0) *
|
| 4069 |
-
const pad = 4 *
|
| 4070 |
const s = Math.max(1, Math.floor(Math.min(sw / (cw + pad), sh / (ch + pad))));
|
| 4071 |
root.scale.set(s);
|
| 4072 |
-
root.x = Math.round((sw - cw * s) / 2 - b.x0 *
|
| 4073 |
-
root.y = Math.round((sh - ch * s) / 2 - b.y0 *
|
| 4074 |
}
|
| 4075 |
|
| 4076 |
// ../auto-battler/src/render/mapConfigs.js
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4077 |
var ASSET = "/assets/minifantasy";
|
| 4078 |
var ORC4 = `${ASSET}/Minifantasy_Orc_Kingdom_v1.0/Minifantasy_Orc_Kingdom_Assets`;
|
| 4079 |
var NECRO4 = `${ASSET}/Minifantasy_Necropolis_v1.0/Minifantasy_Necropolis_Assets`;
|
|
@@ -4251,6 +4499,15 @@ var MAP_ASSET_URLS = [.../* @__PURE__ */ new Set([
|
|
| 4251 |
...NECRO_SHEETS.map((s) => s.url),
|
| 4252 |
...ORC_SHEETS.map((s) => s.url),
|
| 4253 |
...FP_SHEETS.map((s) => s.url),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4254 |
// Premade-scene reference layers.
|
| 4255 |
...sceneUrls(NECRO_EXT_DIR, NECRO_LAYERS),
|
| 4256 |
...sceneUrls(ORC_LAYER_DIR, ORC_LAYERS),
|
|
@@ -4277,7 +4534,7 @@ function h(tag, attrs, ...kids) {
|
|
| 4277 |
var randomSeed = () => Math.floor(Date.now() % 1e6 + Math.random() * 1e6) >>> 0;
|
| 4278 |
var infiniteMeta = (s) => s?.zoom != null ? `\u221E \xB7 seed ${s.seed} \xB7 (${s.cx}, ${s.cy}) \xB7 ${s.zoom.toFixed(2)}\xD7 \xB7 drag / WASD / scroll` : "loading\u2026";
|
| 4279 |
function makeGridOverlay() {
|
| 4280 |
-
const
|
| 4281 |
const cv = h("canvas", { class: "necro-grid-overlay" });
|
| 4282 |
cv.style.display = "none";
|
| 4283 |
let raf = 0, ctrl = null;
|
|
@@ -4290,12 +4547,12 @@ function makeGridOverlay() {
|
|
| 4290 |
if (cv.height !== H) cv.height = H;
|
| 4291 |
const ctx = cv.getContext("2d");
|
| 4292 |
ctx.clearRect(0, 0, W, H);
|
| 4293 |
-
const z = cam.zoom, cell =
|
| 4294 |
if (cell >= 6) {
|
| 4295 |
-
const sx = (wx) => (wx *
|
| 4296 |
-
const sy = (wy) => (wy *
|
| 4297 |
-
const x0 = Math.floor((cam.x - W / 2 / z) /
|
| 4298 |
-
const y0 = Math.floor((cam.y - H / 2 / z) /
|
| 4299 |
ctx.strokeStyle = "rgba(255,70,70,0.45)";
|
| 4300 |
ctx.lineWidth = 1;
|
| 4301 |
ctx.beginPath();
|
|
@@ -4724,6 +4981,7 @@ var GEN_MODES = [{ key: "generated", label: "Generated" }, { key: "tilesheet", l
|
|
| 4724 |
var SKIN_MODES = [{ key: "generated", label: "Generated" }, { key: "reference", label: "Reference" }, { key: "tilesheet", label: "Tilesheet" }];
|
| 4725 |
var skinList = (skins) => Object.entries(skins).map(([key, s]) => ({ key, label: s.label }));
|
| 4726 |
var sceneFromRef = (pixi, host, ref) => createSceneViewer(pixi, host, { layers: ref.layers, dir: ref.dir, sceneW: ref.w, sceneH: ref.h, background: ref.bg, pulse: ref.pulse });
|
|
|
|
| 4727 |
var PAGES = {
|
| 4728 |
world: (pixi, body, opts) => makePage(pixi, body, {
|
| 4729 |
title: "World Map",
|
|
@@ -4796,6 +5054,20 @@ var PAGES = {
|
|
| 4796 |
sheets: () => DD_SHEETS,
|
| 4797 |
generatedMeta: infiniteMeta
|
| 4798 |
}),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4799 |
interiors: (pixi, body) => makePage(pixi, body, {
|
| 4800 |
title: "Interiors",
|
| 4801 |
modes: SKIN_MODES,
|
|
@@ -4821,6 +5093,7 @@ var NAV = [
|
|
| 4821 |
["gameworld", "Game World"],
|
| 4822 |
["world", "World Map"],
|
| 4823 |
{ group: "biome", label: "Biome", pages: [["plains", "Forgotten Plains"], ["desert", "Desolate Desert"], ["orc", "Orc Kingdom"], ["necropolis", "Necropolis"]] },
|
|
|
|
| 4824 |
["interiors", "Interiors"],
|
| 4825 |
["towers", "Towers"]
|
| 4826 |
];
|
|
|
|
| 1 |
// ../auto-battler/src/render/chunkedMap.js
|
| 2 |
function createChunkedMap(pixi, host, config) {
|
| 3 |
const { Application, Assets, Sprite, Container, Texture, Rectangle, RenderTexture } = pixi;
|
| 4 |
+
const TILE10 = config.tile ?? 8;
|
| 5 |
+
const CHUNK9 = config.chunk ?? 32;
|
| 6 |
+
const CHUNKPX = CHUNK9 * TILE10;
|
| 7 |
const BG = config.background ?? "#69636f";
|
| 8 |
const Z_DEFAULT = config.zoomDefault ?? 1;
|
| 9 |
const Z_MIN = config.zoomMin ?? 1 / 32;
|
|
|
|
| 17 |
const DETAIL_BUDGET = config.detailBudget ?? 1;
|
| 18 |
const MACRO_BUDGET = config.macroBudget ?? 8;
|
| 19 |
const bounds = config.bounds ? {
|
| 20 |
+
x0: config.bounds.x0 * TILE10,
|
| 21 |
+
y0: config.bounds.y0 * TILE10,
|
| 22 |
+
x1: config.bounds.x1 * TILE10,
|
| 23 |
+
y1: config.bounds.y1 * TILE10,
|
| 24 |
tx0: config.bounds.x0,
|
| 25 |
ty0: config.bounds.y0,
|
| 26 |
tx1: config.bounds.x1,
|
|
|
|
| 47 |
const pinch = { on: false, dist: 0 };
|
| 48 |
const handlers = {};
|
| 49 |
const emit = () => listeners.forEach((fn) => fn(getSnapshot()));
|
| 50 |
+
const getSnapshot = () => ({ seed, zoom, cx: Math.round(camera.x / TILE10), cy: Math.round(camera.y / TILE10), chunks: chunks.size });
|
| 51 |
function tex(source, c, r) {
|
| 52 |
const k = source.uid + ":" + c + "," + r;
|
| 53 |
let t = texCache.get(k);
|
| 54 |
if (!t) {
|
| 55 |
+
t = new Texture({ source, frame: new Rectangle(c * TILE10, r * TILE10, TILE10, TILE10) });
|
| 56 |
texCache.set(k, t);
|
| 57 |
}
|
| 58 |
return t;
|
|
|
|
| 67 |
return t;
|
| 68 |
}
|
| 69 |
function makeChunk(cx, cy) {
|
| 70 |
+
const x0 = cx * CHUNK9, y0 = cy * CHUNK9;
|
| 71 |
const tmp = new Container();
|
| 72 |
const add = (source, c, r, tx, ty) => {
|
| 73 |
const sp = new Sprite(tex(source, c, r));
|
| 74 |
+
sp.x = tx * TILE10;
|
| 75 |
+
sp.y = ty * TILE10;
|
| 76 |
tmp.addChild(sp);
|
| 77 |
return sp;
|
| 78 |
};
|
| 79 |
+
const res = config.bake({ cx, cy, x0, y0, seed, chunk: CHUNK9, tile: TILE10, ctx, tmp, app, Sprite, Container, Texture, Rectangle, tex, texFrame, add }) || {};
|
| 80 |
const rt = RenderTexture.create({ width: CHUNKPX, height: CHUNKPX, autoGenerateMipmaps: true, scaleMode: "nearest" });
|
| 81 |
rt.source.minFilter = "linear";
|
| 82 |
rt.source.mipmapFilter = "linear";
|
|
|
|
| 84 |
rt.source.updateMipmaps();
|
| 85 |
tmp.destroy({ children: true });
|
| 86 |
const sprite = new Sprite(rt);
|
| 87 |
+
sprite.x = x0 * TILE10;
|
| 88 |
+
sprite.y = y0 * TILE10;
|
| 89 |
return { sprite, rt, meta: res.meta ?? null, live: res.live ?? null };
|
| 90 |
}
|
| 91 |
function chooseMacroLevel(z) {
|
| 92 |
+
return Math.max(0, Math.min(MACRO_LEVEL_MAX, Math.round(Math.log2(MACRO_TEXEL_PX / (TILE10 * z)))));
|
| 93 |
}
|
| 94 |
function makeMacroChunk(L, mcx, mcy) {
|
| 95 |
const step = 1 << L, t0x = mcx * MCHUNK * step, t0y = mcy * MCHUNK * step;
|
|
|
|
| 110 |
const t = Texture.from(cv);
|
| 111 |
t.source.scaleMode = "linear";
|
| 112 |
const sprite = new Sprite(t);
|
| 113 |
+
sprite.x = t0x * TILE10;
|
| 114 |
+
sprite.y = t0y * TILE10;
|
| 115 |
+
sprite.width = sprite.height = MCHUNK * step * TILE10;
|
| 116 |
return { sprite, tex: t };
|
| 117 |
}
|
| 118 |
function coverZoom() {
|
|
|
|
| 169 |
let c0 = Math.floor((camera.x - halfW) / CHUNKPX) - 1, c1 = Math.floor((camera.x + halfW) / CHUNKPX) + 1;
|
| 170 |
let r0 = Math.floor((camera.y - halfH) / CHUNKPX) - 1, r1 = Math.floor((camera.y + halfH) / CHUNKPX) + 1;
|
| 171 |
if (bounds) {
|
| 172 |
+
c0 = Math.max(c0, Math.floor(bounds.tx0 / CHUNK9));
|
| 173 |
+
c1 = Math.min(c1, Math.floor((bounds.tx1 - 1) / CHUNK9));
|
| 174 |
+
r0 = Math.max(r0, Math.floor(bounds.ty0 / CHUNK9));
|
| 175 |
+
r1 = Math.min(r1, Math.floor((bounds.ty1 - 1) / CHUNK9));
|
| 176 |
}
|
| 177 |
for (const [key, ch] of chunks) {
|
| 178 |
const [cx, cy] = key.split(",").map(Number);
|
|
|
|
| 199 |
return missing.length > DETAIL_BUDGET;
|
| 200 |
}
|
| 201 |
function reconcileMacro(L) {
|
| 202 |
+
const px = MCHUNK * (1 << L) * TILE10;
|
| 203 |
const halfW = app.screen.width / 2 / zoom, halfH = app.screen.height / 2 / zoom;
|
| 204 |
let c0 = Math.floor((camera.x - halfW) / px) - 1, c1 = Math.floor((camera.x + halfW) / px) + 1;
|
| 205 |
let r0 = Math.floor((camera.y - halfH) / px) - 1, r1 = Math.floor((camera.y + halfH) / px) + 1;
|
|
|
|
| 403 |
if (cameraDirty || genPending) {
|
| 404 |
reconcile();
|
| 405 |
cameraDirty = false;
|
| 406 |
+
const tk2 = Math.round(camera.x / TILE10) + "," + Math.round(camera.y / TILE10) + "," + zoom.toFixed(3);
|
| 407 |
if (tk2 !== lastEmitTile) {
|
| 408 |
lastEmitTile = tk2;
|
| 409 |
emit();
|
|
|
|
| 464 |
}
|
| 465 |
function tileIndexAt(wx, wy) {
|
| 466 |
if (!config.tileIndexAt) return null;
|
| 467 |
+
const cx = Math.floor(wx / CHUNK9), cy = Math.floor(wy / CHUNK9);
|
| 468 |
const ch = chunks.get(cx + "," + cy);
|
| 469 |
if (!ch) return null;
|
| 470 |
return config.tileIndexAt(wx, wy, ch.meta);
|
|
|
|
| 523 |
ctx = null;
|
| 524 |
texCache.clear();
|
| 525 |
}
|
| 526 |
+
return { ready, regenerate, destroy, onChange, getSnapshot, getCamera, tileIndexAt, biomeAt: biomeAt2, getBounds, zoomBy, flyTo, setEnabled, onTick, getEntityLayer, getApp, screenToWorld, worldToScreen, tile: TILE10 };
|
| 527 |
}
|
| 528 |
|
| 529 |
// ../auto-battler/src/engine/rng.js
|
|
|
|
| 3313 |
return createChunkedMap(pixi, host, { ...desolateDesertConfig(opts.seed ?? 1), keyboardPan: opts.keyboardPan });
|
| 3314 |
}
|
| 3315 |
|
| 3316 |
+
// ../auto-battler/src/render/medievalCity.js
|
| 3317 |
+
var MC = "/assets/minifantasy/Minifantasy_Medieval_City_v1.1/Minifantasy_Medieval_City_Assets";
|
| 3318 |
+
var MC_TILES_URL = `${MC}/Tileset/Tileset.png`;
|
| 3319 |
+
var MC_TILES_SHADOWS_URL = `${MC}/Tileset/Shadows.png`;
|
| 3320 |
+
var MC_PROPS_URL = `${MC}/Props/Props.png`;
|
| 3321 |
+
var MC_PROPS_SHADOWS_URL = `${MC}/Props/Shadows.png`;
|
| 3322 |
+
var MC_MOCKUP_URL = `${MC}/Mockup_Exterior_1.png`;
|
| 3323 |
+
var MC_PREMADE_DIR = `${MC}/Premade/Premade_Exterior/Separate_Layers`;
|
| 3324 |
+
var TILE8 = 8;
|
| 3325 |
+
var CHUNK7 = 32;
|
| 3326 |
+
var MC_REF = {
|
| 3327 |
+
dir: MC_PREMADE_DIR,
|
| 3328 |
+
w: 680,
|
| 3329 |
+
h: 552,
|
| 3330 |
+
bg: "#1a1714",
|
| 3331 |
+
layers: [
|
| 3332 |
+
["Exterior_o-floor", "Floor", "ground"],
|
| 3333 |
+
["Exterior_n-fences", "Fences", "structure"],
|
| 3334 |
+
["Exterior_m-walls_1", "Walls 1", "structure"],
|
| 3335 |
+
["Exterior_l-stairs_and_terraces_1", "Stairs & terraces 1", "structure"],
|
| 3336 |
+
["Exterior_k-walls_2", "Walls 2", "structure"],
|
| 3337 |
+
["Exterior_j-stairs_and_terraces_2", "Stairs & terraces 2", "structure"],
|
| 3338 |
+
["Exterior_i-props", "Props", "scatter"],
|
| 3339 |
+
["Exterior_h-roof", "Roof", "structure"],
|
| 3340 |
+
["Exterior_g-turrets_and_annexes", "Turrets & annexes", "structure"],
|
| 3341 |
+
["Exterior_f-chimneys", "Chimneys", "structure"],
|
| 3342 |
+
["Exterior_e-city_walls", "City walls", "structure"],
|
| 3343 |
+
["Exterior_d-props_on_city_walls", "Props on city walls", "scatter"],
|
| 3344 |
+
["Exterior_c-shadows", "Shadows", "lighting"],
|
| 3345 |
+
["Exterior_b-pennant_flags", "Pennant flags", "scatter"],
|
| 3346 |
+
["Exterior_a-night_effect", "Night effect", "lighting"]
|
| 3347 |
+
]
|
| 3348 |
+
};
|
| 3349 |
+
var DIRT_BASE2 = [4, 132];
|
| 3350 |
+
var DIRT_VARS4 = [[6, 132], [8, 132], [10, 132], [6, 134], [8, 134], [10, 134], [6, 136], [8, 136]];
|
| 3351 |
+
var DIRT_RATE2 = 6;
|
| 3352 |
+
var COL_DIRT4 = [151, 116, 94];
|
| 3353 |
+
var MC_MAP_ASSETS = [MC_TILES_URL];
|
| 3354 |
+
var medievalCityConfig = (seed) => ({
|
| 3355 |
+
seed,
|
| 3356 |
+
tile: TILE8,
|
| 3357 |
+
chunk: CHUNK7,
|
| 3358 |
+
background: "#3a2e25",
|
| 3359 |
+
async load({ Assets }) {
|
| 3360 |
+
const ctx = { tiles: null };
|
| 3361 |
+
const t = await Assets.load(MC_TILES_URL);
|
| 3362 |
+
t.source.scaleMode = "nearest";
|
| 3363 |
+
ctx.tiles = t.source;
|
| 3364 |
+
return ctx;
|
| 3365 |
+
},
|
| 3366 |
+
bake({ x0, y0, seed: seed2, ctx, add, accept = () => true }) {
|
| 3367 |
+
for (let ty = 0; ty < CHUNK7; ty++) for (let tx = 0; tx < CHUNK7; tx++) {
|
| 3368 |
+
if (!accept(tx, ty)) continue;
|
| 3369 |
+
const wx = x0 + tx, wy = y0 + ty;
|
| 3370 |
+
add(ctx.tiles, ...sparse(DIRT_BASE2, DIRT_VARS4, wx, wy, 0, DIRT_RATE2, seed2), tx, ty);
|
| 3371 |
+
}
|
| 3372 |
+
return {};
|
| 3373 |
+
},
|
| 3374 |
+
macroColor() {
|
| 3375 |
+
return COL_DIRT4;
|
| 3376 |
+
}
|
| 3377 |
+
});
|
| 3378 |
+
function createMedievalCityMap(pixi, host, opts = {}) {
|
| 3379 |
+
return createChunkedMap(pixi, host, { ...medievalCityConfig(opts.seed ?? 1), keyboardPan: opts.keyboardPan });
|
| 3380 |
+
}
|
| 3381 |
+
var MC_TILE_CATALOG = [
|
| 3382 |
+
// ── Ground (band at rows ~130-141) ──────────────────────────────────────────────────────────
|
| 3383 |
+
{
|
| 3384 |
+
name: "Outdoor floor (dirt base + speckle)",
|
| 3385 |
+
frame: [4, 140, 8, 9],
|
| 3386 |
+
tiles: [DIRT_BASE2, ...DIRT_VARS4],
|
| 3387 |
+
used: true,
|
| 3388 |
+
note: "dirt base [4,132] (100% plain) + speckle variants on the even col/row grid (cols 4-11), via sparse(). Laid by the Generated ground"
|
| 3389 |
+
},
|
| 3390 |
+
{
|
| 3391 |
+
name: "Cobble road (tan)",
|
| 3392 |
+
frame: [14, 142, 3, 11],
|
| 3393 |
+
tiles: [[14, 132]],
|
| 3394 |
+
used: false,
|
| 3395 |
+
note: "tan cobblestone road \u2014 FP-format autotile block; a grass-on-dirt block sits just below it"
|
| 3396 |
+
},
|
| 3397 |
+
{ name: "Flagstone road (grey)", frame: [18, 142, 3, 13], tiles: [[18, 130]], used: false, note: "grey stone-slab road \u2014 autotile block" },
|
| 3398 |
+
{ name: "Brick road (red)", frame: [22, 142, 3, 13], tiles: [[22, 130]], used: false, note: "red brick road \u2014 autotile block" },
|
| 3399 |
+
{ name: "Smooth pavement", frame: [26, 136, 3, 5], tiles: [[26, 132]], used: false, note: "flat tan paving (plaza/courtyard)" },
|
| 3400 |
+
{ name: "Garden / planting bed", frame: [30, 136, 3, 7], tiles: [[30, 130]], used: false, note: "grass patch + tilled-earth bed" },
|
| 3401 |
+
{ name: "Hedge fence (green)", frame: [38, 137, 5, 7], tiles: [[38, 131]], used: false, note: "9-slice green hedge enclosure" },
|
| 3402 |
+
{ name: "Picket fence", frame: [45, 140, 5, 11], tiles: [[45, 130]], used: false, note: "light picket fence \u2014 9-slice + gate" },
|
| 3403 |
+
{ name: "Wooden fence / gate", frame: [52, 138, 5, 8], tiles: [[52, 131]], used: false, note: "wooden fence/gate frame" },
|
| 3404 |
+
// ── Grates / arches (rows ~120-127) ─────────────────────────────────────────────────────────
|
| 3405 |
+
{ name: "Stone arch (gate/bridge)", frame: [12, 122, 5, 3], tiles: [[12, 120]], used: false, note: "open stone archway" },
|
| 3406 |
+
{ name: "Iron grate / portcullis", frame: [12, 126, 5, 3], tiles: [[12, 124]], used: false, note: "barred iron gate (sewer/gate)" },
|
| 3407 |
+
// ── Buildings — premade facades + components (3 colour sets: red cols 1-37 / green 39-75 / purple 77-113)
|
| 3408 |
+
{
|
| 3409 |
+
name: "Building facades (\xD73 colours)",
|
| 3410 |
+
frame: [1, 32, 37, 30],
|
| 3411 |
+
tiles: [[1, 3]],
|
| 3412 |
+
used: false,
|
| 3413 |
+
note: "PREMADE full house facades + corner/conical towers \u2014 drop-in buildings. Red cols 1-37, green 39-75, purple 77-113"
|
| 3414 |
+
},
|
| 3415 |
+
{
|
| 3416 |
+
name: "Roof pieces (\xD73 colours)",
|
| 3417 |
+
frame: [1, 60, 37, 24],
|
| 3418 |
+
tiles: [[1, 37]],
|
| 3419 |
+
used: false,
|
| 3420 |
+
note: "ridge / slope / eave / cap / gable \u2014 the roof overlay for assembled buildings; same 3 colour columns"
|
| 3421 |
+
},
|
| 3422 |
+
{
|
| 3423 |
+
name: "Walls A \u2014 light stone (9-slice + door + windows)",
|
| 3424 |
+
frame: [20, 85, 13, 15],
|
| 3425 |
+
tiles: [[20, 71]],
|
| 3426 |
+
used: false,
|
| 3427 |
+
note: "wall 9-slice with baked door + window openings (light tan stone), rows 67-90"
|
| 3428 |
+
},
|
| 3429 |
+
{
|
| 3430 |
+
name: "Walls B \u2014 grey stone (9-slice + door + windows)",
|
| 3431 |
+
frame: [20, 112, 16, 19],
|
| 3432 |
+
tiles: [[20, 94]],
|
| 3433 |
+
used: false,
|
| 3434 |
+
note: "second wall material (grey stone), rows 94-118"
|
| 3435 |
+
},
|
| 3436 |
+
{ name: "Doors", frame: [58, 102, 8, 5], tiles: [[58, 98]], used: false, note: "wooden double / arched / portcullis doors" },
|
| 3437 |
+
{ name: "Arched windows (glass)", frame: [34, 77, 2, 6], tiles: [[34, 72]], used: false, note: "stained-glass arched windows" }
|
| 3438 |
+
// TODO: split the wall sets into individual 9-slice anchors (BLOCK/FILL/door/window cells) when the
|
| 3439 |
+
// building generator needs them; and enumerate the per-colour roof sub-pieces. No water tiles in this pack.
|
| 3440 |
+
];
|
| 3441 |
+
var MC_PROP_CATALOG = [
|
| 3442 |
+
{ name: "Crates & sacks", frame: [2, 8, 5, 3], tiles: [[2, 8]], used: false, note: "wooden crates + sack" },
|
| 3443 |
+
{ name: "Market produce / small goods", frame: [8, 9, 10, 5], tiles: [[8, 9]], used: false, note: "small stall goods (food/wares)" },
|
| 3444 |
+
{ name: "Barrel + lamp (stacked)", frame: [22, 9, 1, 7], tiles: [[22, 9]], used: false, note: "1-wide barrel + lantern" },
|
| 3445 |
+
{ name: "Market stalls + well", frame: [24, 9, 19, 10], tiles: [[24, 9]], used: false, note: "awning shop stalls + a well/fountain" },
|
| 3446 |
+
{ name: "Cloth / meat stalls", frame: [44, 9, 7, 4], tiles: [[44, 9]], used: false, note: "covered market tables" },
|
| 3447 |
+
{ name: "Wooden beam", frame: [1, 17, 3, 3], tiles: [[1, 17]], used: false, note: "plank/beam" },
|
| 3448 |
+
{ name: "Benches", frame: [3, 19, 2, 6], tiles: [[3, 19]], used: false, note: "wooden benches" },
|
| 3449 |
+
{ name: "Post / plank", frame: [6, 17, 1, 3], tiles: [[6, 17]], used: false, note: "tall post" },
|
| 3450 |
+
{ name: "Lamp posts", frame: [8, 20, 11, 9], tiles: [[8, 20]], used: false, note: "street lamp posts / torches" },
|
| 3451 |
+
{ name: "Furniture & barrels (mixed)", frame: [22, 23, 26, 13], tiles: [[22, 23]], used: false, note: "barrels, tables, signs, cart wheel \u2014 general street/yard clutter" },
|
| 3452 |
+
{ name: "Barrels (stacked)", frame: [49, 18, 1, 6], tiles: [[49, 18]], used: false, note: "two stacked barrels" },
|
| 3453 |
+
{ name: "Bed / cart", frame: [51, 15, 2, 2], tiles: [[51, 15]], used: false, note: "small bed or hand-cart" }
|
| 3454 |
+
];
|
| 3455 |
+
|
| 3456 |
+
// ../auto-battler/src/render/mountainStronghold.js
|
| 3457 |
+
var MS = "/assets/minifantasy/Minifantasy_Mountain_Stronghold_v1.0/Minifantasy_Mountain_Stronghold_Assets";
|
| 3458 |
+
var MS_TILES_URL = `${MS}/Tileset/Tileset.png`;
|
| 3459 |
+
var MS_PROPS_URL = `${MS}/Props/Props.png`;
|
| 3460 |
+
var MS_MOCKUP_URL = `${MS}/Mockup_Exterior.png`;
|
| 3461 |
+
var MS_PREMADE_DIR = `${MS}/Premade/Premade_Exterior/_Separate_Layers`;
|
| 3462 |
+
var TILE9 = 8;
|
| 3463 |
+
var CHUNK8 = 32;
|
| 3464 |
+
var MS_REF = {
|
| 3465 |
+
dir: MS_PREMADE_DIR,
|
| 3466 |
+
w: 488,
|
| 3467 |
+
h: 592,
|
| 3468 |
+
bg: "#14171c",
|
| 3469 |
+
layers: [
|
| 3470 |
+
["Exterior_l-bg", "Background", "ground"],
|
| 3471 |
+
["Exterior_k-jagged_cliffs", "Jagged cliffs", "ground"],
|
| 3472 |
+
["Exterior_j-snow_1", "Snow 1", "ground"],
|
| 3473 |
+
["Exterior_i-structures_built_into_cliffs", "Structures in cliffs", "structure"],
|
| 3474 |
+
["Exterior_h-props", "Props", "scatter"],
|
| 3475 |
+
["Exterior_g-bridges", "Bridges", "structure"],
|
| 3476 |
+
["Exterior_f-battlements_and_rooftops", "Battlements & rooftops", "structure"],
|
| 3477 |
+
["Exterior_e-snow_2", "Snow 2", "ground"],
|
| 3478 |
+
["Exterior_d-doors_windows", "Doors & windows", "structure"],
|
| 3479 |
+
["Exterior_c-stairs", "Stairs", "structure"],
|
| 3480 |
+
["Exterior_b-human", "Characters", "scatter"],
|
| 3481 |
+
["Exterior_a-shadows", "Shadows", "lighting"]
|
| 3482 |
+
]
|
| 3483 |
+
};
|
| 3484 |
+
var FLOOR_BASE = [39, 85];
|
| 3485 |
+
var FLOOR_VARS = [[40, 85], [39, 86], [40, 86], [39, 87], [40, 87]];
|
| 3486 |
+
var FLOOR_RATE = 5;
|
| 3487 |
+
var COL_STONE3 = [144, 148, 137];
|
| 3488 |
+
var MS_MAP_ASSETS = [MS_TILES_URL];
|
| 3489 |
+
var mountainStrongholdConfig = (seed) => ({
|
| 3490 |
+
seed,
|
| 3491 |
+
tile: TILE9,
|
| 3492 |
+
chunk: CHUNK8,
|
| 3493 |
+
background: "#2c2f2c",
|
| 3494 |
+
async load({ Assets }) {
|
| 3495 |
+
const ctx = { tiles: null };
|
| 3496 |
+
const t = await Assets.load(MS_TILES_URL);
|
| 3497 |
+
t.source.scaleMode = "nearest";
|
| 3498 |
+
ctx.tiles = t.source;
|
| 3499 |
+
return ctx;
|
| 3500 |
+
},
|
| 3501 |
+
bake({ x0, y0, seed: seed2, ctx, add, accept = () => true }) {
|
| 3502 |
+
for (let ty = 0; ty < CHUNK8; ty++) for (let tx = 0; tx < CHUNK8; tx++) {
|
| 3503 |
+
if (!accept(tx, ty)) continue;
|
| 3504 |
+
const wx = x0 + tx, wy = y0 + ty;
|
| 3505 |
+
add(ctx.tiles, ...sparse(FLOOR_BASE, FLOOR_VARS, wx, wy, 0, FLOOR_RATE, seed2), tx, ty);
|
| 3506 |
+
}
|
| 3507 |
+
return {};
|
| 3508 |
+
},
|
| 3509 |
+
macroColor() {
|
| 3510 |
+
return COL_STONE3;
|
| 3511 |
+
}
|
| 3512 |
+
});
|
| 3513 |
+
function createMountainStrongholdMap(pixi, host, opts = {}) {
|
| 3514 |
+
return createChunkedMap(pixi, host, { ...mountainStrongholdConfig(opts.seed ?? 1), keyboardPan: opts.keyboardPan });
|
| 3515 |
+
}
|
| 3516 |
+
var MS_TILE_CATALOG = [
|
| 3517 |
+
// ── Floor band (rows 85-108) ─────────────────────────────────────────────────────────────────
|
| 3518 |
+
{
|
| 3519 |
+
name: "Stone floor (grey + shades)",
|
| 3520 |
+
frame: [38, 107, 3, 23],
|
| 3521 |
+
tiles: [FLOOR_BASE, ...FLOOR_VARS],
|
| 3522 |
+
used: true,
|
| 3523 |
+
note: "grey floor base [39,85] + variants, via sparse() (Generated ground). Also green-grey [42,85] & brown [46,85] shades"
|
| 3524 |
+
},
|
| 3525 |
+
{ name: "Flagstone courtyard", frame: [101, 107, 19, 23], tiles: [[101, 85]], used: false, note: "large paved courtyard / autotile area" },
|
| 3526 |
+
{ name: "Hanging banners (red)", frame: [123, 107, 5, 16], tiles: [[123, 92]], used: false, note: "cloth banners draped on walls" },
|
| 3527 |
+
// ── Walls / structures (snowy rows 0-42; plain rows 43-84) ───────────────────────────────────
|
| 3528 |
+
{ name: "Cliff cave / tunnel mouth", frame: [1, 28, 13, 27], tiles: [[1, 2]], used: false, note: "dark opening bored into the cliff (snowy; plain [1,45])" },
|
| 3529 |
+
{ name: "Fortress wall (9-slice + windows)", frame: [34, 24, 13, 24], tiles: [[34, 1]], used: false, note: "stone wall block with baked windows (snowy; plain [34,44])" },
|
| 3530 |
+
{ name: "Wall with arched door", frame: [61, 22, 9, 20], tiles: [[61, 3]], used: false, note: "wall section with an arched doorway" },
|
| 3531 |
+
{ name: "Wall edges / pilasters", frame: [28, 25, 2, 15], tiles: [[28, 11]], used: false, note: "vertical wall-edge / pilaster strips" },
|
| 3532 |
+
{ name: "Corner tower", frame: [156, 35, 11, 30], tiles: [[156, 6]], used: false, note: "round corner tower (snowy; plain [156,49])" },
|
| 3533 |
+
{ name: "Curtain wall (tall)", frame: [170, 36, 7, 36], tiles: [[170, 1]], used: false, note: "tall curtain-wall section" },
|
| 3534 |
+
{ name: "Great gate arch", frame: [180, 36, 23, 37], tiles: [[180, 0]], used: false, note: "large gatehouse archway (snowy; plain [180,43])" },
|
| 3535 |
+
{ name: "Bridge / aqueduct arch", frame: [102, 27, 24, 23], tiles: [[102, 5]], used: false, note: "arched stone bridge / aqueduct span" },
|
| 3536 |
+
{ name: "Battlements (crenellations)", frame: [148, 35, 7, 9], tiles: [[148, 27]], used: false, note: "wall-top merlons + crenellations" },
|
| 3537 |
+
{ name: "Arched gateway opening", frame: [16, 67, 7, 12], tiles: [[16, 56]], used: false, note: "open arched gateway (plain set)" }
|
| 3538 |
+
// TODO: split wall blocks into 9-slice cells for the building generator (Phase 3); stairs/snow detail.
|
| 3539 |
+
];
|
| 3540 |
+
var MS_PROP_CATALOG = [
|
| 3541 |
+
{ name: "Crates & stone braziers", frame: [1, 16, 7, 15], tiles: [[1, 16]], used: false, note: "wooden crates + stone fire braziers/stands" },
|
| 3542 |
+
{ name: "Wooden table / cart", frame: [9, 10, 3, 9], tiles: [[9, 10]], used: false, note: "table or hand-cart" },
|
| 3543 |
+
{ name: "Banners, racks & barrels", frame: [13, 17, 20, 17], tiles: [[13, 17]], used: false, note: "hanging banners, weapon racks, barrels, bones \u2014 mixed hall clutter" },
|
| 3544 |
+
{ name: "Rubble / small rocks", frame: [3, 33, 1, 13], tiles: [[3, 33]], used: false, note: "thin rubble columns (also at [9] and [23])" },
|
| 3545 |
+
{ name: "Snow-capped boulders", frame: [14, 33, 7, 14], tiles: [[14, 33]], used: false, note: "large rocks with snow" },
|
| 3546 |
+
{ name: "Icy boulders", frame: [26, 33, 7, 14], tiles: [[26, 33]], used: false, note: "ice-glazed boulders" }
|
| 3547 |
+
];
|
| 3548 |
+
|
| 3549 |
// ../auto-battler/src/render/sceneViewer.js
|
| 3550 |
function createSceneViewer(pixi, host, { layers, dir, sceneW, sceneH, background = "#15121b", pulse = null }) {
|
| 3551 |
const { Application, Assets, Sprite, Container } = pixi;
|
|
|
|
| 3884 |
root = new Container();
|
| 3885 |
app.stage.addChild(root);
|
| 3886 |
const skin = skins[skinKey];
|
| 3887 |
+
const TILE10 = skin.tile || 8;
|
| 3888 |
+
const res = render3({ app, root, skin, seed, TILE: TILE10, tex, sources, Sprite, Graphics, Container }) || {};
|
| 3889 |
lastBounds = res.bounds || null;
|
| 3890 |
+
lastTile = res.tile ?? TILE10;
|
| 3891 |
lastSnapshot = res.snapshot || {};
|
| 3892 |
if (res.tick) {
|
| 3893 |
tick = res.tick;
|
|
|
|
| 3961 |
fit
|
| 3962 |
});
|
| 3963 |
}
|
| 3964 |
+
function render({ root, skin, seed, TILE: TILE10, tex, sources, Sprite, Graphics }) {
|
| 3965 |
const src = sources.get(skin.url);
|
| 3966 |
const { W, H, floor, rooms, bounds } = generateRooms(seed);
|
| 3967 |
const isF = (x, y) => x >= 0 && y >= 0 && x < W && y < H && floor[y * W + x] === 1;
|
| 3968 |
const addS = (source, coord, x, y) => {
|
| 3969 |
+
const sp = new Sprite(tex(source, coord[0], coord[1], TILE10));
|
| 3970 |
+
sp.x = x * TILE10;
|
| 3971 |
+
sp.y = y * TILE10;
|
| 3972 |
root.addChild(sp);
|
| 3973 |
return sp;
|
| 3974 |
};
|
| 3975 |
const add = (coord, x, y) => addS(src, coord, x, y);
|
| 3976 |
+
const c = { skin, TILE: TILE10, W, H, rooms, seed, isF, add, addS, root, sources, Graphics };
|
| 3977 |
drawWalls(c);
|
| 3978 |
drawFloor(c);
|
| 3979 |
drawShadows(c);
|
|
|
|
| 3983 |
const tick = torch.flames.length && torch.flameSrc ? (ticker) => {
|
| 3984 |
animPhase += 0.14 * ticker.deltaTime;
|
| 3985 |
const fi = Math.floor(animPhase) % torch.flameFrames;
|
| 3986 |
+
for (const fl of torch.flames) fl.sp.texture = tex(torch.flameSrc, fl.col0 + torch.flameStride * fi, fl.row, TILE10);
|
| 3987 |
if (torch.glowG) torch.glowG.alpha = 0.78 + 0.22 * Math.sin(animPhase * 0.9);
|
| 3988 |
} : null;
|
| 3989 |
+
return { bounds, tile: TILE10, snapshot: { rooms: rooms.length }, tick };
|
| 3990 |
}
|
| 3991 |
+
function fit(app, root, b, TILE10) {
|
| 3992 |
const sw = app.screen.width, sh = app.screen.height;
|
| 3993 |
+
const cw = (b.x1 - b.x0 + 3) * TILE10, ch = (b.y1 - b.y0 + 4) * TILE10;
|
| 3994 |
const s = Math.max(1, Math.floor(Math.min(sw / cw, sh / ch)));
|
| 3995 |
root.scale.set(s);
|
| 3996 |
+
root.x = Math.round((sw - cw * s) / 2 - (b.x0 - 1) * TILE10 * s);
|
| 3997 |
+
root.y = Math.round((sh - ch * s) / 2 - (b.y0 - 2) * TILE10 * s);
|
| 3998 |
}
|
| 3999 |
function drawWalls(c) {
|
| 4000 |
if (c.skin.wall && !c.skin.walls) drawBackWall(c);
|
|
|
|
| 4102 |
}
|
| 4103 |
}
|
| 4104 |
function drawShadows(c) {
|
| 4105 |
+
const { W, H, TILE: TILE10, isF, root, Graphics } = c;
|
| 4106 |
const shade = new Graphics();
|
| 4107 |
for (let y = 0; y < H; y++) for (let x = 0; x < W; x++) {
|
| 4108 |
if (!isF(x, y)) continue;
|
| 4109 |
if (!isF(x, y - 1)) {
|
| 4110 |
+
shade.rect(x * TILE10, y * TILE10, TILE10, TILE10).fill({ color: 0, alpha: 0.3 });
|
| 4111 |
+
if (isF(x, y + 1)) shade.rect(x * TILE10, (y + 1) * TILE10, TILE10, TILE10).fill({ color: 0, alpha: 0.12 });
|
| 4112 |
} else if (!isF(x - 1, y) || !isF(x + 1, y)) {
|
| 4113 |
+
shade.rect(x * TILE10, y * TILE10, TILE10, TILE10).fill({ color: 0, alpha: 0.12 });
|
| 4114 |
}
|
| 4115 |
}
|
| 4116 |
root.addChild(shade);
|
|
|
|
| 4157 |
}
|
| 4158 |
}
|
| 4159 |
function drawTorches(c) {
|
| 4160 |
+
const { skin, W, H, TILE: TILE10, isF, sources, root, Graphics, addS } = c;
|
| 4161 |
const torch = skin.torch, torchSrc = torch && sources.get(torch.url);
|
| 4162 |
if (!(torch && torchSrc)) return { flames: [], glowG: null, flameSrc: null, flameStride: 1, flameFrames: 1 };
|
| 4163 |
const flames = [];
|
|
|
|
| 4166 |
for (let y = 0; y < H; y++) for (let x = 0; x < W; x++) {
|
| 4167 |
if (!isF(x, y) || isF(x, y - 1)) continue;
|
| 4168 |
if ((x * 7 + y * 13) % 5 !== 0) continue;
|
| 4169 |
+
const cx = (x + f.w / 2) * TILE10, cy = (y - 1) * TILE10;
|
| 4170 |
+
for (const [r, a] of [[3.2, 0.05], [2.1, 0.08], [1.2, 0.13]]) glow.circle(cx, cy, r * TILE10).fill({ color: torch.glow, alpha: a });
|
| 4171 |
spots.push([x, y]);
|
| 4172 |
}
|
| 4173 |
root.addChild(glow);
|
|
|
|
| 4208 |
fit: fit2
|
| 4209 |
});
|
| 4210 |
}
|
| 4211 |
+
function render2({ root, skin, seed, TILE: TILE10, tex, sources, Sprite, Graphics }) {
|
| 4212 |
const src = sources.get(skin.url);
|
| 4213 |
const shaftW = skin.crown ? skin.crown.shaftW : (skin.roof?.w ?? 7) - 2;
|
| 4214 |
const winH = skin.window?.h ?? 2, doorH = skin.door?.h ?? 2;
|
|
|
|
| 4225 |
const corn = spec.roof === "none" ? 0 : 1;
|
| 4226 |
const dy = -(h2 + PLINTH - 1);
|
| 4227 |
const add = (coord, x, y) => {
|
| 4228 |
+
const sp = new Sprite(tex(src, coord[0], coord[1], TILE10));
|
| 4229 |
+
sp.x = (x + ox) * TILE10;
|
| 4230 |
+
sp.y = (y + dy) * TILE10;
|
| 4231 |
root.addChild(sp);
|
| 4232 |
return sp;
|
| 4233 |
};
|
| 4234 |
const shadow = new Graphics();
|
| 4235 |
+
shadow.ellipse((ox + w / 2) * TILE10, TILE10 - TILE10 * 0.3, wb / 2 * TILE10 + TILE10 * 0.5, TILE10 * 0.7).fill({ color: 0, alpha: 0.22 });
|
| 4236 |
root.addChild(shadow);
|
| 4237 |
for (let y = 0; y < h2; y++) for (let x = 0; x < w; x++) {
|
| 4238 |
const top = y === 0, bot = y === h2 - 1, left = x === 0, right = x === w - 1;
|
|
|
|
| 4294 |
ox += w + GAP;
|
| 4295 |
}
|
| 4296 |
const bounds = { x0: Math.min(x0, 0), y0, x1: Math.max(x1, ox - GAP), y1: 2 };
|
| 4297 |
+
return { bounds, tile: TILE10, snapshot: { w: spec0?.w ?? 0, h: spec0?.h ?? 0, roof: spec0?.roof } };
|
| 4298 |
}
|
| 4299 |
+
function fit2(app, root, b, TILE10) {
|
| 4300 |
const sw = app.screen.width, sh = app.screen.height;
|
| 4301 |
+
const cw = (b.x1 - b.x0) * TILE10, ch = (b.y1 - b.y0) * TILE10;
|
| 4302 |
+
const pad = 4 * TILE10;
|
| 4303 |
const s = Math.max(1, Math.floor(Math.min(sw / (cw + pad), sh / (ch + pad))));
|
| 4304 |
root.scale.set(s);
|
| 4305 |
+
root.x = Math.round((sw - cw * s) / 2 - b.x0 * TILE10 * s);
|
| 4306 |
+
root.y = Math.round((sh - ch * s) / 2 - b.y0 * TILE10 * s);
|
| 4307 |
}
|
| 4308 |
|
| 4309 |
// ../auto-battler/src/render/mapConfigs.js
|
| 4310 |
+
var CITY_SKINS = {
|
| 4311 |
+
medieval: { label: "Medieval City", url: MC_TILES_URL },
|
| 4312 |
+
mountain: { label: "Mountain Stronghold", url: MS_TILES_URL }
|
| 4313 |
+
};
|
| 4314 |
+
var CITY_REF = { medieval: MC_REF, mountain: MS_REF };
|
| 4315 |
+
var citySheets = (skin) => ({
|
| 4316 |
+
medieval: [
|
| 4317 |
+
{ key: "tiles", label: "Tiles", url: MC_TILES_URL, catalog: MC_TILE_CATALOG },
|
| 4318 |
+
{ key: "props", label: "Props", url: MC_PROPS_URL, catalog: MC_PROP_CATALOG }
|
| 4319 |
+
],
|
| 4320 |
+
mountain: [
|
| 4321 |
+
{ key: "tiles", label: "Tiles", url: MS_TILES_URL, catalog: MS_TILE_CATALOG },
|
| 4322 |
+
{ key: "props", label: "Props", url: MS_PROPS_URL, catalog: MS_PROP_CATALOG }
|
| 4323 |
+
]
|
| 4324 |
+
})[skin] || [];
|
| 4325 |
var ASSET = "/assets/minifantasy";
|
| 4326 |
var ORC4 = `${ASSET}/Minifantasy_Orc_Kingdom_v1.0/Minifantasy_Orc_Kingdom_Assets`;
|
| 4327 |
var NECRO4 = `${ASSET}/Minifantasy_Necropolis_v1.0/Minifantasy_Necropolis_Assets`;
|
|
|
|
| 4499 |
...NECRO_SHEETS.map((s) => s.url),
|
| 4500 |
...ORC_SHEETS.map((s) => s.url),
|
| 4501 |
...FP_SHEETS.map((s) => s.url),
|
| 4502 |
+
// Cities: each skin's generated-ground sheet, clickable Tiles/Props, and premade reference layers.
|
| 4503 |
+
...MC_MAP_ASSETS,
|
| 4504 |
+
MC_TILES_URL,
|
| 4505 |
+
MC_PROPS_URL,
|
| 4506 |
+
...sceneUrls(MC_REF.dir, MC_REF.layers),
|
| 4507 |
+
...MS_MAP_ASSETS,
|
| 4508 |
+
MS_TILES_URL,
|
| 4509 |
+
MS_PROPS_URL,
|
| 4510 |
+
...sceneUrls(MS_REF.dir, MS_REF.layers),
|
| 4511 |
// Premade-scene reference layers.
|
| 4512 |
...sceneUrls(NECRO_EXT_DIR, NECRO_LAYERS),
|
| 4513 |
...sceneUrls(ORC_LAYER_DIR, ORC_LAYERS),
|
|
|
|
| 4534 |
var randomSeed = () => Math.floor(Date.now() % 1e6 + Math.random() * 1e6) >>> 0;
|
| 4535 |
var infiniteMeta = (s) => s?.zoom != null ? `\u221E \xB7 seed ${s.seed} \xB7 (${s.cx}, ${s.cy}) \xB7 ${s.zoom.toFixed(2)}\xD7 \xB7 drag / WASD / scroll` : "loading\u2026";
|
| 4536 |
function makeGridOverlay() {
|
| 4537 |
+
const TILE10 = 8;
|
| 4538 |
const cv = h("canvas", { class: "necro-grid-overlay" });
|
| 4539 |
cv.style.display = "none";
|
| 4540 |
let raf = 0, ctrl = null;
|
|
|
|
| 4547 |
if (cv.height !== H) cv.height = H;
|
| 4548 |
const ctx = cv.getContext("2d");
|
| 4549 |
ctx.clearRect(0, 0, W, H);
|
| 4550 |
+
const z = cam.zoom, cell = TILE10 * z;
|
| 4551 |
if (cell >= 6) {
|
| 4552 |
+
const sx = (wx) => (wx * TILE10 - cam.x) * z + W / 2;
|
| 4553 |
+
const sy = (wy) => (wy * TILE10 - cam.y) * z + H / 2;
|
| 4554 |
+
const x0 = Math.floor((cam.x - W / 2 / z) / TILE10), x1 = Math.ceil((cam.x + W / 2 / z) / TILE10);
|
| 4555 |
+
const y0 = Math.floor((cam.y - H / 2 / z) / TILE10), y1 = Math.ceil((cam.y + H / 2 / z) / TILE10);
|
| 4556 |
ctx.strokeStyle = "rgba(255,70,70,0.45)";
|
| 4557 |
ctx.lineWidth = 1;
|
| 4558 |
ctx.beginPath();
|
|
|
|
| 4981 |
var SKIN_MODES = [{ key: "generated", label: "Generated" }, { key: "reference", label: "Reference" }, { key: "tilesheet", label: "Tilesheet" }];
|
| 4982 |
var skinList = (skins) => Object.entries(skins).map(([key, s]) => ({ key, label: s.label }));
|
| 4983 |
var sceneFromRef = (pixi, host, ref) => createSceneViewer(pixi, host, { layers: ref.layers, dir: ref.dir, sceneW: ref.w, sceneH: ref.h, background: ref.bg, pulse: ref.pulse });
|
| 4984 |
+
var CITY_MAPS = { medieval: createMedievalCityMap, mountain: createMountainStrongholdMap };
|
| 4985 |
var PAGES = {
|
| 4986 |
world: (pixi, body, opts) => makePage(pixi, body, {
|
| 4987 |
title: "World Map",
|
|
|
|
| 5054 |
sheets: () => DD_SHEETS,
|
| 5055 |
generatedMeta: infiniteMeta
|
| 5056 |
}),
|
| 5057 |
+
// Cities — same skin-based shape as Interiors/Towers (one pill, a style picker), with the standard
|
| 5058 |
+
// Generated / Reference / Tilesheet sub-pills. Reference = the pack's layer-by-layer premade;
|
| 5059 |
+
// Tilesheet = clickable Tiles/Props catalogue; Generated = the outdoor-floor ground (buildings TBD).
|
| 5060 |
+
cities: (pixi, body) => makePage(pixi, body, {
|
| 5061 |
+
title: "Cities",
|
| 5062 |
+
subtitle: () => "assembled \xB7 layered",
|
| 5063 |
+
modes: SKIN_MODES,
|
| 5064 |
+
skins: skinList(CITY_SKINS),
|
| 5065 |
+
grid: true,
|
| 5066 |
+
makeGenerated: (p, host, seed, skin) => CITY_MAPS[skin](p, host, { seed }),
|
| 5067 |
+
makeScene: (p, host, skin) => sceneFromRef(p, host, CITY_REF[skin]),
|
| 5068 |
+
sheets: (skin) => citySheets(skin),
|
| 5069 |
+
generatedMeta: (snap, label2) => snap ? `ground \xB7 ${label2} \xB7 seed ${snap.seed}` : "loading\u2026"
|
| 5070 |
+
}),
|
| 5071 |
interiors: (pixi, body) => makePage(pixi, body, {
|
| 5072 |
title: "Interiors",
|
| 5073 |
modes: SKIN_MODES,
|
|
|
|
| 5093 |
["gameworld", "Game World"],
|
| 5094 |
["world", "World Map"],
|
| 5095 |
{ group: "biome", label: "Biome", pages: [["plains", "Forgotten Plains"], ["desert", "Desolate Desert"], ["orc", "Orc Kingdom"], ["necropolis", "Necropolis"]] },
|
| 5096 |
+
["cities", "Cities"],
|
| 5097 |
["interiors", "Interiors"],
|
| 5098 |
["towers", "Towers"]
|
| 5099 |
];
|