// Escalera — climb levels, 3 lives, difficulty grows
const Escalera = ({ profile, onFinish, onQuit }) => {
const t = window.MP_I18N.t;
const diff = window.MP_DATA.difficultyForGrade(profile.grade);
const [phase, setPhase] = React.useState('count');
const [lives, setLives] = React.useState(3);
const [level, setLevel] = React.useState(1);
const [score, setScore] = React.useState(0);
const [correct, setCorrect] = React.useState(0);
const [total, setTotal] = React.useState(0);
const [problem, setProblem] = React.useState(null);
const [choices, setChoices] = React.useState([]);
const [picked, setPicked] = React.useState(null);
const [status, setStatus] = React.useState(null);
const next = React.useCallback((lvl) => {
const useLvl = lvl ?? level;
const max = Math.min(diff.max, 4 + useLvl);
const p = window.MP_DATA.genProblem({ tables: diff.tables, max });
setProblem(p);
setChoices(window.MP_DATA.genOptions(p.answer, 4));
setPicked(null);
setStatus(null);
}, [level]);
React.useEffect(() => { if (phase === 'play') next(level); }, [phase]);
const finish = (livesLeft) => {
onFinish({
mode: 'escalera',
score,
correct,
total,
perfect: livesLeft === 3 && total > 5
});
};
const pick = (c) => {
if (picked != null) return;
setPicked(c);
setTotal(x => x + 1);
if (c === problem.answer) {
window.MP_SOUND.correct();
setStatus('right');
setCorrect(x => x + 1);
const earned = 5 + level * 2;
setScore(s => s + earned);
setTimeout(() => {
const nl = level + 1;
setLevel(nl);
next(nl);
}, 450);
} else {
window.MP_SOUND.wrong();
setStatus('wrong');
const nl = lives - 1;
setLives(nl);
setTimeout(() => {
if (nl <= 0) finish(nl);
else next(level);
}, 800);
}
};
if (phase === 'count') {
return (
setPhase('play')} />
);
}
return (
{t('level')} {level}
{problem && }
);
};
window.Escalera = Escalera;