<!-- SAGA-SOLID · part 74 -->
= 80;
  window._castles.forEach(function(g){
    var d = Math.hypot(g.position.x - kingPos.x, g.position.z - kingPos.z);
    if(d < bd){ bd = d; best = g; }
  });
  if(!best){ say('no castle near'); return; }
  var ox = best.position.x, oz = best.position.z;
  var nx = kingPos.x + 40, nz = kingPos.z + 40;
  best.position.set(nx, 0, nz);
  try{
    var list = JSON.parse(localStorage.getItem('saga-solid-castles') || '[]');
    var bi = -1, bdd = 80;
    list.forEach(function(c, idx){
      var d = Math.hypot(c.x - ox, c.z - oz);
      if(d < bdd){ bdd = d; bi = idx; }
    });
    if(bi > -1) list.splice(bi, 1);
    list.push({x:Math.round(nx), z:Math.round(nz)});
    localStorage.setItem('saga-solid-castles', JSON.stringify(list));
  }catch(e){ console.error(e); }
  say('castle moved');
}};
window.__sagaExecMark('MOVECASTLE OK');
window.__sagaExecMark('6063');
window._bamBlocks = window._bamBlocks || [];
function saveBamBlocks(){
  try{
    var list = window._bamBlocks.map(function(m){
      var b = m.userData.bam || {w:10, h:10, d:10};
      return {w:b.w, h:b.h, d:b.d,
        x:Math.round(m.position.x*100)/100, y:Math.round(m.position.y*100)/100, z:Math.round(m.position.z*100)/100,
        ry:Math.round(m.rotation.y*100)/100,
        sx:m.scale.x, sy:m.scale.y, sz:m.scale.z};
    });
    localStorage.setItem('saga-solid-blocks', JSON.stringify(list));
  }catch(e){ console.error(e); }
}
function restoreBamBlocks(){
  try{
    var list = JSON.parse(localStorage.getItem('saga-solid-blocks') || '[]');
    list.forEach(function(b){
      var mesh = new THREE.Mesh(new THREE.BoxGeometry(b.w, b.h, b.d), goldMat);
      mesh.position.set(b.x, b.y, b.z);
      mesh.rotation.y = b.ry || 0;
      mesh.scale.set(b.sx || 1, b.sy || 1, b.sz || 1);
      mesh.userData.bam = {w:b.w, h:b.h, d:b.d};
      mesh.userData.staysOnMap = true;
      scene.add(mesh);
      window._bamBlocks.push(mesh);
    });
    if(list.length && typeof say === 'function') say(list.length + ' blocks restored');
  }catch(e){ console.error(e); }
}
window.__sagaExecMark('6050');

/* Restore the King's castles on every load — forever means forever */
restoreCastles();
restoreBamBlocks();

/* THE HEROES LOCKER — the one block that holds every inventory. King order 2026-10-05. */
function lockerInventory(){
  var inv = {castles:[], blocks:[]};
  try{ inv.castles = JSON.parse(localStorage.getItem('saga-solid-castles') || '[]'); }catch(e){ console.error(e); }
  try{ inv.blocks = JSON.parse(localStorage.getItem('saga-solid-blocks') || '[]'); }catch(e){ console.error(e); }
  return inv;
}
function sayLocker(){
  var inv = lockerInventory();
  var msg = 'Heroes Locker: ' + inv.castles.length + ' castle' + (inv.castles.length === 1 ? '' : 's') +
    ', ' + inv.blocks.length + ' block' + (inv.blocks.length === 1 ? '' : 's');
  if(typeof say === 'function') say(msg);
}
function buildHeroesLocker(){
  try{
    var lx = 30, lz = 30;
    var g = new THREE.Group();
    var dark = new THREE.MeshStandardMaterial({color:0x1a1a2e, roughness:0.5, metalness:0.6});
    var gold = new THREE.MeshStandardMaterial({color:0xd8a920, roughness:0.3, metalness:0.8});
    var body = new THREE.Mesh(new THREE.BoxGeometry(6, 8, 4), dark);
    body.position.y = 4; g.add(body);
    var trim = new THREE.Mesh(new THREE.BoxGeometry(6.6, 0.8, 4.6), gold);
    trim.position.y = 8.2; g.add(trim);
    var base = new THREE.Mesh(new THREE.BoxGeometry(6.6, 0.8, 4.6), gold);
    base.position.y = 0.4; g.add(base);
    var cv = document.createElement('canvas'); cv.width = 256; cv.height = 128;
    var c = cv.getContext('2d');
    c.fillStyle = '#0a0a12'; c.fillRect(0, 0, 256, 128);
    c.strokeStyle = '#ffd700'; c.lineWidth = 5; c.strokeRect(6, 6, 244, 116);
    c.font = 'bold 30px Georgia'; c.textAlign = 'center';
    c.fillStyle = '#ffe9a8'; c.fillText('HEROES', 128, 55); c.fillText('LOCKER', 128, 95);
    var tex = new THREE.CanvasTexture(cv);
    var face = new THREE.Mesh(new THREE.PlaneGeometry(5.4, 2.7),
      new THREE.MeshBasicMaterial({map:tex}));
    face.position.set(0, 4.5, 2.05); g.add(face);
    g.position.set(lx, 0, lz);
    g.userData.toolName = 'locker';
    g.userData.isLocker = true;
    scene.add(g);
    if(!window._toolSwitches) window._toolSwitches = [];
    window._toolSwitches.push(body); body.userData.toolName = 'locker';
    window._toolSwitches.push(face); face.userData.toolName = 'locker';
    /* gold beacon so the locker is findable */
    var beam = new THREE.Mesh(
      new THREE.CylinderGeometry(0.8, 0.8, 300, 8),
      new THREE.MeshBasicMaterial({color:0xffd700, transparent:true, opacity:0.3, blending:THREE.AdditiveBlending, depthWrite:false})
    );
    beam.position.set(lx, 150, lz);
    scene.add(beam);
    if(typeof trackNewThing === 'function') trackNewThing('heroes-locker', 'The Heroes Locker — source of every inventory on the map');
  }catch(e){ console.error(e); }
}
CODES['briefing'] = {cat:'Special', desc:'The Morning Brie