微件:LevelEditor:修订间差异
来自植物大战僵尸杂交版Wiki
更多操作
无编辑摘要 |
无编辑摘要 |
||
| 第45行: | 第45行: | ||
input:focus, textarea:focus { border-color: #90c8e0; box-shadow: 0 0 0 3px #60a0b888; } | input:focus, textarea:focus { border-color: #90c8e0; box-shadow: 0 0 0 3px #60a0b888; } | ||
textarea { min-height: 100px; resize: vertical; line-height: 1.5; font-family: 'Courier New', monospace; font-size: 0.9rem; } | textarea { min-height: 100px; resize: vertical; line-height: 1.5; font-family: 'Courier New', monospace; font-size: 0.9rem; } | ||
input[type="color"] { width: 36px; height: 30px; padding: 2px; border-radius: 8px; cursor: pointer; border: 1px solid #5b80a0; background: transparent; } | |||
.event-item { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; background: #1a2a36; padding: 6px 12px; border-radius: 30px; border: 1px solid #4a7088; flex-wrap: wrap; } | .event-item { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; background: #1a2a36; padding: 6px 12px; border-radius: 30px; border: 1px solid #4a7088; flex-wrap: wrap; } | ||
.event-item input { flex: 1; background: #0e1822; border: 1px solid #4a6880; border-radius: 20px; padding: 5px 12px; font-size: 0.9rem; min-width: 120px; } | .event-item input { flex: 1; background: #0e1822; border: 1px solid #4a6880; border-radius: 20px; padding: 5px 12px; font-size: 0.9rem; min-width: 120px; } | ||
| 第82行: | 第83行: | ||
.map-grid-scroll { overflow-x: auto; max-width: 100%; } | .map-grid-scroll { overflow-x: auto; max-width: 100%; } | ||
.map-grid-row { display: flex; gap: 2px; margin-bottom: 2px; align-items: center; } | .map-grid-row { display: flex; gap: 2px; margin-bottom: 2px; align-items: center; } | ||
.map-grid-cell { width: 44px; height: 44px | .map-grid-cell { width: 44px; height: 44px; border: 1px solid #ffffff; border-radius: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 0.55rem; color: #000; text-align: center; overflow: hidden; position: relative; transition: all 0.15s; flex-shrink: 0; } | ||
.map-grid-cell:hover { filter: brightness(1.3); transform: scale(1.08); z-index: 2; } | .map-grid-cell:hover { filter: brightness(1.3); transform: scale(1.08); z-index: 2; } | ||
.map-grid-cell.placed::after { content: '🌱'; font-size: 16px; position: absolute; pointer-events: none; } | .map-grid-cell.placed::after { content: '🌱'; font-size: 16px; position: absolute; pointer-events: none; } | ||
.map-grid-label { width: 34px; color: #80b8d0; font-size: 0.65rem; text-align: center; flex-shrink: 0; } | .map-grid-label { width: 34px; color: #80b8d0; font-size: 0.65rem; text-align: center; flex-shrink: 0; } | ||
| 第93行: | 第93行: | ||
.map-toolbar .dim-label { color: #80b8d0; font-size: 0.75rem; margin: 0 2px; } | .map-toolbar .dim-label { color: #80b8d0; font-size: 0.75rem; margin: 0 2px; } | ||
.map-toolbar .dim-input { width: 50px; text-align: center; } | .map-toolbar .dim-input { width: 50px; text-align: center; } | ||
.color-palette { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; background: #0e1a22aa; padding: 8px 14px; border-radius: 16px; border: 1px solid #3a5a6a; } | |||
.color-palette label { font-size: 0.75rem; margin: 0; display: flex; align-items: center; gap: 4px; color: #90b8d0; } | |||
.color-palette input[type="color"] { width: 30px; height: 24px; padding: 1px; border-radius: 6px; cursor: pointer; border: 1px solid #5b80a0; } | |||
.color-palette .preset-colors { display: flex; gap: 3px; } | |||
.color-palette .preset-dot { width: 18px; height: 18px; border-radius: 50%; cursor: pointer; border: 1px solid #5b80a0; transition: transform 0.1s; } | |||
.color-palette .preset-dot:hover { transform: scale(1.3); } | |||
.cell-popup { display: none; position: fixed; background: #1a2a36; border: 2px solid #80c8e0; border-radius: 16px; padding: 12px; z-index: 100; min-width: 180px; box-shadow: 0 8px 24px rgba(0,0,0,0.6); } | .cell-popup { display: none; position: fixed; background: #1a2a36; border: 2px solid #80c8e0; border-radius: 16px; padding: 12px; z-index: 100; min-width: 180px; box-shadow: 0 8px 24px rgba(0,0,0,0.6); } | ||
.cell-popup input { font-size: 0.8rem; margin-bottom: 6px; } | .cell-popup input { font-size: 0.8rem; margin-bottom: 6px; } | ||
| 第102行: | 第108行: | ||
.preset-btn { font-size: 0.7rem; padding: 3px 8px; border-radius: 12px; border: 1px solid #4a7088; background: #1a2a36; color: #80b8d0; cursor: pointer; } | .preset-btn { font-size: 0.7rem; padding: 3px 8px; border-radius: 12px; border: 1px solid #4a7088; background: #1a2a36; color: #80b8d0; cursor: pointer; } | ||
.preset-btn:hover { background: #2a4a5a; color: #c0e8f0; } | .preset-btn:hover { background: #2a4a5a; color: #c0e8f0; } | ||
.preset-btn.active-preset { background: #3a6a7a; border-color: #c0e8f0; color: #fff; } | |||
</style> | </style> | ||
</head> | </head> | ||
| 第140行: | 第147行: | ||
<!-- 地图预放置编辑器 --> | <!-- 地图预放置编辑器 --> | ||
<div class="map-grid-container" id="mapGridEditor"> | <div class="map-grid-container" id="mapGridEditor"> | ||
<label style="margin-bottom: | <label style="margin-bottom:4px;">🗺️ 地图预放置 <i>(点击格子放置/编辑植物,右键清除)</i></label> | ||
<!-- ★ 调色板 ★ --> | |||
<div class="color-palette"> | |||
<label>🎨 背景色:<input type="color" id="gridBg" value="#1a6b0a" title="表格背景色"></label> | |||
<label>格子色:<input type="color" id="gridCell" value="#11ff00" title="单元格背景色"></label> | |||
<label>边框色:<input type="color" id="gridBorder" value="#ffffff" title="单元格边框色"></label> | |||
<span style="color:#6080a0; font-size:0.7rem; margin:0 4px;">预设:</span> | |||
<div class="preset-colors"> | |||
<span class="preset-dot" data-bg="#1a6b0a" data-cell="#11ff00" data-border="#ffffff" style="background:#11ff00;" title="经典草地"></span> | |||
<span class="preset-dot" data-bg="#2d2d2d" data-cell="#3a3a3a" data-border="#555555" style="background:#3a3a3a;" title="暗色主题"></span> | |||
<span class="preset-dot" data-bg="#1a3a2a" data-cell="#2d5a3d" data-border="#4a8a5a" style="background:#2d5a3d;" title="深绿草地"></span> | |||
<span class="preset-dot" data-bg="#3a2a1a" data-cell="#6b4a2a" data-border="#8a6a4a" style="background:#6b4a2a;" title="沙漠主题"></span> | |||
<span class="preset-dot" data-bg="#1a1a3a" data-cell="#2a2a5a" data-border="#4a4a8a" style="background:#2a2a5a;" title="暗夜主题"></span> | |||
</div> | |||
</div> | |||
<div class="map-toolbar"> | <div class="map-toolbar"> | ||
<span style="color:#80b8d0; font-size:0.75rem;">预设:</span> | <span style="color:#80b8d0; font-size:0.75rem;">预设:</span> | ||
<div class="preset-row"> | <div class="preset-row"> | ||
<button class="preset-btn" data-rows="5" data-cols="9">5×9</button> | <button class="preset-btn active-preset" data-rows="5" data-cols="9">5×9</button> | ||
<button class="preset-btn" data-rows="6" data-cols="9">6×9</button> | <button class="preset-btn" data-rows="6" data-cols="9">6×9</button> | ||
<button class="preset-btn" data-rows="7" data-cols="11">7×11</button> | <button class="preset-btn" data-rows="7" data-cols="11">7×11</button> | ||
| 第239行: | 第262行: | ||
</div> | </div> | ||
<div class="wiki-output" id="wikiOutput"></div> | <div class="wiki-output" id="wikiOutput"></div> | ||
<div class="note">⚡ | <div class="note">⚡ 实时生成。点击格子放置植物,右键清除。可自定义颜色和行列数。</div> | ||
</div> | </div> | ||
</div> | </div> | ||
| 第304行: | 第327行: | ||
]; | ]; | ||
// 地图数据 | // 地图数据 | ||
let mapRows = 5, mapCols = 9; | let mapRows = 5, mapCols = 9; | ||
let mapData = []; | let mapData = []; | ||
let gridBg = '#1a6b0a', gridCellColor = '#11ff00', gridBorderColor = '#ffffff'; | |||
function initMapData() { mapData = Array.from({length:mapRows}, ()=>Array.from({length:mapCols}, ()=>null)); } | function initMapData() { mapData = Array.from({length:mapRows}, ()=>Array.from({length:mapCols}, ()=>null)); } | ||
| 第333行: | 第357行: | ||
const mapRowsInput = document.getElementById('mapRows'); | const mapRowsInput = document.getElementById('mapRows'); | ||
const mapColsInput = document.getElementById('mapCols'); | const mapColsInput = document.getElementById('mapCols'); | ||
const gridBgInput = document.getElementById('gridBg'); | |||
const gridCellInput = document.getElementById('gridCell'); | |||
const gridBorderInput = document.getElementById('gridBorder'); | |||
let currentEditRow = -1, currentEditCol = -1; | let currentEditRow = -1, currentEditCol = -1; | ||
| 第373行: | 第400行: | ||
// ========== 地图预放置 ========== | // ========== 地图预放置 ========== | ||
function updateGridColors() { | |||
gridBg = gridBgInput.value || '#1a6b0a'; | |||
gridCellColor = gridCellInput.value || '#11ff00'; | |||
gridBorderColor = gridBorderInput.value || '#ffffff'; | |||
// 更新地图容器背景 | |||
document.querySelector('.map-grid-container').style.background = gridBg + 'cc'; | |||
renderMapGrid(); | |||
refreshPreview(); | |||
} | |||
function applyColorPreset(bg, cell, border) { | |||
gridBgInput.value = bg; | |||
gridCellInput.value = cell; | |||
gridBorderInput.value = border; | |||
updateGridColors(); | |||
} | |||
function resizeMap(newRows, newCols) { | function resizeMap(newRows, newCols) { | ||
const oldData = mapData; | const oldData = mapData; | ||
| 第394行: | 第436行: | ||
const cell = document.createElement('div'); | const cell = document.createElement('div'); | ||
cell.className = 'map-grid-cell'; | cell.className = 'map-grid-cell'; | ||
cell.style.background = gridCellColor; | |||
cell.style.borderColor = gridBorderColor; | |||
if(mapData[r][c]) { cell.classList.add('placed'); cell.title = mapData[r][c].file; } | if(mapData[r][c]) { cell.classList.add('placed'); cell.title = mapData[r][c].file; } | ||
cell.addEventListener('click',()=>openCellPopup(r,c)); | cell.addEventListener('click',()=>openCellPopup(r,c)); | ||
| 第434行: | 第478行: | ||
for(let r=0;r<mapRows;r++) for(let c=0;c<mapCols;c++) if(mapData[r][c]) hasAny=true; | for(let r=0;r<mapRows;r++) for(let c=0;c<mapCols;c++) if(mapData[r][c]) hasAny=true; | ||
if(!hasAny) return ''; | if(!hasAny) return ''; | ||
let table = `\n== 地图预放置 ==\n{| style="width:100%;max-width:900px;table-layout:fixed;text-align:center;background: | let table = `\n== 地图预放置 ==\n{| style="width:100%;max-width:900px;table-layout:fixed;text-align:center;background:${gridBg};border-collapse:collapse;"\n|-\n! !!`; | ||
for(let c=1;c<=mapCols;c++) table += ` 列${c} !!`; | for(let c=1;c<=mapCols;c++) table += ` 列${c} !!`; | ||
table = table.slice(0,-2) + '\n'; | table = table.slice(0,-2) + '\n'; | ||
| 第442行: | 第486行: | ||
const d = mapData[r][c]; | const d = mapData[r][c]; | ||
const content = d ? `[[文件:${d.file}|50px|link=${d.link}]]` : ''; | const content = d ? `[[文件:${d.file}|50px|link=${d.link}]]` : ''; | ||
table += `| style="height:80px;border:2px solid | table += `| style="height:80px;border:2px solid ${gridBorderColor};background:${gridCellColor};" | ${content}\n`; | ||
} | } | ||
} | } | ||
| 第451行: | 第495行: | ||
const tableMatch = src.match(/== 地图预放置 ==\s*\n\{\|[\s\S]*?\n\|\}/); | const tableMatch = src.match(/== 地图预放置 ==\s*\n\{\|[\s\S]*?\n\|\}/); | ||
if(!tableMatch) { initMapData(); renderMapGrid(); return; } | if(!tableMatch) { initMapData(); renderMapGrid(); return; } | ||
// 解析表格背景色 | |||
const bgMatch = tableMatch[0].match(/background:([#\w]+)/); | |||
if(bgMatch) { gridBg = bgMatch[1]; gridBgInput.value = gridBg; } | |||
// 解析表头列数 | // 解析表头列数 | ||
const headerMatch = tableMatch[0].match(/! !!([\s\S]*?)\n\|-/); | const headerMatch = tableMatch[0].match(/! !!([\s\S]*?)\n\|-/); | ||
| 第470行: | 第517行: | ||
const rowIdx = parseInt(rm[1])-1; | const rowIdx = parseInt(rm[1])-1; | ||
if(rowIdx<0||rowIdx>=mapRows) return; | if(rowIdx<0||rowIdx>=mapRows) return; | ||
const cells = [...row.matchAll(/\| style="[^"]*" \| (.*?)(?=\n|$)/g)]; | const cells = [...row.matchAll(/\| style="([^"]*)" \| (.*?)(?=\n|$)/g)]; | ||
cells.forEach((m,ci) => { | cells.forEach((m,ci) => { | ||
if(ci>=mapCols) return; | if(ci>=mapCols) return; | ||
const content = m[ | // 解析单元格颜色 | ||
const styleStr = m[1]; | |||
const cbg = styleStr.match(/background:([#\w]+)/); | |||
const cbd = styleStr.match(/border:[^;]*solid\s+([#\w]+)/); | |||
if(cbg) gridCellColor = cbg[1]; | |||
if(cbd) gridBorderColor = cbd[1]; | |||
const content = m[2].trim(); | |||
const fm = content.match(/\[\[文件:([^|]+)\|[^|]+\|link=([^\]]+)\]\]/); | const fm = content.match(/\[\[文件:([^|]+)\|[^|]+\|link=([^\]]+)\]\]/); | ||
if(fm) mapData[rowIdx][ci] = {file:fm[1], link:fm[2]}; | if(fm) mapData[rowIdx][ci] = {file:fm[1], link:fm[2]}; | ||
}); | }); | ||
}); | }); | ||
gridCellInput.value = gridCellColor; | |||
gridBorderInput.value = gridBorderColor; | |||
} | } | ||
renderMapGrid(); | renderMapGrid(); | ||
| 第700行: | 第755行: | ||
const src = importTextarea.value; | const src = importTextarea.value; | ||
if(src) parseMapTable(src); | if(src) parseMapTable(src); | ||
else { renderMapGrid(); } | else { updateGridColors(); renderMapGrid(); } | ||
refreshPreview(); | refreshPreview(); | ||
} | } | ||
| 第742行: | 第797行: | ||
document.querySelectorAll('.preset-btn').forEach(btn=>{ | document.querySelectorAll('.preset-btn').forEach(btn=>{ | ||
btn.addEventListener('click',()=>{ | btn.addEventListener('click',()=>{ | ||
document.querySelectorAll('.preset-btn').forEach(b=>b.classList.remove('active-preset')); | |||
btn.classList.add('active-preset'); | |||
const nr = parseInt(btn.dataset.rows); | const nr = parseInt(btn.dataset.rows); | ||
const nc = parseInt(btn.dataset.cols); | const nc = parseInt(btn.dataset.cols); | ||
if(nr&&nc) resizeMap(nr, nc); | if(nr&&nc) resizeMap(nr, nc); | ||
}); | |||
}); | |||
// 颜色输入 | |||
gridBgInput.addEventListener('input', updateGridColors); | |||
gridCellInput.addEventListener('input', updateGridColors); | |||
gridBorderInput.addEventListener('input', updateGridColors); | |||
// 预设颜色点 | |||
document.querySelectorAll('.preset-dot').forEach(dot=>{ | |||
dot.addEventListener('click',()=>{ | |||
applyColorPreset(dot.dataset.bg, dot.dataset.cell, dot.dataset.border); | |||
}); | }); | ||
}); | }); | ||