@kayahr/wastelib
    Preparing search index...

    @kayahr/wastelib

    wastelib

    A JavaScript library (Written in TypeScript) for reading the assets of the game Wasteland. Can be used in web-based or Node.js applications to easily parse all the images, animations, maps and other game data from the original Wasteland files.

    The library is based on the valuable information gathered by the members of the Wasteland Deconstruction Wiki.

    The Demo shows wastelib in action.

    Install wastelib as a standard NPM dependency:

    npm install @kayahr/wastelib
    

    And then simply import and use it:

    import { Title } from "@kayahr/wastelib";

    const title = Title.fromBlob(titlePicBlob);
    const width = title.getWidth();
    const height = title.getHeight();
    for (let x = 0; x < width; x++) {
    for (let y = 0; y < height; y++) {
    const rgbaPixel = title.getColor(x, y);
    // ...
    }
    }

    Parsing assets

    There are classes for each asset type of the game:

    • Cursors - For parsing the mouse cursor images from the CURS file.
    • Ending - For parsing the end animation from the END.CPA file.
    • Exe - For fetching strings and offsets from the WL.EXE file.
    • Font - For parsing the color font from the COLORF.FNT file.
    • GameMap - For parsing map data from GAME1 and GAME2 files.
    • Portraits - For parsing the portrait animations from the ALLPICS1 and ALLPICS2 files.
    • Savegame - For parsing savegame data from GAME1 and GAME2 files.
    • ShopItemList - For parsing shop item lists from GAME1 and GAME2 files.
    • Sprites - For parsing the sprites from the IC0_9.WLF and MASKS.WLF files.
    • Tilesets - For parsing the tilesets from the ALLHTDS1 and ALLHTDS2 files.
    • Title - For parsing the title image from the TITLE.PIC file.

    There are always two types of static methods to parse the files:

    • The synchronous fromArray() method (or fromArrays() if data is read from multiple files) simply reads the data from a Uint8Array. How you fetched the data from the corresponding game files is up to you. In a browser you might want to fetch the data via HTTPS, while in Node.js you might want to read the files with readFile.
    • The asynchronous fromBlob() method (or fromBlobs() if data is read from multiple files) can be used with Blob or File objects which can for example be created by a file selector in the browser or with openAsBlob in Node.js.

    wastelib is also able to read the text paragraphs from the file paragraphs.bin shipped by the modernized game release Wasteland 1 - The Original Classic.

    Here is a small Node.js example:

    import { readParagraphs } from "@kayahr/wastelib";
    import { open } from "node:fs/promises";

    const file = await open("paragraphs.bin");
    const paragraphs = await readParagraphs(file);
    console.log(paragraphs[130]);

    The file handle passed to readParagraphs is a minimal interface with just one simple read method which Node.js' FileHandle type already implements. When using readParagraphs in a browser (very unlikely because this file is a whooping 19 MiB) then this minimal interface must be implemented manually.

    There are lots of OCR errors in paragraphs.bin and messed up line breaks. The OCR errors are automatically corrected and the line breaks are normalized and corrected as well, so each line in a paragraph represents a single continuous text block to allow dynamic line wrapping, paragraph spacing and indentation.

    wastelib uses the Canvas API for generating image output but the API is build to not depend on a specific canvas implementation. So in a browser you can use the built-in canvas implementation and in Node.js you can use node-canvas instead.

    Browser:

    import { Title } from "@kayahr/wastelib";

    const title = await Title.fromBlob(await (await fetch("title.pic")).blob());
    const canvas = title.toCanvas(document.createElement("canvas"));
    document.appendChild(canvas);

    Node.js:

    import { Title } from "@kayahr/wastelib";
    import { createCanvas } from "canvas";
    import { readFile, writeFile } from "node:fs/promises";

    const title = await Title.fromArray(await readFile("title.pic"));
    const canvas = title.toCanvas(createCanvas(0, 0));
    await writeFile("/tmp/title.png", canvas.toBuffer());

    So you always create an empty canvas object yourself (initial size doesn't matter) and pass it to the toCanvas() method which then fills the canvas with the image and returns it.