slime permeability and BDCFF

Everything about the modern clones and remakes.

Moderator: Admin

User avatar
cirix
Member
Posts: 284
Joined: Fri Feb 01, 2008 11:00 pm
Contact:

Post by cirix »

Sarr. wrote:now something i'd like to ask the mighty cirix ;]
wow :D

here it is:
for 128
Step[000].Rand[246].Perm[128].Result[0] (the diamond does not)
Step[000].Rand[005].Perm[128].Result[1] (the stone does)
Step[000].Rand[222].Perm[128].Result[0] (the diamond does not)
Step[000].Rand[064].Perm[128].Result[1] (diamond does)
Step[000].Rand[108].Perm[128].Result[1] (another diamond)
Step[000].Rand[226].Perm[128].Result[0] (nothing again)
Step[000].Rand[097].Perm[128].Result[1] (diam, diam, stone, diam)
Step[000].Rand[042].Perm[128].Result[1]
Step[000].Rand[061].Perm[128].Result[1]
Step[000].Rand[026].Perm[128].Result[1]

for 192:
Step[000].Rand[246].Perm[192].Result[0]
Step[000].Rand[005].Perm[192].Result[1]
Step[000].Rand[222].Perm[192].Result[0]
Step[000].Rand[064].Perm[192].Result[0]
Step[000].Rand[108].Perm[192].Result[0]
Step[000].Rand[226].Perm[192].Result[0]
Step[000].Rand[097].Perm[192].Result[0]
Step[000].Rand[042].Perm[192].Result[1]
Step[000].Rand[061].Perm[192].Result[1]
Step[000].Rand[026].Perm[192].Result[1]

and for 224:
Step[000].Rand[246].Perm[224].Result[0]
Step[000].Rand[005].Perm[224].Result[1]
Step[000].Rand[222].Perm[224].Result[0]
Step[000].Rand[064].Perm[224].Result[0]
Step[000].Rand[108].Perm[224].Result[0]
Step[000].Rand[226].Perm[224].Result[0]
Step[000].Rand[097].Perm[224].Result[0]
Step[000].Rand[042].Perm[224].Result[0]
Step[000].Rand[061].Perm[224].Result[0]
Step[000].Rand[026].Perm[224].Result[1]


random numbers are everywhere the same. then use binary (bitwise) AND; then if the result is 0, stuff will pass.

if all things match, think about the following. if a diamond passes (0th frame), then there will be space at the original place of it. in the next frame, the element, which was above it (for example, a stone), falls down one row. but it is NOT a stone in this frame, but a falling stone! so even if in the next frame (1st frame) the slime would allow passing an element, it passes nothing, because it will not pass a falling stone, only a steady stone. only in the 2nd frame has the stone any probability to pass - because it is a stone in the 2nd frame, and not a falling stone.
cirix
subotai
Member
Posts: 251
Joined: Sun Jan 25, 2009 4:19 pm

Post by subotai »

No, I have no question for the moment :)
Thank you cirix for your exact description. That helped me much. My SlimePermeability works accurate now.

For everybody who's interested I'd like to show, how you translate the PLCK values. In PLCK games, the slime permeability is stored in a value between 0 and 8. Look at the binary code to understand how it works:

Code: Select all

PLCK value;     Binary code;   Byte value (SlimePermeability)

0;                00000000;    0
1;                00010000;    16
2;                00011000;    24
3;                00111000;    56
4;                00111100;    60
5;                01111100;    124
6;                01111110;    126
7;                11111110;    254
8;                11111111;    255
subotai
User avatar
LogicDeLuxe
Member
Posts: 638
Joined: Sun Jul 15, 2007 12:52 pm
Contact:

Post by LogicDeLuxe »

subotai wrote:For everybody who's interested I'd like to show, how you translate the PLCK values.
Interesting. Where did you get that table from? The most obvious way would be just shifting in as many 1s as the PLCK value states. It's what CLCK does.

I must admit that I have not done much testing on slime patterns when I wrote the PLCK import into CLCK. And I didn't search the PLCK code for it either.
User avatar
cirix
Member
Posts: 284
Joined: Fri Feb 01, 2008 11:00 pm
Contact:

Post by cirix »

subotai wrote:In PLCK games, the slime permeability is stored in a value between 0 and 8. Look at the binary code to understand how it works:

Code: Select all

PLCK value;     Binary code;   Byte value (SlimePermeability)

0;                00000000;    0
1;                00010000;    16
2;                00011000;    24
3;                00111000;    56
4;                00111100;    60
5;                01111100;    124
6;                01111110;    126
7;                11111110;    254
8;                11111111;    255
That seems also very strange to me as well. but i write it in my to do list to investigate this thing more.
cirix
subotai
Member
Posts: 251
Joined: Sun Jan 25, 2009 4:19 pm

Post by subotai »

Just check it out. I especially compared it in SendyDash01 Cave06. Export the game in Gdash to BDCFF, change the Slimepermeability in the BDCFF-file and compare the orignal game in Vice step by step with Gdash (the engine in Gdash works perfect concerning this). You can also just generate any cave that contains slime and check, if it behaves exactly the same in both engines. The cave delay doesn't have any influence on the SlimePermeability.
LogicDeLuxe wrote:Interesting. Where did you get that table from?
I created a testcave in PLCK similar to CaveE in Bd2 and analysed in which scan the slime let the boulders pass. In my engine, I created a loop for the Slimepermeability from 0 to 255 and checked when the slime had the same behaviour as in the PLCK cave. I checked this for some values ("0" to "8") and I found out that there is a system behind.

I did a lot of tests to confirm if I'm right and I think that there can't be so much coincidence that it always worked perfect with these values.

Besides, how did you find out the values you use for the BDCFF cirix?

subotai
User avatar
cirix
Member
Posts: 284
Joined: Fri Feb 01, 2008 11:00 pm
Contact:

Post by cirix »

subotai wrote:Besides, how did you find out the values you use for the BDCFF cirix?
it was a guess using the available "literature".


but well, you are right.
the values are >C:775a 00 10 18 38 3c 7c 7e fe ff


here is the disassembly from the original construction kit:
slime permeability in plck
--------------------------
slime permeability is stored in $93, which is set at $4f59 in plck.

.C:4f59 AD 0B 41 LDA $410B
.C:4f5c 85 93 STA $93 ; store slime permeability

the code which creates 410b is
.C:7721 AE B5 77 LDX $77B5
.C:7724 BD 5A 77 LDA $775A,X
.C:7727 8D 0B 41 STA $410B

so slime permeability values are stored at 775a, which are
>C:775a 00 10 18 38 3c 7c 7e fe ff



i will also check all other versions (bd2, 1stb etc).
for bd2, something different happens, as for cave m, the permeability is e0, which is not in the above table.

EDIT:
well, other engines simply copy the value from the imported cave data, it seems to me.
this thing only affects plck levels, not 1stb and later versions. also does not affect bd2.
cirix
User avatar
LogicDeLuxe
Member
Posts: 638
Joined: Sun Jul 15, 2007 12:52 pm
Contact:

Post by LogicDeLuxe »

As far as CLCK is concerned, the 0-8 is calculated on the fly and then the actual pattern value is stored with the cave data. It really only affects the PLCK import.
subotai
Member
Posts: 251
Joined: Sun Jan 25, 2009 4:19 pm

Post by subotai »

I have no skills in assembly. So it took me a few hours to find this out. What a waste of time :roll:

@Sarr.
If it still doesn't work in your game, you should maybe also check your implementations of the other elements. In my game it didn't work first only because the explosion of the elements wasn't accurate.
User avatar
Piter
Member
Posts: 41
Joined: Mon May 26, 2008 8:53 pm
Location: Poland

Post by Piter »

Hi!

Now I have similar problem to Sarr and I'm stuck with it. I'm writing BD clone in C++ and predictable Slime permeability doesn't work as desired.

As far as random number generator itself is concerned I'm almost sure it works perfectly. I've checked it against many different caves and didn't see any mistakes.

Problems started when the slime came in. Again - I've tested several caves (especially E from BD2) and compared it against GDash and Atari emulator (if possible). I've also created map-coded cave in GDash and ported it to my clone. Just to be sure I begin with the same random seed values in this case (00 1E).

Regardless whether the cave is random based or map-coded I've found not always the pattern is being followed precisely. For example for higher values like 252, 248, 240 it seems to be working, but for 224 (as also cave E has) pattern is quickly broken.

Here is what I do after cave is loaded & decoded. If it was map-based I set manually random seed values to 00 1E.

1) I iterate from top left corner (0,0) field by field, line by line and check what is in this position

2) If there is slime I do in this order:

-mark this field as "scanned this frame"
-generate random number
-bitwise sum this number and permeability value (AND)
-if result was 0, then pattern is OK. "Slime" checks whether there is stationary boulder/diamond laying on it and free space below. If so - it allows it pass and marks it as _falling and delayed(scanned this frame)_.

3) Generally that's it.

Here is precise code for how I handle slime with my comments.

Code: Select all

if (BDObjects.Slime.predictable) {
    // for every slime found a random number is generated
    BDLevel.NextRandom(&BDLevel.RandSeed1, &BDLevel.RandSeed2);
    
    // by bitwise logic AND the check is made whether slime is permeable
    if ((BDLevel.RandSeed1 & BDObjects.Slime.permeability_predictable) == 0) {

            // if so, a check is made if there's empty space underneath the slime
            // and the object laying above is stationary boulder or diamond
            if ((BDLevel.pl[x][y+1] == 0) && ((BDLevel.pl[x][y-1] == 1) || (BDLevel.pl[x][y-1] == 3))) {

                // if these criteria are satisfied, the object falls through the slime
                // by moving two squares down (it will NEVER be inside it). Its state
                // is set to falling and delayed. Appropriate sound is played.
                switch (BDLevel.pl[x][y-1]) {
                    case 1: BDLevel.pl[x][y+1] = 11;
                            BDSound.Boulder();
                            BDLevel.pl[x][y-1] = 0;
                            isScanned[x][y+1] = 1;
                            break;
                    case 3: BDLevel.pl[x][y+1] = 13;
                            BDSound.Diamond();
                            BDLevel.pl[x][y-1] = 0;
                            isScanned[x][y+1] = 1;
                            break;
                    default: break;
                }

            }
        }
    }
I hope it is easy to understand - if not, let me know I'll explain everything further step by step.

I completely have no idea where might be mistake :/ Maybe someone of you will be able to help... or maybe Sarr had found answer, because it really seems that almost exactly the same problem he had once.
subotai
Member
Posts: 251
Joined: Sun Jan 25, 2009 4:19 pm

Post by subotai »

As already said, also check the implementations of the other elements (explosions f.e.).
User avatar
Piter
Member
Posts: 41
Joined: Mon May 26, 2008 8:53 pm
Location: Poland

Post by Piter »

Yes, Subotai, I have already read this whole topic and so far I wasn't able to figure out problem in implementation of other elements :/

Let's look at Cave E in BD2 - there are only few objects - boulders, diamonds, space, dirt and steel wall... I really don't have idea what might be wrong here.

Ok. Let's stick to boulders/diamonds algorithm - correct me if I'm wrong.

1) scanning "Standing boulder" behavior

-checks if it has has space below (FAILED)
-checks if it can roll off (FAILED)
-remains stationary (BUT NOT DELAYED (scanned this frame), RIGHT?)

2) scanning "Falling boulder" behavior

-checks if it has space below (FAILED)
-checks if it has magic wall below (FAILED)
-checks if it has something explosive below (FAILED)
-becomes stationary (AND DELAYED)

We assume that slime can pass only stationary boulders and diamonds. And not delayed, right?

So let's consider following scenario:

(... scan goes ....)
1) Falling boulder is encountered that had landed on slime frame. It became stationary boulder with delayed state.

(... scan goes ...)
2) Slime is encountered. Random number is generated. Pattern matches. Stationary boulder is now sitting on it, BUT IT WON'T PASS since it is DELAYED?

(... frame ends ...)

Am I getting this right? I might be close to the solution if Boulder/Diamond to fall MUST BE STATIONARY and NOT DELAYED?

EDIT: does anyone can provide me with RandSeed values for cave E/1 (BD2). I mean what are these two values when cave begins.... I might have other lead... In my game values are AE E8. Maybe here is a bug
Best, Peter
User avatar
LogicDeLuxe
Member
Posts: 638
Joined: Sun Jul 15, 2007 12:52 pm
Contact:

Post by LogicDeLuxe »

piter wrote:We assume that slime can pass only stationary boulders and diamonds. And not delayed, right?
Slime has to ignore the scanned flag. Think about it, you would be able to collect a diamond "falling" through slime.
On the other hand, I don't see your code checking for the scanned flag anyway.
User avatar
Piter
Member
Posts: 41
Joined: Mon May 26, 2008 8:53 pm
Location: Poland

Post by Piter »

Thanks for answer, Logic. I just wanted to be sure. Slime in my implementation doesn't check whether item laying on it is in delayed state - so it is correct.

Now I'm eager to know these initial randseed values for cave E1 from BD2. Could anyone check this, please?
subotai
Member
Posts: 251
Joined: Sun Jan 25, 2009 4:19 pm

Post by subotai »

For PLCK Caves: $1E $00;
for Bd2 Cave E1: $E5 $21;

An element that passes the slime gets the falling state.
User avatar
cirix
Member
Posts: 284
Joined: Fri Feb 01, 2008 11:00 pm
Contact:

Post by cirix »

piter: i spent a lot of time on researching the slime predictability. i copy the relevant stuff here from the gdash source documentation (docs/c64_internals.txt).

Code: Select all

predictable slime in plck
-------------------------
This is taken from afl boulder dash:

	 * .C:43dd   20 E6 41   JSR $41E6     ; predictable random
	 * .C:43e0   25 93      AND $93       ; & slime_permeability
	 * .C:43e2   D0 25      BNE $4409     ; slime works if result is 0

and at the start of the game, predictable random generator is
initialised as:
    RandSeed1 = 0
    RandSeed2 = 0x1e
this is required for afl bd cave 15, for example.

the following routine explicitly sets randseed1 and randseed2:
.C:4b6f   A9 00      LDA #$00
; ......
.C:4b91   8D 42 3D   STA $3D42
.C:4b94   8D 43 3D   STA $3D43
.C:4b97   8D 44 3D   STA $3D44
.C:4b9a   A9 1E      LDA #$1E
.C:4b9c   8D 41 3D   STA $3D41

so no worry about random values in memory.
so you should check out afl boulder dash (alphaflight boulder dash), which is also the starting caveset in gdash. cave 15 has a very special timing - it requires the slime emulation to be 1:1 frame (cave iteration) exact, otherwise you'll be stuck at the upper left corner of the screen with rockford. just check the cave to see what i mean.

regarding the values used for the bitwise and by the "will the stone pass?" routine:

Code: Select all

slime permeability in plck
--------------------------

slime permeability is stored in $93, which is set at $4f59 in plck.

.C:4f59   AD 0B 41   LDA $410B
.C:4f5c   85 93      STA $93        ; store slime permeability

the code which creates 410b is
.C:7721   AE B5 77   LDX $77B5
.C:7724   BD 5A 77   LDA $775A,X
.C:7727   8D 0B 41   STA $410B

so slime permeability values are stored at 775a, which are
>C:775a  00 10 18 38  3c 7c 7e fe  ff
you can check these using the vice monitor, maybe check if different versions use different values. so far these worked for me ok.

bd2 uses a different "approach". in that engine, the random seed value is not explicitely initialized: the values left there after the cave random fill routine are used. so the random seed depends on the cave random seed value.

Code: Select all

slime permeability in bd2
-------------------------

stored at $99, used at a059:
.C:a059   20 81 9E   JSR $9E81
.C:a05c   25 99      AND $99
.C:a05e   D0 25      BNE $A085
.C:a060   A0 51      LDY #$51
.C:a062   B1 32      LDA ($32),Y
.C:a064   D0 1F      BNE $A085


set at 4e65
.C:4e64   60         RTS
.C:4e65   A5 DA      LDA $DA
.C:4e67   85 99      STA $99
.C:4e69   60         RTS

predictable slime in bd2
------------------------
randomseed1 and 2 are values left there after cave initialization.
remember that during generating random elements, the upper and lower border ARE NOT filled.
the last sentence is important; the 40x22 cave is not filled by random values, only a 40x20 part of the cave, ie. the random generator routine is called 800x after initializing it at cave load. whatever value it has at that moment, that will be the starting value for the slime random number generator. see caverendered.cpp:412 in the gdash source.

if you try boulder dash 2 cave e/1 in an emulator and in gdash, you'll see that stones and diamonds fall in the same pattern. this pattern depends on the level, e/2 will have another pattern. another random seed value is used for the cave fill, causing another value to be left there when the random fill routine has finished.
cirix
Post Reply