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

@@ -1,3 +0,0 @@
import 'matrix.dart';
typedef Level = Matrix<int>;

View File

@@ -1 +0,0 @@
typedef Matrix<T> = List<List<T>>;

View File

@@ -1,3 +1,7 @@
import 'matrix.dart';
typedef Matrix<T> = List<List<T>>;
typedef Sprite = Matrix<int>;
typedef Wall = Sprite;
typedef Level = Matrix<int>;

View File

@@ -1,142 +0,0 @@
import 'dart:typed_data';
import 'classes/sprite.dart';
class VswapParser {
/// Extracts the 64x64 wall textures from VSWAP.WL1
static List<Sprite> parseWalls(ByteData vswap) {
// 1. Read Header
int chunks = vswap.getUint16(0, Endian.little);
int spriteStart = vswap.getUint16(2, Endian.little);
// int soundStart = vswap.getUint16(4, Endian.little); // We don't need this yet
// 2. Read Offsets (Where does each chunk start in the file?)
List<int> offsets = [];
for (int i = 0; i < spriteStart; i++) {
offsets.add(vswap.getUint32(6 + (i * 4), Endian.little));
}
// 3. Extract the Wall Textures
List<Sprite> textures = [];
// Walls are chunks 0 through (spriteStart - 1)
for (int i = 0; i < spriteStart; i++) {
int offset = offsets[i];
if (offset == 0) continue; // Empty chunk
// Walls are always exactly 64x64 pixels (4096 bytes)
// Note: Wolf3D stores pixels in COLUMN-MAJOR order (Top to bottom, then left to right)
Sprite texture = List.generate(64, (_) => List.filled(64, 0));
for (int x = 0; x < 64; x++) {
for (int y = 0; y < 64; y++) {
int byteIndex = offset + (x * 64) + y;
texture[x][y] = vswap.getUint8(byteIndex);
}
}
textures.add(texture);
}
return textures;
}
/// Extracts the compiled scaled sprites from VSWAP.WL1
static List<Sprite> parseSprites(ByteData vswap) {
int chunks = vswap.getUint16(0, Endian.little);
int spriteStart = vswap.getUint16(2, Endian.little);
int soundStart = vswap.getUint16(4, Endian.little);
List<int> offsets = [];
for (int i = 0; i < chunks; i++) {
offsets.add(vswap.getUint32(6 + (i * 4), Endian.little));
}
List<Sprite> sprites = [];
// Sprites are located between the walls and the sounds
for (int i = spriteStart; i < soundStart; i++) {
int offset = offsets[i];
if (offset == 0) continue; // Some chunks are empty placeholders
// 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);
// Read the offsets for each vertical column of the sprite
List<int> colOffsets = [];
for (int x = leftPix; x <= rightPix; x++) {
colOffsets.add(
vswap.getUint16(offset + 4 + ((x - leftPix) * 2), Endian.little),
);
}
for (int x = leftPix; x <= rightPix; x++) {
int colOffset = colOffsets[x - leftPix];
if (colOffset == 0) continue;
int cmdOffset = offset + colOffset;
// 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(offset + pixelOfs + y);
}
cmdOffset += 6; // Move to the next 6-byte instruction
}
}
sprites.add(sprite);
}
return sprites;
}
/// Extracts digitized sound effects (PCM Audio) from VSWAP.WL1
static List<Uint8List> parseSounds(ByteData vswap) {
int chunks = vswap.getUint16(0, Endian.little);
int soundStart = vswap.getUint16(4, Endian.little);
List<int> offsets = [];
List<int> lengths = [];
// Offsets are 32-bit integers starting at byte 6
for (int i = 0; i < chunks; i++) {
offsets.add(vswap.getUint32(6 + (i * 4), Endian.little));
}
// Lengths are 16-bit integers immediately following the offset array
int lengthStart = 6 + (chunks * 4);
for (int i = 0; i < chunks; i++) {
lengths.add(vswap.getUint16(lengthStart + (i * 2), Endian.little));
}
List<Uint8List> sounds = [];
// Sounds start after the sprites and go to the end of the chunks
for (int i = soundStart; i < chunks; i++) {
int offset = offsets[i];
int length = lengths[i];
if (offset == 0 || length == 0) {
sounds.add(Uint8List(0)); // Empty placeholder
continue;
}
// Extract the raw 8-bit PCM audio bytes
final soundData = vswap.buffer.asUint8List(offset, length);
sounds.add(soundData);
}
return sounds;
}
}

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),
);
}

View File

@@ -3,6 +3,5 @@
/// More dartdocs go here.
library;
export 'src/classes/level.dart' show Level;
export 'src/classes/sprite.dart' show Sprite;
export 'src/vswap_parser.dart' show VswapParser;
export 'src/classes/sprite.dart' hide Matrix;
export 'src/wl_parser.dart' show WLParser;