JazzJackrabbit Community Forums

JazzJackrabbit Community Forums (http://www.jazz2online.com/jcf/index.php)
-   General Jazz Jackrabbit Talk (http://www.jazz2online.com/jcf/forumdisplay.php?f=4)
-   -   JJ & JJ2 screenshots of the whole maps? (http://www.jazz2online.com/jcf/showthread.php?t=20047)

Roobar Dec 3, 2016 10:27 PM

JJ & JJ2 screenshots of the whole maps?
 
Hey guys, are there any Jazz Jackrabbit 1 and 2 whole maps as a screenshots? I couldn't find any. Many other games have such. Or is there a way to make such? I really would like to examine the maps, but not in the editor.

Jelly Jam Dec 4, 2016 07:19 AM

You can view .j2l files on J2O. Just go to any download and click on the level it has. Same for JJ1.

Seren Dec 4, 2016 09:34 AM

For JJ2 levels, as long as you have the time it takes, I'm not aware of any better tools than my script (see here for usage details, although use the version in this post for more accurate results):

Code:

#pragma name "Full Level Screenshot"
jjPALCOLOR getColor(jjPALCOLOR dest, int index, SPRITE::Mode mode, int param) {
        jjPALCOLOR source = jjPalette.color[index];
        switch (mode) {
                case SPRITE::BRIGHTNESS:
                        return param < 128 ?
                                jjPALCOLOR(dest.red * param >> 7, dest.green * param >> 7, dest.blue * param >> 7) :
                                jjPALCOLOR(~(~dest.red * param >> 7), ~(~dest.green * param >> 7), ~(~dest.blue * param >> 7));
                case SPRITE::FROZEN:
                        {
                                jjPALCOLOR color(dest.red + source.red * 3 >> 2, dest.green + source.green * 3 >> 2, dest.blue + source.blue * 3 >> 2);
                                int light = color.getLight();
                                return jjPALCOLOR(light >> 3, light * 5 >> 3, light);
                        }
                case SPRITE::GEM:
                        {
                                const array hue = {245, 106, 136, 201};
                                jjPALCOLOR color;
                                color.setHSL(hue[param & 3], 255, index << 1);
                                return jjPALCOLOR(dest.red + color.red * 3 >> 2, dest.green + color.green * 3 >> 2, dest.blue + color.blue * 3 >> 2);
                        }
                case SPRITE::INVISIBLE:
                        return dest;
                case SPRITE::PALSHIFT:
                        return jjPalette.color[(index + param) & 255];
                case SPRITE::PLAYER:
                        {
                                jjPLAYER@ player = jjPlayers[param];
                                CHAR::Char chara = player.charCurr;
                                bool inRange0 = index >= (jjIsTSF && chara == CHAR::LORI ? 24 : 16) && index < 48;
                                bool inRange1 = index >= 88 && index < 96 && jjIsTSF && chara == CHAR::LORI;
                                bool inRange2 = index >= 80 && index < 88 && (chara == CHAR::BIRD || chara == CHAR::BIRD2 || chara == CHAR::FROG);
                                bool inRange3 = index >= 59 && index < 64 && chara != CHAR::BIRD && chara != CHAR::BIRD2;
                                if (inRange0 || inRange1 || inRange2 || inRange3) {
                                        array fur(4);
                                        for (int i = 0; i < 4; i++) {
                                                fur[i] = player.fur >> (i << 3);
                                        }
                                        if (chara == CHAR::BIRD) {
                                                for (int i = 0; i < 2; i++) {
                                                        uint temp = fur[i];
                                                        fur[i] = fur[i | 2];
                                                        fur[i | 2] = temp;
                                                }
                                        }
                                        if (inRange0)
                                                index -= 16;
                                        else if (inRange1)
                                                index -= 88;
                                        else if (inRange2)
                                                index -= 80;
                                        else if (fur[3] != 40)
                                                index -= index < 61 ? 34 : 33;
                                        else
                                                return source;
                                        return jjPalette.color[(fur[index >> 3] + (index & 7)) & 255];
                                }
                        }
                        return source;
                case SPRITE::SINGLECOLOR:
                        return jjPalette.color[param];
                case SPRITE::TRANSLUCENT:
                        return jjPALCOLOR(dest.red + source.red >> 1, dest.green + source.green >> 1, dest.blue + source.blue >> 1);
        }
        return source;
}
void drawLayers(array>& image, const array &in layers) {
        int width = image.isEmpty() ? 0 : image[0].length(), height = image.length();
        int layerCount = layers.length();
        array translucentPixels;
        for (int i = 0, j = 0; j < height; (i++) == (j += 32)) {
                for (int k = 0, l = 0; l < width; (k++) == (l += 32)) {
                        array tiles(layerCount, -1);
                        for (int m = 0; m < 32; m++) {
                                array@ row = image[j | m];
                                for (int n = 0; n < 32; n++) {
                                        int column = l | n;
                                        for (int o = 0; o < layerCount; o++) {
                                                int tile = tiles[o];
                                                if (tile < 0) {
                                                        int layer = layers[o];
                                                        int layerWidth = jjLayerWidth[layer], layerHeight = jjLayerHeight[layer];
                                                        int x = k, y = i;
                                                        if (x >= layerWidth) {
                                                                if (jjLayerTileWidth[layer])
                                                                        x %= layerWidth;
                                                                else
                                                                        x = -1;
                                                        }
                                                        if (y >= layerHeight) {
                                                                if (jjLayerTileHeight[layer])
                                                                        y %= layerHeight;
                                                                else
                                                                        y = -1;
                                                        }
                                                        tile = tiles[o] = x >= 0 && y >= 0 ? jjTileGet(layer, x, y) : 0;
                                                }
                                                int index = jjPIXELMAP(jjGetStaticTile(tile))[n, m];
                                                if (index != 0) {
                                                        jjPALCOLOR color = jjPalette.color[index];
                                                        if (tile & TILE::ANIMATED == 0 && jjTileType[tile & TILE::RAWRANGE] == 1) {
                                                                translucentPixels.insertLast(color);
                                                        } else {
                                                                row[column] = color;
                                                                break;
                                                        }
                                                }
                                        }
                                        while (!translucentPixels.isEmpty()) {
                                                jjPALCOLOR one = translucentPixels[translucentPixels.length() - 1], two = row[column];
                                                row[column] = jjPALCOLOR(one.red * 3 + two.red >> 2, one.green * 3 + two.green >> 2, one.blue * 3 + two.blue >> 2);
                                                translucentPixels.removeLast();
                                        }
                                }
                        }
                }
        }
}
void drawFrame(array>& image, jjANIMFRAME@ frame, int x, int y, int d, SPRITE::Mode mode, int param) {
        const jjPIXELMAP source(frame);
        int width = frame.width, height = frame.height;
        int xMax = image.isEmpty() ? 0 : image[0].length(), yMax = image.length();
        bool hFlip = d < 0, vFlip = (d & 0xC0 != 0) && (~d & 0xC0 != 0);
        x += hFlip ? 1 - (width + frame.hotSpotX) : frame.hotSpotX;
        y += vFlip ? 1 - (height + frame.hotSpotY) : frame.hotSpotY;
        int xDir = hFlip ? -1 : 1;
        int yDir = vFlip ? -1 : 1;
        int xStart = hFlip ? width - 1 : 0;
        int yStart = vFlip ? height - 1 : 0;
        for (int i = 0, j = y, k = yStart; i < height; (i++) ^ (j++) ^ (k += yDir)) {
                if (j >= 0 && j < yMax) {
                        array@ row = image[j];
                        for (int l = 0, m = x, n = xStart; l < width; (l++) ^ (m++) ^ (n += xDir)) {
                                if (m >= 0 && m < xMax) {
                                        int index = source[n, k];
                                        if (index != 0)
                                                row[m] = getColor(row[m], index, mode, param);
                                }
                        }
                }
        }
}
void takeScreenshot(const string &in filename) {
        array fgLayers, bgLayers;
        for (int i = 1; i < 8; i++) {
                if (
                        jjLayerHasTiles[i] &&
                        jjLayerXSpeed[i] == 1.f &&
                        jjLayerYSpeed[i] == 1.f &&
                        jjLayerXAutoSpeed[i] == 0.f &&
                        jjLayerYAutoSpeed[i] == 0.f &&
                        jjLayerXOffset[i] == 0.f &&
                        jjLayerYOffset[i] == 0.f
                )
                        (i < 4 ? fgLayers : bgLayers).insertLast(i);
        }
        bgLayers.insertLast(8);
        int width = jjLayerWidth[4] << 5, height = jjLayerHeight[4] << 5;
        array> image(height, array(width));
        drawLayers(image, bgLayers);
        for (int i = 1; i < jjObjectCount; i++) {
                const jjOBJ@ obj = jjObjects[i];
                if (obj.isActive && obj.curFrame != 0) {
                        int pickupAnim = obj.curAnim - jjAnimSets[ANIM::PICKUPS];
                        jjANIMFRAME@ frame = jjAnimFrames[obj.curFrame];
                        SPRITE::Mode mode;
                        int param = 0;
                        if (obj.freeze != 0) {
                                mode = SPRITE::FROZEN;
                        } else if (obj.justHit != 0) {
                                mode = SPRITE::SINGLECOLOR;
                                param = 15;
                        } else if (pickupAnim == 22 || pickupAnim == 34 || pickupAnim == 35) {
                                mode = SPRITE::GEM;
                                param = obj.var[0] - 1;
                        } else if (frame.transparent) {
                                mode = SPRITE::TRANSLUCENT;
                        } else {
                                mode = SPRITE::NORMAL;
                        }
                        switch (obj.eventID) {
                                case OBJECT::STOMPSCENERY:
                                case OBJECT::COLLAPSESCENERY:
                                case OBJECT::DESTRUCTSCENERY:
                                case OBJECT::DESTRUCTSCENERYBOMB:
                                case OBJECT::BUBBLER:
                                case OBJECT::GEMSTOMP:
                                        break;
                                case OBJECT::FLOATLIZARD:
                                        {
                                                int x = int(obj.xPos), y = int(obj.yPos);
                                                const jjANIMATION@ anim = jjAnimations[jjAnimSets[ANIM::LIZARD] + 3];
                                                drawFrame(image, jjAnimFrames[anim + jjGameTicks / 3  % anim.frameCount], x, y + 4, obj.direction, mode, param);
                                                drawFrame(image, frame, x, y, obj.direction, mode, param);
                                        }
                                        break;
                                case OBJECT::WARP:
                                        {
                                                const array palShift = {248, 48, 0, 24, 8, 32, 40};
                                                int x = int(obj.xPos), y = int(obj.yPos);
                                                const jjANIMATION@ anim;
                                                @anim = jjAnimations[obj.special];
                                                drawFrame(image, jjAnimFrames[anim + (obj.counter >> 3) % anim.frameCount], x - 1, y + 3, obj.direction, mode, param);
                                                @anim = jjAnimations[obj.curAnim];
                                                drawFrame(image, jjAnimFrames[obj.curFrame + anim.frameCount], x, y, obj.direction, mode, param);
                                                drawFrame(image, frame, x, y, obj.direction, SPRITE::PALSHIFT, palShift[obj.var[0] % 7]);
                                        }
                                        break;
                                case OBJECT::BRIDGE:
                                        {
                                                int length = 0, x = int(obj.xPos), y = int(obj.yPos);
                                                uint frameID = 0;
                                                const jjANIMATION@ anim = jjAnimations[obj.curAnim];
                                                do {
                                                        @frame = jjAnimFrames[anim + frameID];
                                                        drawFrame(image, frame, x + length - frame.hotSpotX, y, obj.direction, mode, param);
                                                        length += frame.width;
                                                        if (++frameID >= anim.frameCount)
                                                                frameID = 0;
                                                } while (length < obj.var[0]);
                                        }
                                        break;
                                case OBJECT::BOLLPLATFORM:
                                case OBJECT::FRUITPLATFORM:
                                case OBJECT::GRASSPLATFORM:
                                case OBJECT::PINKPLATFORM:
                                case OBJECT::SONICPLATFORM:
                                case OBJECT::SPIKEPLATFORM:
                                case OBJECT::SPIKEBOLL:
                                        {
                                                jjANIMFRAME@ subFrame = jjAnimFrames[jjAnimations[obj.killAnim]];
                                                int distPlus = subFrame.width - 1, dist = 0, anglePlus = -obj.var[5], angle = obj.var[4] - anglePlus * obj.var[2];
                                                for (int j = obj.var[2]; j > 0; j--) {
                                                        drawFrame(image, subFrame, int(obj.xOrg + dist * jjSin(angle)), int(obj.yOrg + dist * jjCos(angle)), 0, mode, param);
                                                        angle += anglePlus;
                                                        dist += distPlus;
                                                }
                                        }
                                        drawFrame(image, frame, int(obj.xPos), int(obj.yPos), obj.direction, mode, param);
                                        break;
                                case OBJECT::CTFBASE:
                                        {
                                                int animSet = jjAnimSets[ANIM::FLAG], x = int(obj.xOrg), y = int(obj.yOrg), d = obj.var[2] != 0 ? 1 : -1, t = jjGameTicks / 6;
                                                const jjANIMATION@ anim;
                                                @anim = jjAnimations[animSet + 1];
                                                drawFrame(image, jjAnimFrames[anim + obj.var[1]], x + 5 * d, y + 17, d, mode, param);
                                                @anim = jjAnimations[animSet + 2];
                                                drawFrame(image, jjAnimFrames[anim + t % anim.frameCount], x + 23 * d, y - 36, d, mode, param);
                                                if (obj.var[4] == 0) {
                                                        @anim = jjAnimations[animSet + 5];
                                                        drawFrame(image, jjAnimFrames[anim + t % anim.frameCount], x - 64 * d, y - 4, -d, mode, param);
                                                } else {
                                                        @anim = jjAnimations[animSet + 6];
                                                        drawFrame(image, jjAnimFrames[anim + obj.counter / 4 % anim.frameCount], x - 64 * d, y - 4, -d, mode, param);
                                                }
                                        }
                                default:
                                        drawFrame(image, frame, int(obj.xPos), int(obj.yPos), obj.direction, mode, param);
                        }
                }
        }
        for (int i = 0; i < 32; i++) {
                const jjPLAYER@ player = jjPlayers[i];
                if (player.isInGame && !player.invisibility)
                        drawFrame(image, jjAnimFrames[player.curFrame], int(player.xPos), int(player.yPos),
                                player.direction ^ (player.antiGrav ? SPRITE::FLIPV : SPRITE::FLIPNONE),
                                player.frozen == 0 ? player.spriteMode : SPRITE::FROZEN, player.spriteParam);
        }
        drawLayers(image, fgLayers);
        jjSTREAM file;
        string header = "P6 " + width + ' ' + height + " 255\n";
        int headerLength = header.length();
        for (int i = 0; i < headerLength; i++) {
                file.push(header[i]);
        }
        for (int i = 0; i < height; i++) {
                for (int j = 0; j < width; j++) {
                        jjPALCOLOR color = image[i][j];
                        file.push(color.red);
                        file.push(color.green);
                        file.push(color.blue);
                }
        }
        file.save(filename);
}
bool onLocalChat(string &in text, CHAT::Type type) {
        array results;
        if (type == CHAT::NORMAL && jjRegexMatch(text, """!screenshot(?:\s+([^\s"]+|"([^"]+)"))?\s*""", results, true)) {
                string filename;
                if (results[1].isEmpty())
                        filename = "SEscreenshot";
                else if (results[2].isEmpty())
                        filename = results[1];
                else
                        filename = results[2];
                takeScreenshot(filename + ".ppm.asdat");
                return true;
        }
        return false;
}


Stijn Dec 5, 2016 06:18 AM

Quote:

Originally Posted by Jelly Jam (Post 490775)
You can view .j2l files on J2O. Just go to any download and click on the level it has. Same for JJ1.

Worth noting that these are zoomed-out though. They also don't have events, etc, on them.

(which is a choice rather than a limitation, so if you really want a full-size full-detail shot of a particular level I could perhaps help you)

Simon Jan 12, 2017 01:02 AM

I would like full-level images of the JJ1 levels that ship with JJ1. I haven't found these levels in any downloadable in the JJ1 section, therefore the advice so far doesn't help.

How does the site generate the full-level images? Is there a full-level image dumper for download? Should I upload the JJ1 levels in a large archive and let the site dump them for me? <_<

Why I want the levels as images: I'm documenting a speedrunning route for Stonar 2. The first part of Stonar 2 looks the same everywhere, therefore ingame screenshots are too narrow, too hard to understand. I want an atlas image of this section and then draw reference points into it.

-- Simon

cooba Jan 12, 2017 05:23 AM

JJ1MOD can generate you full-sized level images: https://www.jazz2online.com/downloads/6040/-/

Stijn Jan 12, 2017 05:52 AM

Quote:

Originally Posted by Simon (Post 490942)
How does the site generate the full-level images? Is there a full-level image dumper for download? Should I upload the JJ1 levels in a large archive and let the site dump them for me? <_<

It's a script I wrote that generates preview images for all kinds of stuff in the downloads. Let me know if JJ1MOD doesn't help, and I could run it on the original levels. It doesn't show events, etc, though.

Simon Jan 14, 2017 09:49 PM

Quote:

JJ1MOD can generate you full-sized level images: https://www.jazz2online.com/downloads/6040/-/
Thanks! JJ1MOD did the job: Exported Stonar 2 initial section.

JJ1MOD's seems to be halfway command-line, halfway interactive, that made it hard to use in a shell loop. I resorted to running JJ1MOD in DOSBox, trying different levels one after another, giving interactive input (type "1" to select image export) for every level, until I had the desired image.

But it works!

Quote:

Let me know if JJ1MOD doesn't help, and I could run it on the original levels. It doesn't show events, etc, though.
Happy with the image, but thanks for the offer. :-)

-- Simon


All times are GMT -8. The time now is 09:10 AM.

Powered by vBulletin® Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
JCF © 2001-Infinity Jazz2Online