Allenamento alla Sovranità Cognitiva
LIFENET è il simulatore narrativo di HUMANSAFE OS. Qui non “vinci” contro qualcuno:
osservi come reagisci quando la realtà ti graffia un po’.
Ogni scenario modifica il tuo profilo invisibile, genera XP etici, aggiorna il tuo livello
e ti propone una missione reale.
Scenario 1
Caricamento...
"game-data/scenarios/scenario_01.json",
"game-data/scenarios/scenario_02.json",
"game-data/scenarios/scenario_03.json",
"game-data/scenarios/scenario_04.json"
];
const levelsFile = "game-data/progression/levels.json";
const missionsFile = "game-data/missions/missions_01.json";
let scenarios = [];
let levels = [];
let missions = [];
let currentScenarioIndex = 0;
let xpTotal = 0;
let stats = {
impulsivita: 0,
resilienza_emotiva: 0,
empatia: 0,
consapevolezza: 0,
sovranita_cognitiva: 0,
fuga_realta: 0,
capacita_comunicativa: 0,
fiducia_in_se: 0
};
function formatStatLabel(key) {
return key
.replaceAll("_", " ")
.replace(/\b\w/g, char => char.toUpperCase());
}
function renderStats() {
const wrap = document.getElementById("statsWrap");
wrap.innerHTML = "";
Object.entries(stats).forEach(([key, value]) => {
const item = document.createElement("div");
item.className = "stat";
item.innerHTML = `
${formatStatLabel(key)}
${value > 0 ? "+" + value : value}
`;
wrap.appendChild(item);
});
}
function getCurrentLevel(xp) {
let current = levels[0];
for (const level of levels) {
if (xp >= level.xp_required) {
current = level;
}
}
return current;
}
function getNextLevel(xp) {
return levels.find(level => level.xp_required > xp) || null;
}
function renderProgression() {
const xpEl = document.getElementById("xpValue");
const levelNameEl = document.getElementById("levelName");
const levelMetaEl = document.getElementById("levelMeta");
const progressBar = document.getElementById("levelProgressBar");
const currentLevel = getCurrentLevel(xpTotal);
const nextLevel = getNextLevel(xpTotal);
xpEl.textContent = xpTotal;
levelNameEl.textContent = currentLevel ? currentLevel.name : "Nessun livello";
if (!currentLevel) {
levelMetaEl.textContent = "Sistema livelli non disponibile.";
progressBar.style.width = "0%";
return;
}
if (!nextLevel) {
levelMetaEl.textContent = "Livello massimo attuale raggiunto.";
progressBar.style.width = "100%";
return;
}
const currentFloor = currentLevel.xp_required;
const nextFloor = nextLevel.xp_required;
const span = nextFloor - currentFloor;
const progress = ((xpTotal - currentFloor) / span) * 100;
levelMetaEl.textContent = `${xpTotal}/${nextFloor} XP · Prossimo livello: ${nextLevel.name}`;
progressBar.style.width = `${Math.max(0, Math.min(100, progress))}%`;
}
function getSuggestedMission() {
if (!missions.length) return null;
return missions[currentScenarioIndex % missions.length];
}
function renderMissionSuggestion() {
const mission = getSuggestedMission();
const box = document.getElementById("missionBox");
const text = document.getElementById("missionText");
const meta = document.getElementById("missionMeta");
if (!mission) {
box.style.display = "none";
return;
}
text.textContent = mission.description;
meta.textContent = `${mission.title} · +${mission.reward_xp} XP · Valore etico: ${mission.ethical_value}`;
box.style.display = "block";
}
async function loadScenarios() {
const loadedScenarios = await Promise.all(
scenarioFiles.map(async (file) => {
const response = await fetch(file);
if (!response.ok) {
throw new Error(`Impossibile caricare ${file}`);
}
return response.json();
})
);
const levelsResponse = await fetch(levelsFile);
if (!levelsResponse.ok) {
throw new Error(`Impossibile caricare ${levelsFile}`);
}
const levelsData = await levelsResponse.json();
const missionsResponse = await fetch(missionsFile);
if (!missionsResponse.ok) {
throw new Error(`Impossibile caricare ${missionsFile}`);
}
const missionsData = await missionsResponse.json();
scenarios = loadedScenarios;
levels = levelsData.levels || [];
missions = missionsData.missions || [];
renderScenario();
renderProgression();
}
function renderScenario() {
const scenario = scenarios[currentScenarioIndex];
document.getElementById("scenarioCounter").textContent =
`Scenario ${currentScenarioIndex + 1} di ${scenarios.length}`;
document.getElementById("scenarioTitle").textContent = scenario.title;
document.getElementById("scenarioTheme").textContent = scenario.theme;
document.getElementById("questionText").textContent = scenario.question;
const setupWrap = document.getElementById("setupWrap");
setupWrap.innerHTML = "";
scenario.setup.forEach((line) => {
const div = document.createElement("div");
div.className = "setup-line";
div.textContent = line;
setupWrap.appendChild(div);
});
const choicesWrap = document.getElementById("choicesWrap");
choicesWrap.innerHTML = "";
document.getElementById("oracleBox").style.display = "none";
document.getElementById("missionBox").style.display = "none";
document.getElementById("nextBtn").style.display = "none";
scenario.choices.forEach((choice) => {
const btn = document.createElement("button");
btn.className = "choice";
btn.innerHTML = `${choice.action_name}
${choice.text}`;
btn.onclick = () => applyChoice(choice);
choicesWrap.appendChild(btn);
});
renderStats();
renderProgression();
}
function calculateChoiceXP(choice) {
const values = Object.values(choice.stat_changes || {});
return values.reduce((sum, value) => sum + Math.max(0, value), 0);
}
function applyChoice(choice) {
for (const [key, value] of Object.entries(choice.stat_changes)) {
stats[key] = (stats[key] || 0) + value;
}
xpTotal += calculateChoiceXP(choice);
document.getElementById("oracleText").textContent = choice.oracle_intervention;
document.getElementById("oracleBox").style.display = "block";
document.getElementById("choicesWrap").innerHTML = "";
document.getElementById("nextBtn").style.display = "inline-flex";
renderStats();
renderProgression();
renderMissionSuggestion();
}
function nextScenario() {
currentScenarioIndex += 1;
if (currentScenarioIndex >= scenarios.length) {
const currentLevel = getCurrentLevel(xpTotal);
document.getElementById("scenarioView").innerHTML = `
Sessione completata
Hai attraversato ${scenarios.length} scenari. Il punto non è “vincere”,
ma capire il tuo stile di risposta quando l’attrito chiama.
HUMANSAFE ORACLE
La maturità non consiste nell’assenza di impulso,
ma nella capacità di non lasciargli il volante.
Esito del percorso
XP totale: ${xpTotal}
Livello raggiunto: ${currentLevel ? currentLevel.name : "N/D"}
`;
renderStats();
renderProgression();
return;
}
renderScenario();
}
function restartGame() {
currentScenarioIndex = 0;
xpTotal = 0;
stats = {
impulsivita: 0,
resilienza_emotiva: 0,
empatia: 0,
consapevolezza: 0,
sovranita_cognitiva: 0,
fuga_realta: 0,
capacita_comunicativa: 0,
fiducia_in_se: 0
};
location.reload();
}
loadScenarios().catch((error) => {
document.getElementById("scenarioView").innerHTML = `
Errore di caricamento
${error.message}
Controlla che i file JSON siano presenti nelle cartelle corrette del progetto.
`;
});