feat: Phase 4 port Oracle, Meaning, UNE, and Dice
Ports the four core Mythic GME tools from reference/index.html into the modular structure. Fate Check and Random Event Check preserve the exact probability matrix and roll logic, now reading chaos factor live from the active campaign instead of local state. Meaning and UNE tables are served from data/tables/ via a new tables route. UNE motivation uses the published verb+noun tables instead of the reference's flattened phrase list. Dice (pool builder, custom roll, percentile, ability score) is ported verbatim as pure frontend logic.
This commit is contained in:
+60
-1
@@ -1 +1,60 @@
|
||||
// Mythic Oracle — UNE
|
||||
// Mythic Oracle — UNE (Universal NPC Emulator)
|
||||
|
||||
import { getTable } from './api.js';
|
||||
|
||||
const tableCache = {};
|
||||
|
||||
async function loadTable(name) {
|
||||
if (!tableCache[name]) {
|
||||
tableCache[name] = (await getTable(name)).entries;
|
||||
}
|
||||
return tableCache[name];
|
||||
}
|
||||
|
||||
function pickRandom(entries) {
|
||||
return entries[Math.floor(Math.random() * entries.length)];
|
||||
}
|
||||
|
||||
function capitalize(word) {
|
||||
return word.charAt(0).toUpperCase() + word.slice(1);
|
||||
}
|
||||
|
||||
async function rollUNE() {
|
||||
const [verbs, nouns, demeanors, characters] = await Promise.all([
|
||||
loadTable('une-motivation-verb'),
|
||||
loadTable('une-motivation-noun'),
|
||||
loadTable('une-demeanor'),
|
||||
loadTable('une-character'),
|
||||
]);
|
||||
|
||||
const motivation = `${capitalize(pickRandom(verbs))} ${pickRandom(nouns)}`;
|
||||
const demeanor = pickRandom(demeanors);
|
||||
const character = pickRandom(characters);
|
||||
|
||||
document.getElementById('uneMotivation').textContent = motivation;
|
||||
document.getElementById('uneDemeanor').textContent = demeanor;
|
||||
document.getElementById('uneCharacter').textContent = character;
|
||||
|
||||
const result = document.getElementById('uneResult');
|
||||
result.style.display = 'block';
|
||||
result.classList.remove('animate');
|
||||
void result.offsetWidth;
|
||||
result.classList.add('animate');
|
||||
}
|
||||
|
||||
async function rollRelationship() {
|
||||
const relationships = await loadTable('une-relationship');
|
||||
const rel = pickRandom(relationships);
|
||||
const box = document.getElementById('relationshipResult');
|
||||
box.innerHTML = `<span class="relationship-text">${rel}</span>`;
|
||||
box.classList.remove('animate');
|
||||
void box.offsetWidth;
|
||||
box.classList.add('animate');
|
||||
}
|
||||
|
||||
function init() {
|
||||
document.getElementById('uneRollBtn').addEventListener('click', rollUNE);
|
||||
document.getElementById('relationshipRollBtn').addEventListener('click', rollRelationship);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
|
||||
Reference in New Issue
Block a user