Skip to content
View in the app

A better way to browse. Learn more.

ResHax

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
Help us keep the site running.

Help with Cool Spot formats

Featured Replies

  • Localization

Hello!

 

I'm trying to extract custom file formats from DOS videogame Cool Spot. Formats are compressed by some modification of RLE compression i think + something else. 

I'm interested in everything except those 2 DOS binaries/executables(.exe) provided in the archive, since the all of the data is in other files.

Cool-Spot_DOS_EN.7z

  • 2 months later...
  • Supporter
On 9/16/2025 at 1:18 PM, anderlli0053 said:

Hello!

 

I'm trying to extract custom file formats from DOS videogame Cool Spot. Formats are compressed by some modification of RLE compression i think + something else. 

I'm interested in everything except those 2 DOS binaries/executables(.exe) provided in the archive, since the all of the data is in other files.

Cool-Spot_DOS_EN.7z 573.63 kB · 4 downloads

Here the Rle logic.
Vertical:
 

std::vector<uint8_t> decompress_type1(const std::vector<uint8_t>& data, int width, int height) {
    if (width <= 0 || height <= 0) return {};

    // Aloca buffer de saída (W * H)
    // Usamos long long para evitar overflow no calculo do tamanho se as dimensoes forem grandes
    size_t total_pixels = (size_t)width * (size_t)height;
    std::vector<uint8_t> output(total_pixels, 0);

    // Coordenadas para escrita vertical (x, y)
    int x = 0;
    int y = 0;

    size_t data_pos = 0;
    size_t data_len = data.size();

    // Helper para escrever pixel na geometria correta (Vertical: Top->Down, depois Left->Right)
    auto write_pixel = [&](uint8_t val) {
        if (x < width && y < height) {
            output[y * width + x] = val;
        }
        y++;
        if (y >= height) {
            y = 0;
            x++;
        }
        };

    while (data_pos < data_len) {
        // Se já preencheu a largura total, para
        if (x >= width) break;

        uint8_t cmd = data[data_pos++];

        if (cmd == 0) break; // Marcador de fim

        // Verifica bit 7 (0x80): Raw Copy (Literais)
        if (cmd & 0x80) {
            int count = (cmd & 0x7F) + 1;
            for (int i = 0; i < count; ++i) {
                if (data_pos < data_len) {
                    write_pixel(data[data_pos++]);
                }
            }
        }
        // RLE (Repetição)
        else {
            int count = 0;
            // Verifica bit 6 (0x40): Contagem estendida (2 bytes)
            if (cmd & 0x40) {
                if (data_pos < data_len) {
                    // Remove flags e combina com próximo byte (Little Endian)
                    count = ((cmd & 0x3F) << 8) | data[data_pos++];
                }
            }
            else {
                count = cmd;
            }

            count += 1;

            if (data_pos < data_len) {
                uint8_t val = data[data_pos++];
                for (int i = 0; i < count; ++i) {
                    write_pixel(val);
                }
            }
        }
    }

    return output;
}


horizontal

 


std::vector<uint8_t> decompress_type3(const std::vector<uint8_t>& data, int width, int height) {
    if (width <= 0 || height <= 0) return {};

    size_t total_pixels = (size_t)width * (size_t)height;
    std::vector<uint8_t> output(total_pixels, 0);

    size_t pos = 0;
    size_t data_pos = 0;
    size_t data_len = data.size();

    while (data_pos < data_len && pos < total_pixels) {
        uint8_t cmd = data[data_pos++];

        if (cmd == 0) {
            break;  // fim dos dados
        }

        if (cmd & 0x80) {
            // Literais
            size_t count = (cmd & 0x7F) + 1;
            for (size_t i = 0; i < count && data_pos < data_len && pos < total_pixels; ++i) {
                output[pos++] = data[data_pos++];
            }
        }
        else {
            // Repetido
            size_t count = 0;

            if (cmd & 0x40) {
                // Contagem estendida
                if (data_pos >= data_len) break;
                count = ((cmd & 0x3F) << 8) | data[data_pos++];
            }
            else {
                count = cmd;
            }
            count += 1;

            if (data_pos >= data_len) break;
            uint8_t val = data[data_pos++];

            for (size_t i = 0; i < count && pos < total_pixels; ++i) {
                output[pos++] = val;
            }
        }
    }

    return output;
}




image.png.b164eb4e72e0b81ae06bbc02052a9fe4.png

Edited by Rabatini

  • 2 weeks later...
  • Author
  • Localization
On 12/11/2025 at 8:13 PM, Rabatini said:

Here the Rle logic.
Vertical:
 

std::vector<uint8_t> decompress_type1(const std::vector<uint8_t>& data, int width, int height) {
    if (width <= 0 || height <= 0) return {};

    // Aloca buffer de saída (W * H)
    // Usamos long long para evitar overflow no calculo do tamanho se as dimensoes forem grandes
    size_t total_pixels = (size_t)width * (size_t)height;
    std::vector<uint8_t> output(total_pixels, 0);

    // Coordenadas para escrita vertical (x, y)
    int x = 0;
    int y = 0;

    size_t data_pos = 0;
    size_t data_len = data.size();

    // Helper para escrever pixel na geometria correta (Vertical: Top->Down, depois Left->Right)
    auto write_pixel = [&](uint8_t val) {
        if (x < width && y < height) {
            output[y * width + x] = val;
        }
        y++;
        if (y >= height) {
            y = 0;
            x++;
        }
        };

    while (data_pos < data_len) {
        // Se já preencheu a largura total, para
        if (x >= width) break;

        uint8_t cmd = data[data_pos++];

        if (cmd == 0) break; // Marcador de fim

        // Verifica bit 7 (0x80): Raw Copy (Literais)
        if (cmd & 0x80) {
            int count = (cmd & 0x7F) + 1;
            for (int i = 0; i < count; ++i) {
                if (data_pos < data_len) {
                    write_pixel(data[data_pos++]);
                }
            }
        }
        // RLE (Repetição)
        else {
            int count = 0;
            // Verifica bit 6 (0x40): Contagem estendida (2 bytes)
            if (cmd & 0x40) {
                if (data_pos < data_len) {
                    // Remove flags e combina com próximo byte (Little Endian)
                    count = ((cmd & 0x3F) << 8) | data[data_pos++];
                }
            }
            else {
                count = cmd;
            }

            count += 1;

            if (data_pos < data_len) {
                uint8_t val = data[data_pos++];
                for (int i = 0; i < count; ++i) {
                    write_pixel(val);
                }
            }
        }
    }

    return output;
}


horizontal

 


std::vector<uint8_t> decompress_type3(const std::vector<uint8_t>& data, int width, int height) {
    if (width <= 0 || height <= 0) return {};

    size_t total_pixels = (size_t)width * (size_t)height;
    std::vector<uint8_t> output(total_pixels, 0);

    size_t pos = 0;
    size_t data_pos = 0;
    size_t data_len = data.size();

    while (data_pos < data_len && pos < total_pixels) {
        uint8_t cmd = data[data_pos++];

        if (cmd == 0) {
            break;  // fim dos dados
        }

        if (cmd & 0x80) {
            // Literais
            size_t count = (cmd & 0x7F) + 1;
            for (size_t i = 0; i < count && data_pos < data_len && pos < total_pixels; ++i) {
                output[pos++] = data[data_pos++];
            }
        }
        else {
            // Repetido
            size_t count = 0;

            if (cmd & 0x40) {
                // Contagem estendida
                if (data_pos >= data_len) break;
                count = ((cmd & 0x3F) << 8) | data[data_pos++];
            }
            else {
                count = cmd;
            }
            count += 1;

            if (data_pos >= data_len) break;
            uint8_t val = data[data_pos++];

            for (size_t i = 0; i < count && pos < total_pixels; ++i) {
                output[pos++] = val;
            }
        }
    }

    return output;
}




image.png.b164eb4e72e0b81ae06bbc02052a9fe4.png


Thank you, i managed to rewrite it in Python and i got .PIC and .TEX out into readable PNGs. Other files use some other form of encryption and compression and i did not manage to decompile them, they could also contain pallete for the images/whole game. So all-in-all that's a win... other things are not really important as this is old DOS game and it does not use 3D model formats for the models, but rather use buffers and direct drawing techniques to create meshes.. thank you again for the c++ one!

  • Supporter
42 minutes ago, anderlli0053 said:


Thank you, i managed to rewrite it in Python and i got .PIC and .TEX out into readable PNGs. Other files use some other form of encryption and compression and i did not manage to decompile them, they could also contain pallete for the images/whole game. So all-in-all that's a win... other things are not really important as this is old DOS game and it does not use 3D model formats for the models, but rather use buffers and direct drawing techniques to create meshes.. thank you again for the c++ one!

Nice!! do you have these files? we can dig out.

  • Author
  • Localization

... only now i see that this is the thread for Cool Spot... i was talking about the similar game "Ignition", which i managed to partially decompile... From the Cool Spot i got just mangled images... nothing else - i just switched game names by accident, i meant for the Ignition one, not this one, i just re-read this thread and just saw the mistake i made.. 🤦‍♂️
 

coolspot.zip

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.