Working on fixing enemy identification

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-14 21:06:31 +01:00
parent 12e2e7e3a8
commit 1ec891d9a0
18 changed files with 293 additions and 292 deletions

View File

@@ -0,0 +1,130 @@
import 'dart:typed_data';
import 'classes/sprite.dart';
class WLParser {
/// Extracts the 64x64 wall textures from VSWAP.WL1
static List<Sprite> parseWalls(ByteData vswap) {
final header = _VswapHeader(vswap);
return header.offsets
.take(header.spriteStart)
.where((offset) => offset != 0) // Skip empty chunks
.map((offset) => _parseWallChunk(vswap, offset))
.toList();
}
/// Extracts the compiled scaled sprites from VSWAP.WL1
static List<Sprite> parseSprites(ByteData vswap) {
final header = _VswapHeader(vswap);
final sprites = <Sprite>[];
// Sprites are located between the walls and the sounds
for (int i = header.spriteStart; i < header.soundStart; i++) {
int offset = header.offsets[i];
if (offset != 0) {
sprites.add(_parseSingleSprite(vswap, offset));
}
}
return sprites;
}
/// Extracts digitized sound effects (PCM Audio) from VSWAP.WL1
static List<Uint8List> parseSounds(ByteData vswap) {
final header = _VswapHeader(vswap);
final lengthStart = 6 + (header.chunks * 4);
final sounds = <Uint8List>[];
// Sounds start after the sprites and go to the end of the chunks
for (int i = header.soundStart; i < header.chunks; i++) {
int offset = header.offsets[i];
int length = vswap.getUint16(lengthStart + (i * 2), Endian.little);
if (offset == 0 || length == 0) {
sounds.add(Uint8List(0)); // Empty placeholder
} else {
// Extract the raw 8-bit PCM audio bytes
sounds.add(vswap.buffer.asUint8List(offset, length));
}
}
return sounds;
}
// --- Private Helpers ---
static Sprite _parseWallChunk(ByteData vswap, int offset) {
// Generate the 64x64 pixel grid in column-major order functionally
return List.generate(
64,
(x) => List.generate(64, (y) => vswap.getUint8(offset + (x * 64) + y)),
);
}
static Sprite _parseSingleSprite(ByteData vswap, int offset) {
// Initialize the 64x64 grid with 255 (The Magenta Transparency Color!)
Sprite sprite = List.generate(64, (_) => List.filled(64, 255));
int leftPix = vswap.getUint16(offset, Endian.little);
int rightPix = vswap.getUint16(offset + 2, Endian.little);
// Parse vertical columns within the sprite bounds
for (int x = leftPix; x <= rightPix; x++) {
int colOffset = vswap.getUint16(
offset + 4 + ((x - leftPix) * 2),
Endian.little,
);
if (colOffset != 0) {
_parseSpriteColumn(vswap, sprite, x, offset, offset + colOffset);
}
}
return sprite;
}
static void _parseSpriteColumn(
ByteData vswap,
Sprite sprite,
int x,
int baseOffset,
int cmdOffset,
) {
// Execute the column drawing commands
while (true) {
int endY = vswap.getUint16(cmdOffset, Endian.little);
if (endY == 0) break; // 0 marks the end of the column
endY ~/= 2; // Wolf3D stores Y coordinates multiplied by 2
int pixelOfs = vswap.getUint16(cmdOffset + 2, Endian.little);
int startY = vswap.getUint16(cmdOffset + 4, Endian.little);
startY ~/= 2;
for (int y = startY; y < endY; y++) {
// The Carmack 286 Hack: pixelOfs + y gives the exact byte address
sprite[x][y] = vswap.getUint8(baseOffset + pixelOfs + y);
}
cmdOffset += 6; // Move to the next 6-byte instruction
}
}
}
/// Helper class to parse and store redundant VSWAP header data
class _VswapHeader {
final int chunks;
final int spriteStart;
final int soundStart;
final List<int> offsets;
_VswapHeader(ByteData vswap)
: chunks = vswap.getUint16(0, Endian.little),
spriteStart = vswap.getUint16(2, Endian.little),
soundStart = vswap.getUint16(4, Endian.little),
offsets = List.generate(
vswap.getUint16(0, Endian.little), // total chunks
(i) => vswap.getUint32(6 + (i * 4), Endian.little),
);
}