/* ===== Character Prompts Module ===== */ window.NAICharacter = { MAX_CHARS: 6, characters: [], // [{prompt, uc, row, col}] addCharacter() { if (this.characters.length >= this.MAX_CHARS) return; this.characters.push({ prompt: '', uc: '', row: 2, // 0-indexed, default 3rd row col: 2, // 0-indexed, default 3rd col }); this.render(); }, removeCharacter(idx) { this.characters.splice(idx, 1); this.render(); }, isAutoCoords() { const cb = $('#char-auto-coords'); return cb ? cb.checked : true; }, render() { const container = $('#char-list'); container.innerHTML = ''; const autoCoords = this.isAutoCoords(); this.characters.forEach((char, idx) => { const item = document.createElement('div'); item.className = 'char-item'; // Header with remove button const header = document.createElement('div'); header.className = 'char-item-header'; header.innerHTML = ` 角色 ${idx + 1} `; header.querySelector('.char-remove-btn').addEventListener('click', () => this.removeCharacter(idx)); item.appendChild(header); // Prompt textarea const promptGroup = document.createElement('div'); promptGroup.className = 'form-group'; promptGroup.innerHTML = ` `; const promptTA = promptGroup.querySelector('textarea'); promptTA.addEventListener('input', () => { char.prompt = promptTA.value; NAIUtils.autoResize(promptTA); }); item.appendChild(promptGroup); setTimeout(() => NAIUtils.autoResize(promptTA), 0); // UC textarea const ucGroup = document.createElement('div'); ucGroup.className = 'form-group'; ucGroup.innerHTML = ` `; const ucTA = ucGroup.querySelector('textarea'); ucTA.addEventListener('input', () => { char.uc = ucTA.value; NAIUtils.autoResize(ucTA); }); item.appendChild(ucGroup); setTimeout(() => NAIUtils.autoResize(ucTA), 0); // 5x5 Grid (only interactive when auto coords is off) const gridGroup = document.createElement('div'); gridGroup.className = 'form-group char-grid-group'; if (autoCoords) gridGroup.classList.add('disabled'); const gridLabel = document.createElement('label'); gridLabel.textContent = `角色${idx + 1} 位置`; gridGroup.appendChild(gridLabel); const grid = document.createElement('div'); grid.className = 'char-grid'; for (let r = 0; r < 5; r++) { for (let c = 0; c < 5; c++) { const cell = document.createElement('div'); cell.className = 'char-grid-cell'; if (r === char.row && c === char.col) { cell.classList.add('selected'); } if (!autoCoords) { cell.addEventListener('click', () => { char.row = r; char.col = c; // Update grid selection grid.querySelectorAll('.char-grid-cell').forEach(cl => cl.classList.remove('selected')); cell.classList.add('selected'); }); } grid.appendChild(cell); } } gridGroup.appendChild(grid); item.appendChild(gridGroup); container.appendChild(item); }); // Update add button state const addBtn = $('#btn-char-add'); if (addBtn) { addBtn.disabled = this.characters.length >= this.MAX_CHARS; } }, collectParams() { if (this.characters.length === 0) return { characters: [], useCoords: !this.isAutoCoords() }; const useCoords = !this.isAutoCoords(); const characters = this.characters.map(char => { // x = col * 0.2 + 0.1, y = row * 0.2 + 0.1 (centered in cell) const x = parseFloat((char.col * 0.2 + 0.1).toFixed(2)); const y = parseFloat((char.row * 0.2 + 0.1).toFixed(2)); return { prompt: char.prompt, uc: char.uc, center: { x, y }, }; }); return { characters, useCoords }; }, init() { // Toggle $('#char-toggle').addEventListener('click', () => { const c = $('#char-content'); const a = $('#char-arrow'); const open = c.classList.toggle('open'); a.textContent = open ? '▼' : '▶'; }); // Auto coords checkbox $('#char-auto-coords').addEventListener('change', () => { this.render(); }); // Add button $('#btn-char-add').addEventListener('click', () => this.addCharacter()); }, };