2

I have been analysing, an File called FW190AS.PAC from a 16 Bit Game called Secret Weapons Of The Luftwaffe, in a Hex Editor, the Bytes are displayed in Little Endian format. My aim with this game, is to eventually change The Planes shapes in the game for the outside View, i.e. they are basic Bitmap images, to other shaped Planes. There is another File called FW190A.PAC which also contains images for different views of the Plane and other info. My feeling the 'S' at the end of the name of the File, refers to Shape.

Through trial and error and narrowing down byte sections in the FW190AS.PAC File, I have noticed for example, that when I change byte values, at certain positions at offset 1030 shown in the Hex Editor, one of the views at an angle of the FW190 plane i.e. Focke Wolf 190,

A line attached to the plane, on the right side appears, when I look out the rear view mirror view, changing the bytes produces different coloured sections on the line, each time I change the values. Also when I Change Bytes For Offsets 1000 to 10F0, with Bytes from the Corresponding Offsets in BF109GS.PAC, gives a certain angle view of the BF109G, not facing forwards but Northeast for the FW190A. When I change bytes in offset 1720 in FW190AS.PAC the Upwards View looks different.

Also If I do the same with the bytes, from offsets 1100 to 1400 in the BF109GS.PAC File, to offsets 1100 to 1400 in the FW190AS.PAC File I get the BF109G shown in the opening movie in the game instead of the FW190A.

I also believe that the different angle Views, for the outside views of the Planes in the game, are at different offsets in the shape Files. I am convinced too, that the Bytes for the different, outside angle views of the Planes, are at different offsets for the different planes' Shape Files, as the BF109GS.PAC bytes for the offsets 1000 to 10F0, give a different view for the BF109G, to the bytes from 1000 to 10F0 Offsets in FW190AS.PAC, which is a forward-facing view i.e. for the FW190A. This would make sense, as the total number of offsets, is different in each plane's shape file.

I have attached links to Screenshots of the FW190A, and you will notice the different Colours, in sections of the line showing out of the FW190A, in the different Screenshots. Also In the climbing Plane View changes, when changing bytes in offset 1720, changing the first byte to 07, puts a black line on the left wing, near where it is attached to the fuselage, and also a bitmap, of the original view of the FW190A.

the SWOTL Plane Shape Test 19 and SWOTL Plane Shape Test 20 Screenshot Files I link to amongst others correspond to the Files I named FW190AS (19).PAC and FW190AS (20).PAC respectively, those will need to change back to FW190AS.PAC to be used in the game, choose the Scramble from Brandis Mission, in Historical Missions for the FW190A, and look out of the rearview mirror, to see the new view, it sometimes takes a few seconds, to change to that, bytes were changed at offset 1030.

Here is a C Program that extracts the images from Secret Weapons of the Luftwaffe Files, and saves them as a bitmap, some are in colour most output Greyscale images:-

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>


    #define MAX_W   600
    #define MAX_H   300   
    #define HEADER_SIZE     54
    #define PALETTE_ENTRIES 256
    #define PALETTE_SIZE    (PALETTE_ENTRIES * 4)   // 4 bytes per entry
#define DATA_OFFSET     (HEADER_SIZE + PALETTE_SIZE)    typedef unsigned char Byte; typedef enum Mode { V1, V2 } Mode; // V1 for
older files, V2 for newer    typedef struct Info {
    Byte image[MAX_H][MAX_W];
    int  min_width, max_width;
    int  width, height;
    int  adder;
    int  output_file_index;
    int  n_palette;
    const char *filename; } Info;    Info info = {
    .min_width = INT_MAX,
    .n_palette = -1,
    .filename  = NULL }; Mode ProgramMode = V1;    void reset() {
    memset(info.image, 0, MAX_H * MAX_W);
    info.min_width = INT_MAX;
    info.max_width = 0;
    info.width = 0;
    info.height = 0;
    info.adder = 0; }    void default_palette(Byte *pal) {
    const int shift = (ProgramMode == V1 ? 3 : 2);
    for (int color = 0; color < PALETTE_ENTRIES; color++) {
        *pal++ = color << shift;
        *pal++ = color << shift;
        *pal++ = color << shift;
        *pal++ = 0;
    } }    void fill_palette(Byte *pal, const char *infilename, int n_palette) {
    if (n_palette == -1) {
        default_palette(pal);
        return;
    }
    FILE *f = fopen(infilename, "rb");
    int byte, cnt = 0;
    const int shift = (ProgramMode == V1 ?  3 :  2);
    const int size  = (ProgramMode == V1 ? 32 : 64);
    while ((byte = fgetc(f)) != EOF) {
        if (byte == 0xFF && ++cnt == n_palette) {
            for (int i = 0; i < size; ++i) {
                int r = fgetc(f), g = fgetc(f), b = fgetc(f);
                pal[i * 4    ] = b << shift;
                pal[i * 4 + 1] = g << shift;
                pal[i * 4 + 2] = r << shift;
            }
            break;
        }
    }
    fclose(f); }    void save_bmp() { 
    Byte header[HEADER_SIZE] = {
        0x42, 0x4D,                  //  0: BM signature
          -1,   -1,   -1,   -1,      //  2: filesize
           0,    0,    0,    0,      //  6: reserved
          -2,   -2,   -2,   -2,      // 10: offset to pixel array
        0x28,    0,    0,    0,      // 14: DIB header size
          -3,   -3,   -3,   -3,      // 18: width
          -4,   -4,   -4,   -4,      // 22: height
        0x01,    0,                  // 26: planes
        0x08,    0                   // 28: bits per pixel
    };
  
    int pad = (4 - info.max_width % 4) % 4;
    int file_size = DATA_OFFSET + (info.max_width + pad) * info.height;
    Byte *output = malloc(file_size);
    memcpy(output, header, HEADER_SIZE);
    *(int*)(output +  2) =  file_size;
    *(int*)(output + 10) =  DATA_OFFSET;
    *(int*)(output + 18) =  info.max_width;
    *(int*)(output + 22) = -info.height;
  
    Byte *pal = output + HEADER_SIZE;
    if (info.n_palette == -1)
        default_palette(pal);
    else
        fill_palette(pal, info.filename, info.n_palette);
 
    for (int h = 0, pos = DATA_OFFSET; h < info.height; h++) {
        for (int w = 0; w < info.max_width; w++)
            output[pos++] = info.image[h][w];
        for (int p = 0; p < pad; p++)
            output[pos++] = 0;
    }
  
    // Output filenames are: filename-outN.bmp where N is 0,1,...
    char outfilename[100];
    strcpy(outfilename, info.filename);
    char *p = strrchr(outfilename, '.');
    if (p) *p = '\0';
    sprintf(outfilename + strlen(outfilename), "-out%d.bmp",
        info.output_file_index);
  
    FILE *f = fopen(outfilename, "wb");
    fwrite(output, 1, file_size, f);
    fclose(f);
  
    free(output); }    void add(int value) {
    if (info.height < MAX_H && info.width < MAX_W)
        info.image[info.height][info.width++] = value; }    void process(FILE *fp) {
    for (int byte, prev = 0xFF; (byte = fgetc(fp)) != EOF; prev = byte) {
        int count, value;
        if (prev == 0xFF)
            printf("Chunk: %d\n", info.output_file_index);
        switch (byte) {
        case 0xFF: // End of image
            if (prev == 0xFE) {
                if (info.min_width != info.max_width)
                    printf("  Error: min (%d) and max (%d) widths do not match\n",
                        info.min_width, info.max_width);
                printf("  Width: %d  Height: %d\n", info.max_width, info.height);
                save_bmp();
            }
            reset();
            ++info.output_file_index;
            break;
        case 0xFE: // End of image line
            if (info.width < info.min_width) info.min_width = info.width;
            if (info.width > info.max_width) info.max_width = info.width;
            ++info.height;
            info.width = 0;
            break;
        case 0xFD: // next two bytes are count-1 and value
            count = fgetc(fp) + 1;
            value = fgetc(fp);
            for (int i = 0; i < count; ++i) add(value);
            break;
        case 0xFC: // next two bytes are count-1 and value
            value = fgetc(fp);  // orig. code had +1 here (but why?)
            count = fgetc(fp) + 1;
            for (int i = 0; i < count; ++i) // draw dithered line
                add(i % 2 == 0 ? value : value + 1);
            break;
        case 0xFB: // Set adder used in default case
            info.adder = fgetc(fp);
            break;
        default:
            if (ProgramMode == V1) {
                value = (byte >> 3) + info.adder; // High 5 bits are value
                count = (byte & 7) + 1;           // Low 3 bits are count-1
            }
            else {
                value = (byte >> 2) + info.adder; // High 6 bits are value
                count = (byte & 3) + 1;           // Low 2 bits are count-1
            }
            for (int i = 0; i < count; ++i) add(value);
        }
    } }    int main(int argc, char *argv[]) {
    if (argc < 2 || argc > 5) {
        printf("Usage: %s [-n] [-p N] INPUT_FILE\n", argv[0]);
        exit(EXIT_FAILURE);
    }
  
    while (**++argv == '-') {
        if (strcmp(*argv, "-n") == 0)
            ProgramMode = V2;
        else if (strncmp(*argv, "-p", 2) == 0) {
            if (argv[0][2])
                info.n_palette = atoi(&argv[0][2]);
            else {
                if (*++argv == NULL) {
                    fprintf(stderr, "Error: Missing parameters\n");
                    exit(EXIT_FAILURE);
                }
                info.n_palette = atoi(*argv);
            }
        }
        else {
            fprintf(stderr, "Error: Unknown switch: %s\n", *argv);
            exit(EXIT_FAILURE);
        }
    }
  
    if (!*argv) {
        fprintf(stderr, "Error: No filename\n");
        exit(EXIT_FAILURE);
    }
    info.filename = *argv;
    FILE *fp = fopen(info.filename, "rb");
    if (!fp) {
        perror(info.filename);
        exit(EXIT_FAILURE);
    }
   
    process(fp);
  
    return 0; }

Could someone look at the code, and tell me any changes that could be made to the Code i.e. adapt it ?, to extract the bitmap views from the S.PAC Files i.e. the Plane Shape Files, and save them as bitmaps in the game ? The .PAC Files are from the FE Folder in the game, and the .PNL Files from the CP Folder. the S.PAC Files are from the AC, i.e. Aircraft Folder in the game. and I have linked to some, of the output bitmap images, of .PAC and .PNL Files.

I watched the following Youtube Video, and particularly looked, at the Fonts Section of the video :-

https://www.youtube.com/watch?v=fKb_0BfKtsA&t=1644s

I noticed that when I opened the BF109GS.PAC and FW190AS.PAC Files in HxD Hex Editor there were repeating Bytes at the top few Offsets, i.e. 01 04 0D 31 01 04 0D 31 01 04 0D 31, on the first offset in the FW190AS.PAC File, then some more repeats in the BF109GS.PAC File, i.e. 01 07 0C 11 01 07 0C 11 01 06 0C 12 01 06 0C 12 01 06 0C 12 01 06 0D 11 01 06 0D, could these repeats be akin, to what the man in the video says they could be, for the Bioforge Game ? And what sections of code i.e. offsets do they correspond to here, are they saying, where the offsets and bytes, for each of the angle views are in the File?

Here is a link to the game, where you can download it from:-

https://www.abandonwaredos.com/abandonware-game.php?abandonware=Secret+Weapons+of+the+Luftwaffe&gid=2627

I run the 16bit DOS Game in the Program DOSBox, either in version 0.74 or 0.74.3 or the later version 0.83, which has alot more options, than the other two.

Here is a link, to the Files I uploaded :-

https://www.dropbox.com/t/eaq3eQBZ3cSzcoSq

The pacswotl and pnlswotl Folders amongst other files, contain the batch Files and compiled C program.

Also here is another dropbox website link, to Files and Folders which might be useful for this post :-

https://www.dropbox.com/t/lquuXmk6JBz1Hpkk

Could a Moderator, sort out the C Code, some of it hasn't displayed correctly in my post.

Any help and info would be much appreciated. If that is okay ?

54
  • that C code looks like a regular .bmp file parser.. you sure it's supposed to extract images from the game's data files? Commented Jul 12, 2023 at 18:37
  • Hi Ali, Yes the code does extract RLE Graphics from the Games Files, i.e. the ones I have in the pacswotl and pnlswotl Folders, in the download link I provide in my post. And saves the Graphics as Bitmap Files. Commented Jul 12, 2023 at 19:12
  • I have started to look into the provided files and have several questions: 1) I've tried to run pac files swotl (Works).cmd with *.PAC files. While it converts some of them into b/w bmp pictures, it doesn't generate any bmp files with e.g. FW190A.PAC and FW190AS.PAC. Am I doing something wrong, or is that what you want to solve? 2) The posted C program looks like a source code of PAC-MISC.exe but has some difference. PAC-MISC.exe accepts -d option but the C program does not. Which is the latest one? Can you provide the source code corresponding to the PAC-MISC.exe?
    – tshiono
    Commented Jul 13, 2023 at 8:58
  • 3) When you program the code, what did you use for reference? The linked Youtube video? Sorry for too many questions. BR.
    – tshiono
    Commented Jul 13, 2023 at 8:58
  • 1
    Hi tshiono, I will sort this out for you, when I get home tomorrow, early hours here at the moment. Commented Jul 19, 2023 at 1:43

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.