bd4 conversion program

Discussion around programming R'n'D, its source code and its tools.

Moderators: Flumminator, Zomis

dave
Posts: 77
Joined: Mon Aug 13, 2007 2:06 am
Contact:

bd4 conversion program

Post by dave »

i just wrote a small program to convert bd4 levels into emc levels, which should then be able to be loaded into r'n'd. as far as i can tell, bd4 is identical to kingsoft emerald mine (without emerald mine club enhancements) and they play okay in my player. i couldnt figure out how to attach a downloadable file to the message, so i just quoted the whole thing. its about 120 lines. a quick description of the fields is at the end of the code, so writing a converter for r'n'd (to load bd4 levels natively) shouldnt be too hard to cruft. use the files in the bd4 distribution tar in the data/ directory.

./conv < data/1.levels > bd4.1
./conv < data/4.levels > bd4.4

etc.

Code: Select all

/* 2007-11-12T21:47:54Z
 *
 * convert bd4 caves to emc v6 caves
 */

#include <stdio.h>
#include <string.h>
#include <errno.h>

static const unsigned char map_v4[256] = { /* filter crap for v4 */
    0,0,2,2,4,4,118,118,8,9,10,11,12,13,14,15,
    16,16,18,18,20,21,22,23,24,25,26,27,28,28,118,28,
    0,16,2,18,36,37,37,37,147,41,42,43,44,45,128,128,
    128,148,148,148,45,45,45,148,0,153,153,59,60,61,62,63,
    64,65,66,153,153,153,153,153,153,153,153,153,153,153,153,153,
    153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
    153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
    153,118,114,115,131,118,118,119,120,121,122,118,118,118,118,118,
    128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
    144,145,146,147,148,149,150,151,152,68,154,155,156,157,158,160,
    160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,175,
    153,153,153,153,153,153,153,153,153,153,153,153,153,153,68,153,
    153,153,153,153,153,153,153,153,200,201,202,203,204,205,206,207,
    208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
    224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
    240,241,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
};

unsigned char bd4[2432];
unsigned char emc[2172];

int main()
{
    int num;
    for(num = 0; fread(bd4, sizeof(bd4), 1, stdin) == 1; num++) {
        int i, j;
        if(bd4[98] != 32 && bd4[99] != 64) {
            fprintf(stderr, "unrecognized bd4 cave (%d)\n", num);
            continue;
        }

        memset(emc, 0, sizeof(emc));
        emc[2106] = 255; emc[2107] = 54; emc[2108] = 48; emc[2109] = 48;
        emc[2159] = 128;

        for(i = 0; i < 2048; i++) emc[i] = map_v4[bd4[i + 100]]; /* cave */
        for(i = 64; i < 2048; i++) if(emc[i] == 63) emc[i - 64] = 128;
        for(i = 64; i < 2048; i++) if(emc[i] == 63) emc[i - 64] = 101;

        for(i = 0; i < 36; i++) emc[i + 2048] = map_v4[bd4[i + 2149]]; /* eaters */
        for(i = 0; i < 36; i++) emc[i + 2112] = map_v4[bd4[i + 2185]];
        if(bd4[2148] == 4) {
            for(i = 0; i < 36; i++) emc[i + 2112] = emc[i + 2048];
        }

        for(i = 0; i < 10; i++) emc[i + 2084] = bd4[i + 2221]; /* scores */

        for(i = 0; i < 4; i += 2) { /* players */
            j = bd4[i + 2236] << 8 | bd4[i + 2237];
            j &= 2047;
            emc[i + 2096] = j >> 8; emc[i + 2097] = j;
            emc[j] = 128;
        }
        for(i = 0; i < 6; i += 2) { /* speed */
            j = bd4[i + 2240] << 8 | bd4[i + 2241];
            if(j > 9999) j = 9999;
            emc[i + 2100] = j >> 8; emc[i + 2101] = j;
        }

        i = bd4[2231] << 16 | bd4[2232] << 8 | bd4[2233]; /* time */
        i /= 50;
        if(i > 9999) i = 9999;
        emc[2110] = i >> 8; emc[2111] = i;

        i = bd4[2234] << 8 | bd4[2235]; /* emeralds */
        if(i > 255) i = 255;
        emc[2095] = i;

        if(fwrite(emc, sizeof(emc), 1, stdout) != 1) { perror("write failed"); return(1); }
    }
    return(0);
}

/*
structure of bd4 level disk files

elements are probably exactly the same as emerald mine v4

100 - cave data (64*32)
2148 - number of eater explosions
2149 - eater explosion 1
2158 - eater explosion 2
2167 - eater explosion 3
2176 - eater explosion 4
2185 - eater explosion 5
2194 - eater explosion 6
2203 - eater explosion 7
2212 - eater explosion 8
2221 - emerald score
2222 - diamond score
2223 - alien score
2224 - tank score
2225 - bug score
2226 - eater score
2227 - nut score
2228 - dynamite score
2229 - key score
2230 - bonus
2231 - time (seconds * 500)
2234 - emeralds needed
2236 - player 1 pos
2238 - player 2 pos
2240 - ameuba speed
2242 - wonderwall time
2244 - wheel time
2246
2432 - size

*/
HerzAusGold
Posts: 366
Joined: Sun Sep 25, 2005 4:41 pm
Location: Germany

Post by HerzAusGold »

Hi can you upload some levels to
Zomis filearchiv http://www.zomis.net/rnd/
?

I see the description in your code, but
do have a more detailed description about the format?

Your prog convert BD4 to EM-V6 format?
Is it than playable by any EM-prog? Which?

How many levels exists with this format?
And the answer is ... 42 !
dave
Posts: 77
Joined: Mon Aug 13, 2007 2:06 am
Contact:

Post by dave »

HerzAusGold wrote:Hi can you upload some levels to
Zomis filearchiv http://www.zomis.net/rnd/
?

I see the description in your code, but
do have a more detailed description about the format?

Your prog convert BD4 to EM-V6 format?
Is it than playable by any EM-prog? Which?

How many levels exists with this format?
i downloaded the latest bd4 program from
http://bd4.amristar.com.au/
and there were some levels in it.
i'll try and turn them into emc style names (00S 00T etc)
bd4 seems to use old emerald mine objects, but it needs the newest version because it has 8 eater explosions.
i'm not familiar with the way r'n'd organizes it's directories, so you'll probably have to add a levelinfo.conf file or something.

no more detailed description about bd4 format, it was just a quick thing to get the caves. what ive written _should_ be enough to get the caves out.
Steffest
Posts: 57
Joined: Thu Dec 06, 2007 9:27 pm
Location: Belgium
Contact:

Post by Steffest »

Hey,
years and years and years ago I wrote a cave-editor that could extract en export to BD4 levels.

I wrote down some specs on

http://www.steffest.com/dxboulder/EMLevelformat.htm

Maybe it can be usefull.

See you
Steffest
dave
Posts: 77
Joined: Mon Aug 13, 2007 2:06 am
Contact:

Post by dave »

Steffest wrote:I wrote down some specs on

http://www.steffest.com/dxboulder/EMLevelformat.htm

Maybe it can be usefull.
better info is in filter.c in my emc engine. (also in the rocks'n'diamonds source code... src/game_em/filter.c i think). it covers all versions up to v6 (which includes bd4) and is pretty much complete.

dave
HerzAusGold
Posts: 366
Joined: Sun Sep 25, 2005 4:41 pm
Location: Germany

Post by HerzAusGold »

Code: Select all


        for(i = 64; i < 2048; i++) if(emc[i] == 63) emc[i - 64] = 128;
        for(i = 64; i < 2048; i++) if(emc[i] == 63) emc[i - 64] = 101;

        for(i = 0; i < 36; i++) emc[i + 2048] = map_v4[bd4[i + 2149]]; /* eaters */
*Edit*
Hm, this works on Linux? --> Off course
On VisualC it ends up in an infinity loop. --> But only seems in the debugger
Seems I'm trapped into a Microsoft's quirk :oops:
It's working with the above code too!

I changed it to this: (for easier debugging)

Code: Select all

        for(i = 64; i < 2048; i++) { if(emc[i] == 63) emc[i - 64] = 128; }
        for(i = 64; i < 2048; i++) { if(emc[i] == 63) emc[i - 64] = 101; }

        for(i = 0; i < 36; i++) emc[i + 2048] = map_v4[bd4[i + 2149]]; /* eaters */
Hm the first for loop seems senseless because 128 is always overwritten with 101. What do you want to do?

Nevertheless I integrated it in RndTest. And it works fine.
RndTest is now able to load BD4 ".levels" files native.

Look here:
viewtopic.php?t=957


Have fun!
And the answer is ... 42 !
dave
Posts: 77
Joined: Mon Aug 13, 2007 2:06 am
Contact:

Post by dave »

HerzAusGold wrote:

Code: Select all

        for(i = 64; i < 2048; i++) { if(emc[i] == 63) emc[i - 64] = 128; }
        for(i = 64; i < 2048; i++) { if(emc[i] == 63) emc[i - 64] = 101; }

        for(i = 0; i < 36; i++) emc[i + 2048] = map_v4[bd4[i + 2149]]; /* eaters */
Hm the first for loop seems senseless because 128 is always overwritten with 101. What do you want to do?
it's quite necessary for acid that is stacked vertically. in the old emc engine this would produce a plant (holger modified it to fake acid). in the new engine it is simply removed (ie blank (128)) because plant broke some caves, and i dont really like fake acid (or any of the fake objects). change 128 to fake acid if you want, but i will (almost certainly) never support it in my engine.
all this may be moot if bd4 caves never used fake acid at all :)
HerzAusGold
Posts: 366
Joined: Sun Sep 25, 2005 4:41 pm
Location: Germany

Post by HerzAusGold »

Only again to mentioned:
In the array the 128 is not set! (or only set for a short time)
It is always overwritten with 101.
Because the second loop do the replacement again.
And the answer is ... 42 !
Steffest
Posts: 57
Joined: Thu Dec 06, 2007 9:27 pm
Location: Belgium
Contact:

Post by Steffest »

Hey HerzAusGold,

Just to be complete: not nececarily so. e.g.

if you have something like

00 00 00
00 63 00
00 63 00
00 63 00
00 63 00
00 63 00
00 63 00

you would end up with

00 128 00
00 128 00
00 128 00
00 128 00
00 128 00
00 101 00
00 63 00

so with vertically stacked elements, the top ones would be converted to 128.
HerzAusGold
Posts: 366
Joined: Sun Sep 25, 2005 4:41 pm
Location: Germany

Post by HerzAusGold »

Indeed! :shock:
Where are my eyes.
My only excuse is that I don't know that a EM-Cave have a width of 64.
Very good example what a linear loop can do.
Sorry for my mistake.
And the answer is ... 42 !
Steffest
Posts: 57
Joined: Thu Dec 06, 2007 9:27 pm
Location: Belgium
Contact:

Post by Steffest »

True, EM-caves are always 64 objects wide.
it also seems that all (or most ?) EM-players use a 1-dimensional array to store the level.
Thats why in borderless caves, if you walk to the right off the edge, you end up on the left end of the cave, but 1 row down, because, technically, thats the position just to the right of the right border.

Also, 1 dimensional array are generally faster then 2 dim arrays, expecially in tight loops, so maybe thats the reason why it was used back then when processor speeds where in the single digit Mhertz range.

Steffest
dave
Posts: 77
Joined: Mon Aug 13, 2007 2:06 am
Contact:

Post by dave »

Steffest wrote:True, EM-caves are always 64 objects wide.
it also seems that all (or most ?) EM-players use a 1-dimensional array to store the level.
Thats why in borderless caves, if you walk to the right off the edge, you end up on the left end of the cave, but 1 row down, because, technically, thats the position just to the right of the right border.

Also, 1 dimensional array are generally faster then 2 dim arrays, expecially in tight loops, so maybe thats the reason why it was used back then when processor speeds where in the single digit Mhertz range.

Steffest
at least original emerald mine program, emc v6 player (and i suspect bd4) used a 1d array, and fixed width caves.
my old em engine (which is still in r'n'd today) used a 2d array, and didnt support wrapping around on borderless caves.

my new engine (on zomis's rnd site) does support wrapping around with a 2d array, except it is imho sensible in that everything stays on the same y coord when it wraps. also the width can be variable and still wrap properly.

a 2d array is much much easier to code & read later on. it allowed me to easily fiddle with the way it scans over the level to make things a little less predictable (x coords are shuffled, but y still top to bottom). also wrapping came almost completely free with some c pointer tricks :)

an em engine i wrote for the amiga (in assembly which evolved into the c version today) used a 1d array & the logic was littered with 64's everywhere. it was a nightmare to change and true variable width caves were quite impossible. for that ancient code (which has gone to the bit bucket) i decided variable width (really fixed width but with the sides filled in) was more important so wrapping was out of the question (one or the other, not both :) you are right about the speed... i tried to squeeze every cycle out of it & a constant offset from a pointer is faster than a variable indexed one.
Steffest
Posts: 57
Joined: Thu Dec 06, 2007 9:27 pm
Location: Belgium
Contact:

Post by Steffest »

Hey,

I'm fiddling around with a flash based EM engine in Actionscript 2 (available here)
Not nearly complete, just poking around with it.

Compared to compiled languages actionscript is very slow, so I tried both 1 and 2 dim arrays.
This is the engine with 2 dims
This is the same engine with 1 dim
I didn't botter with the borders in the 1-dim version: it does wrap around, but the viewport doesn't follow, so if you walk across a border, you're kind of lost.

The speed increase is hardly noticable so I've sticked to 2 dim arrays also.

Clear, flexible and reusable code is more important then speed optimisations.

But we're drifting away again from R'n'B :-)
dave
Posts: 77
Joined: Mon Aug 13, 2007 2:06 am
Contact:

Post by dave »

dave wrote:better info is in filter.c in my emc engine. (also in the rocks'n'diamonds source code... src/game_em/filter.c i think).
i looked and its not in there. must have been removed by holger.

oh well, it is in Emerald Mine for X11 source code:

http://www.zomis.net/rnd/info.php?f=702

in the file emerald/conv/src/filter.c it has info on the binary emerald mine file format. all the object codes, file offsets etc.

steffest: all the emerald mine logic for v6 is in there and it may be easier to read than the (heavily modified) code in r'n'd. also the display code (scrolling etc) may easily port to flash thing. imho the most important thing for the graphics is making the player appear _behind_ everything, especially when going through doors and you can see him in the keyhole *ah* satisfying.

my code uses one offscreen pixmap which is blitted to the window every frame. if it needs to scroll, it is done with a blit in the offscreen pixmap. large blits seem to be much faster these days compared to the old, slow amiga so simple straightforward methods work better than tricks to save a big blit :)
Last edited by dave on Thu Dec 20, 2007 1:28 am, edited 1 time in total.
Steffest
Posts: 57
Joined: Thu Dec 06, 2007 9:27 pm
Location: Belgium
Contact:

Post by Steffest »

Hey Dave,
hmm ... The BD4 levelformat seems to have changed a bit since the last time I checked (which is years ago)

e.g. the 8 yam explosion slots.
Paul Williams did add some new elements to his bd4, like a wizard and a smart type of android that actually calculates the best path to chase you (pesky little bugger), but apparently they are not present in the included levels, and his java based online leveleditor, which had those elements, is no longer available.
Oh well ...

Yes, your EMC player is great!
Actually it's my favourite player at this moment for the PC.
One thing that annoys me though is the pusching of rocks, but that's because you took the V6 EMC player as a target.

In the original Kingsoft Emerald Mine, and also in the EMC version up to V5, thare was a random delay when you push a rock.

in your engine (and also in R'n'D, and also in EMC V6 and V7)
its push, wait, push, wait, push, wait ....

in the original EM (and also in EMC V5, and BD4, and my own DXBoulderdash)
its maybe push ... , wait, maybe push ..., wait, maybe push, ...

in psoedocode its something like: if (rand()>2,7) {pushrock}else{wait_one_more_tick}

that rockpush delay went missing somewhere between EMC V5 and V6 , and in my opinion thats a bug.
It really adds some spice to the game if the pushing of rocks is a little less predictable. (Maybe you can "fix that bug" hehe)

Cheers
Steffest
Post Reply