Ajoute l'assistant IA "Ruby" (Claude + Scenario) et corrige plusieurs bugs de la scène
Build and deploy / test-python (push) Successful in 12m24s
Build and deploy / test-js (push) Successful in 1m9s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped

Intègre un chat IA capable de manipuler la scène via les mêmes fonctions
que l'éditeur manuel (objets, variables, déclencheurs, images générées),
avec conversations multiples par écran façon Claude. Corrige au passage
le rafraîchissement pjax hors-ordre, l'onglet IA/déclencheurs vide après
sélection d'un objet, la comparaison de booléens dans les conditions, et
le blocage du glisser-déposer hors du cadre caméra après un redimensionnement
de fond par l'IA.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-09 19:40:31 +02:00
co-authored by Claude Sonnet 5
parent ab6635eee0
commit b07b231a61
62 changed files with 2928 additions and 62 deletions
@@ -41,12 +41,29 @@ test('compareValues — repli sur comparaison de chaînes si non numérique', ()
assert.equal(compareValues('abc', 'different', 'xyz'), true);
});
test('compareValues — "egal"/"different" sur du texte, insensible à la casse (bug corrigé)', () => {
assert.equal(compareValues('Vrai', 'egal', 'vrai'), true);
assert.equal(compareValues('VRAI', 'egal', 'vrai'), true);
assert.equal(compareValues('Vrai', 'different', 'vrai'), false);
assert.equal(compareValues('Vrai', 'egal', 'faux'), false);
});
test('compareValues — champ booléen, vocabulaire oui/non insensible à la casse', () => {
assert.equal(compareValues(true, 'egal', 'Oui', 'booleen'), true);
assert.equal(compareValues(false, 'egal', 'non', 'booleen'), true);
assert.equal(compareValues(true, 'different', 'non', 'booleen'), true);
});
test('compareValues — champ booléen, la valeur RÉELLE stockée en texte "faux" est bien fausse (bug corrigé)', () => {
// Une variable booléenne est stockée en texte ("vrai"/"faux") — la
// chaîne "faux" est non vide, donc VRAIE au sens JS naïf : sans
// normalisation des DEUX côtés, "faux" == "Vrai" ressortait vrai à tort.
assert.equal(compareValues('faux', 'egal', 'Vrai', 'booleen'), false);
assert.equal(compareValues('faux', 'different', 'Vrai', 'booleen'), true);
assert.equal(compareValues('vrai', 'egal', 'Vrai', 'booleen'), true);
assert.equal(compareValues('non', 'egal', 'oui', 'booleen'), false);
});
test('resolveVariablePath — chemin vide renvoie la valeur brute', () => {
assert.equal(resolveVariablePath('42', ''), '42');
});
+24 -9
View File
@@ -25,14 +25,22 @@ function readFieldValue(definitionId, rowId, fieldName) {
function compareValues(actual, operator, expected, fieldType) {
if (fieldType === 'booleen') {
const a = actual ? 1 : 0;
// Bug corrigé : une variable booléenne est stockée en TEXTE
// ("vrai"/"faux", voir gameData.variables) — `actual ? 1 : 0` prenait
// n'importe quelle chaîne non vide pour vraie, y compris la chaîne
// "faux" elle-même ! Les deux côtés doivent passer par la MÊME
// normalisation texte->booléen, pas seulement le côté "expected".
// "oui"/"non" (voir data_list.html) est le vocabulaire affiché
// partout ailleurs pour un champ booléen — une valeur de comparaison
// fixe tapée "Oui" doit donc être reconnue vraie ici aussi, pas
// seulement "1"/"true" (et insensible à la casse, aligné avec
// _compare() côté Python, voir filter_repeater_rows.py).
const expectedStr = String(expected).trim().toLowerCase();
const e = (expected === true || ['1', 'true', 'vrai', 'oui'].includes(expectedStr)) ? 1 : 0;
// partout ailleurs pour un champ booléen — une valeur tapée "Oui"
// doit donc être reconnue vraie ici aussi, pas seulement "1"/"true"
// (et insensible à la casse, aligné avec _compare() côté Python).
const normalizeBool = function (v) {
if (v === true) return 1;
if (v === false || v === null || v === undefined) return 0;
return ['1', 'true', 'vrai', 'oui'].includes(String(v).trim().toLowerCase()) ? 1 : 0;
};
const a = normalizeBool(actual);
const e = normalizeBool(expected);
return operator === 'different' ? a !== e : a === e;
}
const an = parseFloat(actual), en = parseFloat(expected);
@@ -49,9 +57,16 @@ function compareValues(actual, operator, expected, fieldType) {
}
const as = (actual === undefined || actual === null) ? '' : String(actual);
const es = (expected === undefined || expected === null) ? '' : String(expected);
// "egal"/"different" insensibles à la casse (bug corrigé : une valeur de
// comparaison texte tapée avec une casse différente de la valeur réelle
// — ex. "Vrai" vs "vrai" — était jugée différente à tort, alors que le
// créateur/l'IA n'a aucun moyen de connaître la casse EXACTE attendue).
// superieur/inferieur restent une comparaison lexicographique brute
// (l'ordre alphabétique dépend de la casse, hors du champ de ce bug).
const asLower = as.toLowerCase(), esLower = es.toLowerCase();
switch (operator) {
case 'egal': return as === es;
case 'different': return as !== es;
case 'egal': return asLower === esLower;
case 'different': return asLower !== esLower;
case 'superieur': return as > es;
case 'inferieur': return as < es;
case 'superieur_egal': return as >= es;