- Full classic layer: roads/walkers, 11-tier housing evolution, food chain, industry chains, trade routes, taxes/wages, ratings, fires & collapse - Fantasy layer: heroes (XP/levels/auras), mana & 7 spells, monsters/invasions, walls/towers/legions/golems, campaign of 5 scenarios + endless sandbox - Canvas2D isometric engine with procedural sprites, zero runtime deps - Save/load slots + autosave, WebAudio synth music/SFX, HUD/menus/minimap - Tests: headless sim smoke test + Playwright E2E (build/combat/save)
43 lines
2.0 KiB
TypeScript
43 lines
2.0 KiB
TypeScript
import { CAMPAIGN } from '../src/data/scenarios';
|
|
import { createCity, tickCity, placeBuilding } from '../src/sim/city';
|
|
import { ensureSimHooks } from '../src/sim/hooks';
|
|
|
|
const c = createCity(CAMPAIGN[0]);
|
|
ensureSimHooks();
|
|
let ox=-1, oy=-1;
|
|
outer: for (let y=8;y<c.H-12;y++) for (let x=8;x<c.W-14;x++){
|
|
let ok=true;
|
|
for (let dy=-2; dy<8 && ok; dy++) for (let dx=-2;dx<26;dx++){
|
|
const t=c.tiles[(y+dy)*c.W+(x+dx)];
|
|
if(!t||t.terrain==='water'||t.terrain==='tree'||t.terrain==='rock'){ok=false;break;}
|
|
}
|
|
if(ok){ox=x;oy=y;break outer;}
|
|
}
|
|
for(let i=0;i<22;i++) placeBuilding(c,'road',ox+i,oy);
|
|
for(let i=1;i<21;i++) placeBuilding(c,'house',ox+i,oy-1);
|
|
placeBuilding(c,'well',ox+2,oy+1);
|
|
placeBuilding(c,'market',ox+4,oy+1);
|
|
placeBuilding(c,'granary',ox+8,oy+1);
|
|
placeBuilding(c,'prefecture',ox+12,oy+1);
|
|
let farmPlaced=false;
|
|
for (const [fdx,fdy] of [[15,1],[14,1],[16,4],[13,4]] as const){
|
|
if(placeBuilding(c,'farmWheat',ox+fdx,oy+fdy).ok){farmPlaced=true;console.log('farm at',fdx,fdy);break;}
|
|
}
|
|
|
|
const dump=(label:string)=>{
|
|
const f=[...c.buildings.values()].find(b=>b.def==='farmWheat')!;
|
|
const g=[...c.buildings.values()].find(b=>b.def==='granary')!;
|
|
const m=[...c.buildings.values()].find(b=>b.def==='market')!;
|
|
console.log(`--- ${label} (month ${c.month})`);
|
|
console.log(`farm workers=${f.workersLive} progress=${f.progress.toFixed(2)} wheat=${f.inv['wheat']??0}`);
|
|
console.log(`granary wheat=${g.inv['wheat']??0}`);
|
|
console.log(`market workers=${m.workersLive} inv=`, JSON.stringify(m.inv));
|
|
const wk=[...c.walkers.values()];
|
|
console.log('walkers:', wk.map(w=>`${w.kind}${w.cargo?'('+JSON.stringify(w.cargo)+')':''}`).slice(0,12).join(', '));
|
|
const hs=[...c.buildings.values()].filter(b=>b.def==='house');
|
|
const fed=hs.filter(h=>((h.goodsStock?.['wheat']??0)+(h.goodsStock?.['fruit']??0))>0).length;
|
|
console.log(`houses=${hs.length} residents=${hs.reduce((a,b)=>a+b.residents,0)} fed=${fed}`);
|
|
};
|
|
dump('start');
|
|
for (let i=0;i<20*20;i++){ tickCity(c,CAMPAIGN[0],0.5); if(i===199||i===399) dump(`t+${Math.round(i*0.5)}s`); }
|