Dev #11
@@ -12,6 +12,7 @@ const {
|
||||
forgeQuestById, forgeShowDialogueBox, forgeDialogueBoxAdvance,
|
||||
forgeDialogueBoxAcceptQuest, forgeDialogueBoxDeclineQuest,
|
||||
forgeQuizBoxAnswer, forgeUpdateAllScoreWidgets,
|
||||
forgeAddQuizScore, forgeSyncAllQuestsCompletionToScorm,
|
||||
} = require('../dialogue-box-controller.js');
|
||||
|
||||
function fakeWidget(objectId) {
|
||||
@@ -321,3 +322,75 @@ test('forgeUpdateAllScoreWidgets — met à jour tous les widgets "🏆 Score" a
|
||||
assert.equal(values[1].textContent, 42);
|
||||
} finally { global.document = previousDoc; }
|
||||
});
|
||||
|
||||
// ---------- Pont vers SCORM (gameData.scoring, voir static/js/play/offline/scorm-api.js) ----------
|
||||
// Bug signalé : "les indicateurs qu'on utilise pour les quêtes devraient
|
||||
// aussi servir aux indicateurs SCORM, or ce n'est pas le cas" — un jeu
|
||||
// construit uniquement avec des quêtes/quiz ne touchait jamais
|
||||
// gameData.scoring, laissant Score/Completion perpétuellement "unknown"
|
||||
// dans le LMS même après avoir fini le jeu.
|
||||
|
||||
test('forgeAddQuizScore alimente aussi gameData.scoring (score + statut "en_cours")', () => {
|
||||
global.gameData.scoring = undefined;
|
||||
window.forgeQuizScore = 0;
|
||||
const previousDoc = global.document;
|
||||
global.document = { querySelectorAll: () => [] };
|
||||
try {
|
||||
forgeAddQuizScore(5);
|
||||
assert.equal(gameData.scoring.score, 5);
|
||||
assert.equal(gameData.scoring.status, 'en_cours');
|
||||
|
||||
forgeAddQuizScore(3);
|
||||
assert.equal(gameData.scoring.score, 8); // cumulé, jamais écrasé
|
||||
assert.equal(gameData.scoring.status, 'en_cours'); // déjà "en_cours", pas rétrogradé
|
||||
} finally { global.document = previousDoc; }
|
||||
});
|
||||
|
||||
test('forgeAddQuizScore ne rétrograde jamais un statut déjà plus avancé que "non_commence"', () => {
|
||||
global.gameData.scoring = { score: 0, status: 'termine' };
|
||||
window.forgeQuizScore = 0;
|
||||
const previousDoc = global.document;
|
||||
global.document = { querySelectorAll: () => [] };
|
||||
try {
|
||||
forgeAddQuizScore(2);
|
||||
assert.equal(gameData.scoring.status, 'termine');
|
||||
} finally { global.document = previousDoc; }
|
||||
});
|
||||
|
||||
test('accepter une quête fait passer gameData.scoring.status à "en_cours" (la partie a commencé)', () => {
|
||||
const widget = fakeWidget(42);
|
||||
global.gameData.scoring = undefined;
|
||||
const previousDoc = global.document;
|
||||
global.document = { querySelector: () => widget };
|
||||
try {
|
||||
forgeDialogueBoxAcceptQuest(5, 42);
|
||||
assert.equal(gameData.scoring.status, 'en_cours');
|
||||
} finally { global.document = previousDoc; }
|
||||
});
|
||||
|
||||
test('forgeSyncAllQuestsCompletionToScorm — passe "termine" seulement quand TOUTES les quêtes sont "terminee"', () => {
|
||||
global.gameData.quests = [{ id: 1, status: 'terminee' }, { id: 2, status: 'en_cours' }];
|
||||
global.gameData.scoring = { score: 0, status: 'en_cours' };
|
||||
forgeSyncAllQuestsCompletionToScorm();
|
||||
assert.equal(gameData.scoring.status, 'en_cours'); // pas encore toutes finies
|
||||
|
||||
gameData.quests[1].status = 'terminee';
|
||||
forgeSyncAllQuestsCompletionToScorm();
|
||||
assert.equal(gameData.scoring.status, 'termine');
|
||||
});
|
||||
|
||||
test('la dernière ligne d\'un dialogue "en_cours" propage la complétion à gameData.scoring si c\'est la seule quête', () => {
|
||||
const widget = fakeWidget(42);
|
||||
global.gameData.quests = [
|
||||
{ id: 20, status: 'en_cours', dialogues: { nouvelle: [], en_cours: [{ speaker: 'PNJ', text: 'Bravo !' }], terminee: [] } },
|
||||
];
|
||||
global.gameData.scoring = { score: 0, status: 'en_cours' };
|
||||
const previousDoc = global.document;
|
||||
global.document = { querySelector: sel => (sel.indexOf('data-object-id="42"') !== -1 ? widget : (sel.indexOf('dialogueBoxWidget') !== -1 ? widget : null)) };
|
||||
try {
|
||||
forgeShowDialogueBox(20);
|
||||
forgeDialogueBoxAdvance(42); // dernière (et unique) ligne consommée -> quête "terminee"
|
||||
assert.equal(forgeQuestById(20).status, 'terminee');
|
||||
assert.equal(gameData.scoring.status, 'termine');
|
||||
} finally { global.document = previousDoc; }
|
||||
});
|
||||
|
||||
@@ -102,9 +102,45 @@ function forgeUpdateAllScoreWidgets() {
|
||||
for (var i = 0; i < values.length; i++) values[i].textContent = window.forgeQuizScore;
|
||||
}
|
||||
|
||||
// Alimente aussi gameData.scoring (voir static/js/play/offline/
|
||||
// apply-actions.js, même forme {score, status}) — bug signalé : "les
|
||||
// indicateurs qu'on utilise pour les quêtes devraient aussi servir aux
|
||||
// indicateurs SCORM, or ce n'est pas le cas". C'est CE champ que
|
||||
// static/js/play/offline/scorm-api.js lit toutes les 2s pour pousser
|
||||
// cmi.core.score.raw/cmi.core.lesson_status au LMS — sans jamais y
|
||||
// toucher, un jeu construit uniquement avec des quêtes/quiz (jamais
|
||||
// l'action de flow "Modifier un score") laissait Score/Completion
|
||||
// perpétuellement "unknown" dans SCORM Cloud, même après y avoir joué
|
||||
// jusqu'au bout. Vocabulaire de statut identique à db/scoring/
|
||||
// (non_commence/en_cours/termine/...), voir FORGE_TO_SCORM_STATUS.
|
||||
function forgeSyncQuizScoreToScorm() {
|
||||
gameData.scoring = gameData.scoring || { score: 0, status: 'non_commence' };
|
||||
gameData.scoring.score = window.forgeQuizScore;
|
||||
if (gameData.scoring.status === 'non_commence') gameData.scoring.status = 'en_cours';
|
||||
}
|
||||
|
||||
// Une quête acceptée = la partie a commencé, même sans le moindre point
|
||||
// encore gagné — sans cet appel, Score restait "0" mais Completion
|
||||
// restait "unknown" tant qu'aucune question n'avait encore été résolue.
|
||||
function forgeSyncQuestStartedToScorm() {
|
||||
gameData.scoring = gameData.scoring || { score: 0, status: 'non_commence' };
|
||||
if (gameData.scoring.status === 'non_commence') gameData.scoring.status = 'en_cours';
|
||||
}
|
||||
|
||||
// Le jeu entier est considéré terminé quand TOUTES les quêtes connues
|
||||
// sont "terminee" — règle simple et prévisible plutôt que de deviner
|
||||
// laquelle des quêtes créées "compte" pour la fin du jeu.
|
||||
function forgeSyncAllQuestsCompletionToScorm() {
|
||||
var quests = gameData.quests || [];
|
||||
if (!quests.length || !quests.every(function (q) { return q.status === 'terminee'; })) return;
|
||||
gameData.scoring = gameData.scoring || { score: 0, status: 'non_commence' };
|
||||
gameData.scoring.status = 'termine';
|
||||
}
|
||||
|
||||
function forgeAddQuizScore(amount) {
|
||||
window.forgeQuizScore += (amount || 0);
|
||||
forgeUpdateAllScoreWidgets();
|
||||
forgeSyncQuizScoreToScorm();
|
||||
}
|
||||
|
||||
// ---------- Enchaînement dialogue/question ----------
|
||||
@@ -171,7 +207,10 @@ function forgeAdvanceConversation(dialogueObjectId) {
|
||||
// questions, toutes répondues correctement) -> quête terminée. Voir
|
||||
// demande utilisateur : "quand le joueur a répondu à toutes les
|
||||
// questions la quête passe au statut terminé".
|
||||
if (quest && quest.status === 'en_cours') quest.status = 'terminee';
|
||||
if (quest && quest.status === 'en_cours') {
|
||||
quest.status = 'terminee';
|
||||
forgeSyncAllQuestsCompletionToScorm();
|
||||
}
|
||||
if (widget) widget.classList.remove('is-active');
|
||||
delete forgeDialogueBoxState[dialogueObjectId];
|
||||
return;
|
||||
@@ -287,6 +326,7 @@ function forgeShowQuestOffer(widget, objectId, quest) {
|
||||
function forgeDialogueBoxAcceptQuest(questId, objectId) {
|
||||
var quest = forgeQuestById(questId);
|
||||
if (quest) quest.status = 'en_cours';
|
||||
forgeSyncQuestStartedToScorm();
|
||||
var widget = forgeDialogueBoxWidgetById(objectId);
|
||||
if (widget) widget.classList.remove('is-active');
|
||||
delete forgeDialogueBoxState[objectId];
|
||||
@@ -310,5 +350,6 @@ if (typeof module !== 'undefined' && module.exports) {
|
||||
forgeShowQuestOffer, forgeDialogueBoxAcceptQuest, forgeDialogueBoxDeclineQuest, forgeResetDialogueBoxFooter,
|
||||
forgeShowQuizBox, forgeQuizBoxAnswer, forgeQuizBoxWidgetOnCurrentScreen, forgeQuizBoxWidgetById,
|
||||
forgeUpdateAllScoreWidgets, forgeAddQuizScore, forgeAdvanceConversation, forgeShowCurrentConversationLine,
|
||||
forgeSyncQuizScoreToScorm, forgeSyncQuestStartedToScorm, forgeSyncAllQuestsCompletionToScorm,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user