diff --git a/editor.html b/editor.html index 91bb2a7..65fa30e 100644 --- a/editor.html +++ b/editor.html @@ -224,7 +224,7 @@ function init() { // Init map data for all maps for (const id of Object.keys(mapConfigs)) { - mapData[id] = { walls: new Set(), spawn: { x: 0, y: 0 }, npcs: [], exits: [], interactions: [] }; + mapData[id] = { walls: new Set(), spawn: null, npcs: [], exits: [], interactions: [] }; } // Load current game data @@ -283,7 +283,7 @@ function loadCurrentGameData() { 11: [0,1,2,3,6,7,8,9] }; mapData.lab.walls = wallDataToSet(labWalls); - mapData.lab.spawn = { x: 4, y: 10 }; + mapData.lab.spawn = null; // No spawn β player enters via door from town mapData.lab.npcs = [ { id: 'professor', x: 5, y: 1, facing: 'down', dialog: ['Welcome to the Circuit Lab!','I\'m the Professor. We study logic gates here.','Use the workshop tables to design circuits.','Press TAB to open the Workshop anytime!'] } ]; @@ -345,12 +345,14 @@ function wallDataToSet(data) { function switchMap(id) { currentMapId = id; selectedEntity = null; - // Center camera on spawn + // Center camera on spawn or map center const md = mapData[id]; const cfg = mapConfigs[id]; if (md && cfg) { - camera.x = -(md.spawn.x * TILE_PX - canvas.width / 2 + TILE_PX / 2); - camera.y = -(md.spawn.y * TILE_PX - canvas.height / 2 + TILE_PX / 2); + const cx = md.spawn ? md.spawn.x : Math.floor(cfg.widthTiles / 2); + const cy = md.spawn ? md.spawn.y : Math.floor(cfg.heightTiles / 2); + camera.x = -(cx * TILE_PX - canvas.width / 2 + TILE_PX / 2); + camera.y = -(cy * TILE_PX - canvas.height / 2 + TILE_PX / 2); } updateEntityList(); updateProps(); @@ -419,14 +421,17 @@ function render() { ctx.stroke(); } - // Spawn - const sp = md.spawn; - ctx.fillStyle = 'rgba(0, 229, 153, 0.4)'; - ctx.fillRect(sp.x * TILE_PX, sp.y * TILE_PX, TILE_PX, TILE_PX); - ctx.strokeStyle = '#00e599'; - ctx.lineWidth = 2; - ctx.strokeRect(sp.x * TILE_PX, sp.y * TILE_PX, TILE_PX, TILE_PX); - drawLabel(ctx, 'π ', sp.x, sp.y); + // Spawn (optional β only needed on the starting map) + if (md.spawn) { + const sp = md.spawn; + const spSel = selectedEntity?.type === 'spawn'; + ctx.fillStyle = 'rgba(0, 229, 153, 0.4)'; + ctx.fillRect(sp.x * TILE_PX, sp.y * TILE_PX, TILE_PX, TILE_PX); + ctx.strokeStyle = spSel ? '#fff' : '#00e599'; + ctx.lineWidth = spSel ? 2.5 : 2; + ctx.strokeRect(sp.x * TILE_PX, sp.y * TILE_PX, TILE_PX, TILE_PX); + drawLabel(ctx, 'π ', sp.x, sp.y); + } // Exits md.exits.forEach((e, i) => { @@ -548,8 +553,15 @@ function onMouseDown(e) { render(); break; case 'spawn': - md.spawn = { x: tile.x, y: tile.y }; - updateEntityList(); render(); + // Toggle: if spawn already at this tile, remove it; otherwise place/move + if (md.spawn && md.spawn.x === tile.x && md.spawn.y === tile.y) { + md.spawn = null; + selectedEntity = null; + } else { + md.spawn = { x: tile.x, y: tile.y }; + selectedEntity = { type: 'spawn', index: 0 }; + } + updateEntityList(); updateProps(); render(); break; case 'npc': md.npcs.push({ id: `npc_${Date.now()}`, x: tile.x, y: tile.y, facing: 'down', dialog: ['Hello!'] }); @@ -597,7 +609,7 @@ function onMouseMove(e) { const key = `${tile.x},${tile.y}`; let info = ''; if (md.walls.has(key)) info += 'Wall '; - if (md.spawn.x === tile.x && md.spawn.y === tile.y) info += 'Spawn '; + if (md.spawn && md.spawn.x === tile.x && md.spawn.y === tile.y) info += 'Spawn '; md.npcs.forEach(n => { if (n.x === tile.x && n.y === tile.y) info += `NPC:${n.id} `; }); md.exits.forEach(e => { if (e.x === tile.x && e.y === tile.y) info += `Exitβ${e.targetMap}(${e.targetX ?? '?'},${e.targetY ?? '?'}) `; }); md.interactions.forEach(i => { if (i.x === tile.x && i.y === tile.y) info += `${i.type}:${i.label} `; }); @@ -655,7 +667,8 @@ function onKeyDown(e) { e.preventDefault(); const md = getData(); const { type, index } = selectedEntity; - if (type === 'npc') md.npcs.splice(index, 1); + if (type === 'spawn') md.spawn = null; + else if (type === 'npc') md.npcs.splice(index, 1); else if (type === 'exit') md.exits.splice(index, 1); else if (type === 'interaction') md.interactions.splice(index, 1); selectedEntity = null; @@ -731,13 +744,15 @@ function selectEntityAt(tx, ty) { idx = md.interactions.findIndex(i => i.x === tx && i.y === ty); if (idx >= 0) { selectedEntity = { type: 'interaction', index: idx }; updateEntityList(); updateProps(); return; } // Spawn? - if (md.spawn.x === tx && md.spawn.y === ty) { selectedEntity = { type: 'spawn', index: 0 }; updateEntityList(); updateProps(); return; } + if (md.spawn && md.spawn.x === tx && md.spawn.y === ty) { selectedEntity = { type: 'spawn', index: 0 }; updateEntityList(); updateProps(); return; } selectedEntity = null; updateEntityList(); updateProps(); } function deleteEntityAt(tx, ty) { const md = getData(); + // Spawn + if (md.spawn && md.spawn.x === tx && md.spawn.y === ty) { md.spawn = null; selectedEntity = null; updateEntityList(); updateProps(); return; } let idx = md.npcs.findIndex(n => n.x === tx && n.y === ty); if (idx >= 0) { md.npcs.splice(idx, 1); selectedEntity = null; updateEntityList(); updateProps(); return; } idx = md.exits.findIndex(e => e.x === tx && e.y === ty); @@ -751,7 +766,9 @@ function deleteEntityAt(tx, ty) { function updateEntityList() { const md = getData(); - document.getElementById('spawn-list').innerHTML = makeEntityItem('spawn', 0, 'π ', `Spawn`, md.spawn.x, md.spawn.y); + document.getElementById('spawn-list').innerHTML = md.spawn + ? makeEntityItem('spawn', 0, 'π ', `Spawn`, md.spawn.x, md.spawn.y) + : '