Title of State:
Resource Definition
Goal of Change:
Avg Node Size = starting balance baseline
Variation % (0–100) = deviation around Avg
- 0% ⇒ every node starts at Avg
- 100% ⇒ range becomes 0 → 2×Avg
Max Node Size = hard cap for every node of that resource
- If variation would exceed Max, Max wins
Generation % (-1000 to 1000) = stored on the node (no behavior yet)
Spawning = checkbox + % rate (stored, no behavior yet)
Also: menu window widened to cover the 1500 viewer
PATCH 0 — Widen menu window to cover viewer
Code to Remove
81 -
.menuPanel{
width:980px;
height:760px;
position:relative;
display:flex;
flex-direction:column;
}
Code to Add
81 -
.menuPanel{
width:1500px;
height:900px;
position:relative;
display:flex;
flex-direction:column;
}
PATCH 1 — Make resource rows support lots of controls (CSS)
Code to Remove
192 -
.resRow{
display:flex;
align-items:center;
justify-content:space-between;
gap:12px;
padding:10px 10px;
border-radius:10px;
border:1px solid rgba(255,255,255,.10);
background:rgba(0,0,0,.18);
}
.countInput{
width:110px;
padding:10px 10px;
border-radius:10px;
border:1px solid rgba(255,255,255,.16);
background:rgba(0,0,0,.25);
color:#e9f0ff;
font-size:14px;
outline:none;
text-align:right;
}
Code to Add
192 -
.resRow{
display:flex;
align-items:center;
justify-content:flex-start;
gap:10px;
padding:10px 10px;
border-radius:10px;
border:1px solid rgba(255,255,255,.10);
background:rgba(0,0,0,.18);
flex-wrap:wrap;
}
.miniLabel{
font-size:12px;
opacity:.75;
user-select:none;
white-space:nowrap;
}
.countInput{
width:80px;
padding:10px 10px;
border-radius:10px;
border:1px solid rgba(255,255,255,.16);
background:rgba(0,0,0,.25);
color:#e9f0ff;
font-size:14px;
outline:none;
text-align:right;
}
.numInput{
width:110px;
padding:10px 10px;
border-radius:10px;
border:1px solid rgba(255,255,255,.16);
background:rgba(0,0,0,.25);
color:#e9f0ff;
font-size:14px;
outline:none;
text-align:right;
}
.pctInput{
width:90px;
padding:10px 10px;
border-radius:10px;
border:1px solid rgba(255,255,255,.16);
background:rgba(0,0,0,.25);
color:#e9f0ff;
font-size:14px;
outline:none;
text-align:right;
}
.spawnRow{
display:flex;
align-items:center;
gap:8px;
opacity:.9;
font-size:12px;
white-space:nowrap;
}
PATCH 2 — MENU HTML: replace the 4 resource rows with full controls
Code to Remove
339 -
<div class="resRow">
<label class="chkRow">
<input id="resOreOn" type="checkbox" checked />
<span>Ore</span>
</label>
<label class="chkRow smallChk">
<input id="resOreHidden" type="checkbox" />
<span>Hidden</span>
</label>
<input id="resOreCount" class="countInput" type="number" step="1" min="0" value="40" />
</div>
<div class="resRow">
<label class="chkRow">
<input id="resStoneOn" type="checkbox" checked />
<span>Stone</span>
</label>
<label class="chkRow smallChk">
<input id="resStoneHidden" type="checkbox" />
<span>Hidden</span>
</label>
<input id="resStoneCount" class="countInput" type="number" step="1" min="0" value="35" />
</div>
<div class="resRow">
<label class="chkRow">
<input id="resOilOn" type="checkbox" checked />
<span>Oil</span>
</label>
<label class="chkRow smallChk">
<input id="resOilHidden" type="checkbox" checked />
<span>Hidden</span>
</label>
<input id="resOilCount" class="countInput" type="number" step="1" min="0" value="12" />
</div>
<div class="resRow">
<label class="chkRow">
<input id="resWoodOn" type="checkbox" checked />
<span>Wood</span>
</label>
<label class="chkRow smallChk">
<input id="resWoodHidden" type="checkbox" />
<span>Hidden</span>
</label>
<input id="resWoodCount" class="countInput" type="number" step="1" min="0" value="55" />
</div>
Code to Add
192 -
<div class="resRow">
<label class="chkRow">
<input id="resOreOn" type="checkbox" checked />
<span>Ore</span>
</label>
<label class="chkRow smallChk">
<input id="resOreHidden" type="checkbox" />
<span>Hidden</span>
</label>
<span class="miniLabel">#</span>
<input id="resOreCount" class="countInput" type="number" step="1" min="0" value="40" />
<span class="miniLabel">Avg</span>
<input id="resOreAvg" class="numInput" type="number" step="1" min="0" value="700" />
<span class="miniLabel">Var%</span>
<input id="resOreVar" class="pctInput" type="number" step="1" min="0" max="100" value="20" />
<span class="miniLabel">Max</span>
<input id="resOreMax" class="numInput" type="number" step="1" min="1" value="1200" />
<span class="miniLabel">Gen%</span>
<input id="resOreGen" class="pctInput" type="number" step="1" min="-1000" max="1000" value="0" />
<label class="spawnRow">
<input id="resOreSpawnOn" type="checkbox" />
<span>Spawn</span>
</label>
<span class="miniLabel">Rate%</span>
<input id="resOreSpawnRate" class="pctInput" type="number" step="1" min="0" max="100" value="0" />
</div>
<div class="resRow">
<label class="chkRow">
<input id="resStoneOn" type="checkbox" checked />
<span>Stone</span>
</label>
<label class="chkRow smallChk">
<input id="resStoneHidden" type="checkbox" />
<span>Hidden</span>
</label>
<span class="miniLabel">#</span>
<input id="resStoneCount" class="countInput" type="number" step="1" min="0" value="35" />
<span class="miniLabel">Avg</span>
<input id="resStoneAvg" class="numInput" type="number" step="1" min="0" value="900" />
<span class="miniLabel">Var%</span>
<input id="resStoneVar" class="pctInput" type="number" step="1" min="0" max="100" value="15" />
<span class="miniLabel">Max</span>
<input id="resStoneMax" class="numInput" type="number" step="1" min="1" value="1600" />
<span class="miniLabel">Gen%</span>
<input id="resStoneGen" class="pctInput" type="number" step="1" min="-1000" max="1000" value="0" />
<label class="spawnRow">
<input id="resStoneSpawnOn" type="checkbox" />
<span>Spawn</span>
</label>
<span class="miniLabel">Rate%</span>
<input id="resStoneSpawnRate" class="pctInput" type="number" step="1" min="0" max="100" value="0" />
</div>
<div class="resRow">
<label class="chkRow">
<input id="resOilOn" type="checkbox" checked />
<span>Oil</span>
</label>
<label class="chkRow smallChk">
<input id="resOilHidden" type="checkbox" checked />
<span>Hidden</span>
</label>
<span class="miniLabel">#</span>
<input id="resOilCount" class="countInput" type="number" step="1" min="0" value="12" />
<span class="miniLabel">Avg</span>
<input id="resOilAvg" class="numInput" type="number" step="1" min="0" value="1200" />
<span class="miniLabel">Var%</span>
<input id="resOilVar" class="pctInput" type="number" step="1" min="0" max="100" value="25" />
<span class="miniLabel">Max</span>
<input id="resOilMax" class="numInput" type="number" step="1" min="1" value="2500" />
<span class="miniLabel">Gen%</span>
<input id="resOilGen" class="pctInput" type="number" step="1" min="-1000" max="1000" value="0" />
<label class="spawnRow">
<input id="resOilSpawnOn" type="checkbox" />
<span>Spawn</span>
</label>
<span class="miniLabel">Rate%</span>
<input id="resOilSpawnRate" class="pctInput" type="number" step="1" min="0" max="100" value="0" />
</div>
<div class="resRow">
<label class="chkRow">
<input id="resWoodOn" type="checkbox" checked />
<span>Wood</span>
</label>
<label class="chkRow smallChk">
<input id="resWoodHidden" type="checkbox" />
<span>Hidden</span>
</label>
<span class="miniLabel">#</span>
<input id="resWoodCount" class="countInput" type="number" step="1" min="0" value="55" />
<span class="miniLabel">Avg</span>
<input id="resWoodAvg" class="numInput" type="number" step="1" min="0" value="300" />
<span class="miniLabel">Var%</span>
<input id="resWoodVar" class="pctInput" type="number" step="1" min="0" max="100" value="35" />
<span class="miniLabel">Max</span>
<input id="resWoodMax" class="numInput" type="number" step="1" min="1" value="900" />
<span class="miniLabel">Gen%</span>
<input id="resWoodGen" class="pctInput" type="number" step="1" min="-1000" max="1000" value="0" />
<label class="spawnRow">
<input id="resWoodSpawnOn" type="checkbox" checked />
<span>Spawn</span>
</label>
<span class="miniLabel">Rate%</span>
<input id="resWoodSpawnRate" class="pctInput" type="number" step="1" min="0" max="100" value="5" />
</div>
PATCH 3 — JS: grab new controls
Code to Remove
516 -
const resOreCount = document.getElementById("resOreCount");
const resStoneCount = document.getElementById("resStoneCount");
const resOilCount = document.getElementById("resOilCount");
const resWoodCount = document.getElementById("resWoodCount");
Code to Add
516 -
const resOreCount = document.getElementById("resOreCount");
const resStoneCount = document.getElementById("resStoneCount");
const resOilCount = document.getElementById("resOilCount");
const resWoodCount = document.getElementById("resWoodCount");
const resOreAvg = document.getElementById("resOreAvg");
const resOreVar = document.getElementById("resOreVar");
const resOreMax = document.getElementById("resOreMax");
const resOreGen = document.getElementById("resOreGen");
const resOreSpawnOn = document.getElementById("resOreSpawnOn");
const resOreSpawnRate = document.getElementById("resOreSpawnRate");
const resStoneAvg = document.getElementById("resStoneAvg");
const resStoneVar = document.getElementById("resStoneVar");
const resStoneMax = document.getElementById("resStoneMax");
const resStoneGen = document.getElementById("resStoneGen");
const resStoneSpawnOn = document.getElementById("resStoneSpawnOn");
const resStoneSpawnRate = document.getElementById("resStoneSpawnRate");
const resOilAvg = document.getElementById("resOilAvg");
const resOilVar = document.getElementById("resOilVar");
const resOilMax = document.getElementById("resOilMax");
const resOilGen = document.getElementById("resOilGen");
const resOilSpawnOn = document.getElementById("resOilSpawnOn");
const resOilSpawnRate = document.getElementById("resOilSpawnRate");
const resWoodAvg = document.getElementById("resWoodAvg");
const resWoodVar = document.getElementById("resWoodVar");
const resWoodMax = document.getElementById("resWoodMax");
const resWoodGen = document.getElementById("resWoodGen");
const resWoodSpawnOn = document.getElementById("resWoodSpawnOn");
const resWoodSpawnRate = document.getElementById("resWoodSpawnRate");
PATCH 4 — JS: read Avg/Var/Max/Gen/Spawn settings into readResourceSettings()
Code to Remove
784 -
return {
Enabled: on,
Ore: { Enabled: on && oreOn, Count: oreCount, Hidden: !!resOreHidden.checked },
Stone: { Enabled: on && stoneOn, Count: stoneCount, Hidden: !!resStoneHidden.checked },
Oil: { Enabled: on && oilOn, Count: oilCount, Hidden: !!resOilHidden.checked },
Wood: { Enabled: on && woodOn, Count: woodCount, Hidden: !!resWoodHidden.checked },
};
Code to Add
784 -
const clamp01 = (v)=> Math.max(0, Math.min(100, v|0));
const clampGen = (v)=> Math.max(-1000, Math.min(1000, v|0));
const oreAvg = Math.max(0, (Number(resOreAvg.value) | 0));
const oreVar = clamp01(Number(resOreVar.value));
const oreMax = Math.max(1, (Number(resOreMax.value) | 0));
const oreGen = clampGen(Number(resOreGen.value));
const oreSpawnOn = !!resOreSpawnOn.checked;
const oreSpawnRate = clamp01(Number(resOreSpawnRate.value));
const stoneAvg = Math.max(0, (Number(resStoneAvg.value) | 0));
const stoneVar = clamp01(Number(resStoneVar.value));
const stoneMax = Math.max(1, (Number(resStoneMax.value) | 0));
const stoneGen = clampGen(Number(resStoneGen.value));
const stoneSpawnOn = !!resStoneSpawnOn.checked;
const stoneSpawnRate = clamp01(Number(resStoneSpawnRate.value));
const oilAvg = Math.max(0, (Number(resOilAvg.value) | 0));
const oilVar = clamp01(Number(resOilVar.value));
const oilMax = Math.max(1, (Number(resOilMax.value) | 0));
const oilGen = clampGen(Number(resOilGen.value));
const oilSpawnOn = !!resOilSpawnOn.checked;
const oilSpawnRate = clamp01(Number(resOilSpawnRate.value));
const woodAvg = Math.max(0, (Number(resWoodAvg.value) | 0));
const woodVar = clamp01(Number(resWoodVar.value));
const woodMax = Math.max(1, (Number(resWoodMax.value) | 0));
const woodGen = clampGen(Number(resWoodGen.value));
const woodSpawnOn = !!resWoodSpawnOn.checked;
const woodSpawnRate = clamp01(Number(resWoodSpawnRate.value));
return {
Enabled: on,
Ore: { Enabled: on && oreOn, Count: oreCount, Hidden: !!resOreHidden.checked, Avg: oreAvg, Var: oreVar, Max: oreMax, Gen: oreGen, SpawnOn: oreSpawnOn, SpawnRate: oreSpawnRate },
Stone: { Enabled: on && stoneOn, Count: stoneCount, Hidden: !!resStoneHidden.checked, Avg: stoneAvg, Var: stoneVar, Max: stoneMax, Gen: stoneGen, SpawnOn: stoneSpawnOn, SpawnRate: stoneSpawnRate },
Oil: { Enabled: on && oilOn, Count: oilCount, Hidden: !!resOilHidden.checked, Avg: oilAvg, Var: oilVar, Max: oilMax, Gen: oilGen, SpawnOn: oilSpawnOn, SpawnRate: oilSpawnRate },
Wood: { Enabled: on && woodOn, Count: woodCount, Hidden: !!resWoodHidden.checked, Avg: woodAvg, Var: woodVar, Max: woodMax, Gen: woodGen, SpawnOn: woodSpawnOn, SpawnRate: woodSpawnRate },
};
PATCH 5 — JS: apply your Avg/Var/Max rules in node creation
Code to Remove
836 -
const pushN = (type, n)=>{
for(let i=0;i<n;i++){
const node = {
Type: type,
X: randRange(minX, maxX),
Y: randRange(minY, maxY),
Radius: 16,
Hidden: false,
Revealed: true,
};
S.resources.push(node);
}
};
Code to Add
836 -
const pushN = (type, n, cfg)=>{
// Avg = starting balance baseline
// Var% = 0..100:
// 0% => start = Avg
// 100% => start in [0, 2*Avg]
// Max = hard cap; if start > Max, clamp to Max
const avg = Math.max(0, cfg.Avg | 0);
const varPct = Math.max(0, Math.min(100, cfg.Var | 0));
const maxCap = Math.max(avg + 1, cfg.Max | 0); // enforce max > avg
for(let i=0;i<n;i++){
// t in [-1, +1]
const t = (RNG() * 2) - 1;
const start = avg * (1 + t * (varPct / 100));
let amt = Math.floor(start);
if(amt < 0) amt = 0;
if(amt > maxCap) amt = maxCap;
const node = {
Type: type,
X: randRange(minX, maxX),
Y: randRange(minY, maxY),
Radius: 16,
MaxRemaining: maxCap, // flat cap for the type
Remaining: amt, // starting balance per your rule
GenerationPct: cfg.Gen, // stored only (no behavior yet)
SpawnOn: !!cfg.SpawnOn, // stored only (no behavior yet)
SpawnRate: cfg.SpawnRate, // stored only (no behavior yet)
Hidden: false,
Revealed: true,
};
S.resources.push(node);
}
};
Ore
Code to Remove
887 -
pushN("ORE", S.resourceSettings.Ore.Count);
Code to Add
887 -
pushN("ORE", S.resourceSettings.Ore.Count, S.resourceSettings.Ore);
Stone
Code to Remove
893 -
pushN("STONE", S.resourceSettings.Stone.Count);
Code to Add
893 -
pushN("STONE", S.resourceSettings.Stone.Count, S.resourceSettings.Stone);
Oil
Code to Remove
899 -
pushN("OIL", S.resourceSettings.Oil.Count);
Code to Add
899 -
pushN("OIL", S.resourceSettings.Oil.Count, S.resourceSettings.Oil);
Wood
Code to Remove
905 -
pushN("WOOD", S.resourceSettings.Wood.Count);
Code to Add
905 -
pushN("WOOD", S.resourceSettings.Wood.Count, S.resourceSettings.Wood);
PATCH 6 — HUD: show AMT as Remaining/MaxCap for selection
Code to Remove
1117 -
selLine = `\\nSEL: #${si} ${n.Type} @ ${Math.floor(n.X)},${Math.floor(n.Y)}`;
Code to Add
1117 -
selLine = `\\nSEL: #${si} ${n.Type} @ ${Math.floor(n.X)},${Math.floor(n.Y)} AMT: ${n.Remaining}/${n.MaxRemaining}`;
Insert spawn function
Code to Remove
1021 -
insert line
Code to Add
1021 -
/* =========================
GENERIC SPAWNING
========================= */
function spawnFromNode(parent, dt){
if(!parent.SpawnOn) return;
const rate = Math.max(0, Math.min(100, parent.SpawnRate|0));
const chancePerSecond = rate / 100;
if(RNG() > chancePerSecond * dt) return;
const angle = RNG() * Math.PI * 2;
const dist = 40 + RNG() * 100;
const nx = parent.X + Math.cos(angle) * dist;
const ny = parent.Y + Math.sin(angle) * dist;
if(nx < 40 || ny < 40 || nx > MAP_SIZE-40 || ny > MAP_SIZE-40) return;
for(const r of S.resources){
const dx = r.X - nx;
const dy = r.Y - ny;
if(dx*dx + dy*dy < 30*30) return;
}
S.resources.push({
Type: parent.Type,
X: nx,
Y: ny,
Radius: parent.Radius,
MaxRemaining: parent.MaxRemaining,
Remaining: parent.Remaining,
GenerationPct: parent.GenerationPct,
SpawnOn: parent.SpawnOn,
SpawnRate: parent.SpawnRate,
Hidden: false,
Revealed: true,
});
}
Add spawn pass inside update()
Code to Remove
1086 -
// Clamp to map bounds
const maxCam = MAP_SIZE - VIEW;
S.camX = clamp(S.camX, 0, maxCam);
S.camY = clamp(S.camY, 0, maxCam);
}
Code to Add
1086 -
// Clamp to map bounds
const maxCam = MAP_SIZE - VIEW;
S.camX = clamp(S.camX, 0, maxCam);
S.camY = clamp(S.camY, 0, maxCam);
// ---- Spawning pass ----
if(S.resources && S.resources.length){
const initialCount = S.resources.length;
for(let i=0;i<initialCount;i++){
const r = S.resources[i];
if(r && r.SpawnOn){
spawnFromNode(r, dt);
}
}
}
}
Apply Generation as Units/Sec in update(dt)
Code to Remove
1091 -
// ---- Spawning pass ----
if(S.resources && S.resources.length){
const initialCount = S.resources.length;
for(let i=0;i<initialCount;i++){
const r = S.resources[i];
if(r && r.SpawnOn){
spawnFromNode(r, dt);
}
}
}
}
Code to Add
1091 -
// ---- Generation / Decay pass ----
if(S.resources && S.resources.length){
for(const r of S.resources){
if(typeof r.GenerationPct === "number"){
const delta = r.GenerationPct * dt; // units per second
r.Remaining += delta;
if(r.Remaining < 0) r.Remaining = 0;
if(r.MaxRemaining != null && r.Remaining > r.MaxRemaining){
r.Remaining = r.MaxRemaining;
}
}
}
}
// ---- Spawning pass ----
if(S.resources && S.resources.length){
const initialCount = S.resources.length;
for(let i=0;i<initialCount;i++){
const r = S.resources[i];
if(r && r.SpawnOn){
spawnFromNode(r, dt);
}
}
}
}
Rename GenerationPct to GenerationRate (cleaner, optional but correct)
Code to Remove
863 -
GenerationPct: cfg.Gen, // stored only (no behavior yet)
Code to Add
863 -
GenerationRate: cfg.Gen,
Rename GenerationPct to GenerationRate (cleaner, optional but correct)
Code to Remove
1094 -
if(typeof r.GenerationPct === "number"){
const delta = r.GenerationPct * dt; // units per second
Code to Add
1094 -
if(typeof r.GenerationRate === "number"){
const delta = r.GenerationRate * dt;