Problème
Observation utilisateur sur le niveau de test test_alien_bullets : plusieurs
aliens semblent visuellement identiques, alors que dans le jeu original ils
ont des variants distincts (Guard bleu, ‘Ard Guard rouge avec lampes,
Ashnarg vert, etc.). Hypothèse initiale « sprites partagés par gfxType »
incorrecte.
Analyse
Après lecture de defs.i, hires.s et newaliencontrol.s :
-
La struct ASM
AlienTn’a effectivement qu’un champGFXType(pas de
WAD individuel par alien). Le mappinggfxType → WADdu LevelSceneBuilder
est donc fidèle. -
Mais chaque alien a sa propre table
GLFT_AlienAnims_l[type](2420
octets dans le binaire) qui spécifie quelles frames du WAD partagé il
utilise. C’est par ce biais que Guard et ‘Ard Guard, qui partagent le WAD
guard, peuvent être visuellement différents : Guard utilise les frames
0-18, ‘Ard Guard utilise une autre plage (19-36 ou similaire). -
Structure d’une frame d’anim alien (11 octets, voir
defs.iA_FrameLen) : - byte 0 : wadFrame → numéro de frame WAD à afficher (clé)
- byte 1 : flipMirror (signed, négatif = mirror)
- bytes 2-3 : scaleHint (taille/luminosité)
- byte 4 : doActionFlag (trigger tir/hit)
- byte 5 : finishedFlag (=1 à la dernière frame, loop)
- byte 6 : moveSpeed
- byte 7 : soundIndex (sample SFX)
-
bytes 8-10 : réservés
-
Total par alien : 11 options × 20 frames × 11 octets = 2420 octets
(NUM_ALIEN_DEFS × A_AnimLen = 20 × 2420 = 48400 octets).
Bug bonus découvert
En calculant l’offset de GLFT_AlienAnims_l, j’ai trouvé que
OFS_GUN_GIVE dans LnkParser valait 0x7FF8 au lieu de 0x8000 :
OFS_AMMO_GIVE = 0x7AD8
+ NUM_OBJECT_DEFS * AmmoGiveLen (30 * 44 = 1320)
= 0x8000 <-- valeur correcte
L’erreur de 8 octets faisait que getGunGive(defIdx) lisait dans les 8
derniers octets de l’entrée AmmoGive[29] au lieu du début de
GunGive[0]. Effet : les flags Shield/JetPack/Weapons des objets étaient
décalés. Cas peu visible en pratique car les valeurs résiduelles étaient
souvent 0, mais c’était latent.
Modifications
LnkParser.java :
- Fix
OFS_GUN_GIVE = 0x8000(était0x7FF8) - Ajout
OFS_ALIEN_ANIMS = 0x82D0(=0x8000 + 30*24) - Ajout des constantes
A_FRAME_LEN,A_OPT_LEN,A_ANIM_LEN,
A_FRAMES_PER_OPTION,A_OPTIONS_PER_ALIEN - Ajout du record
AlienAnimFrameavec les 10 champs documentés - Ajout des méthodes :
getAlienAnimFrame(alienIdx, optIdx, frameIdx)→AlienAnimFramegetAlienAnimOption(alienIdx, optIdx)→AlienAnimFrame[20]getAlienIdleFrame(alienIdx)→ int (raccourci pour
[opt=0][frame=0].wadFrame)getAlienAnimByte(alienIdx, optIdx, frameIdx, byteOff)→ int
LevelJsonExporter.java :
- Ajout du champ
idleFramedans chaque entrée d’aliens[]de
definitions.json - Ajout d’une nouvelle section
alienAnims[]qui exporte la table
complète (20 aliens × 11 options × 20 frames). Format compact :
[wadFrame, flipMirror, finishedFlag, doActionFlag]par frame.
Taille résultante : ~30-40 ko ajoutés àdefinitions.json.
LevelSceneBuilder.java :
- Extension du record interne
AlienDefavec le champidleFrame - Lecture de
idleFramedansloadAlienDefs()(fallback 0 si absent
pour compatibilité avec d’anciensdefinitions.json) - Utilisation de
adef.idleFrame()dansaddItems()pour passer la bonne
frame àtryLoadSprite(). Avant : toujours0. Maintenant : la frame
vraie de l’alien dans son WAD partagé.
Pipeline pour tester
./gradlew convertLevels # regénère definitions.json avec idleFrame
./gradlew buildScenes # regénère les .j3o avec les bonnes frames
./gradlew run --args="--test-level ALIEN_BULLETS"
Résultat attendu
Dans le niveau test test_alien_bullets, les 16 aliens devraient maintenant
apparaître avec leurs sprites distincts du jeu original :
- gfxType 3 (Guard, ‘Ard Guard, Triclaw, Insect Boss) : 4 variants
visuellement différents au lieu de 4 copies du Guard - gfxType 2 (Droid, Ashnarg, AlienPriest, BigInsect, Tough Triclaw) :
5 variants distincts au lieu de 5 copies du Droid - gfxType 4 (well ard guard, Insectalien) : 2 variants distincts
Reste à faire (V2)
La fix de cette session ne touche que la frame de repos (idleFrame).
L’animation dynamique (marche, attaque, hit, mort) utilise toujours la
convention hardcodée dans AlienAnimTable.java (frames 0-3 = TOWARDS,
4-7 = RIGHT, etc.), ce qui peut donner des animations incorrectes pour
les aliens dont la table d’anim utilise un offset différent.
La V2 consistera à :
- Créer
AlienAnimsLoader.javaqui chargedefinitions.json::alienAnims
au démarrage du jeu - Adapter
AlienAnimTable.pickFrame()pour utiliser la vraie table par
alien (avec fallback sur la convention si absente) - Utiliser
doActionFlagetfinishedFlagpour piloter précisément les
triggers de tir/hit dansAlienAI.java(au lieu deFIRE_FRAME = 4
hardcodé)
Bénéfices V2 : animations 100% fidèles + timing de tir exact + sons par
frame (offset 7 dans la struct).