/* ===== 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());
},
};