Zynaps Pokes - quick hack for improved collisions

Started by 8bitTinShed, 12:36, 28 October 21

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.


G'day fellow CPC fans, First time poster, hope this is the right place to post this. I was mucking around with z80 assembly and Zynaps collision detection on the CPC. Because it was one of my favourite games on my 6128, very good for 1987, but terrible collision bugs.

Here's a quick dirty hack for more forgiving scenery collisions in Zynaps, a 1 or 2 pixel sprite overlap with scenery, but at least you no longer explode alone in deep space!


These memory locations SEEM to be fixed "offsets" for the ship that are compared to the scrolling map values, there's more starting at 4980 but only 7 of them seemed to help me, maybe someone can improve on these?

Address(hex)  Value (hex)        Notes (do not put these in)
498C          00                 //01 - original values
498E          01                 //03
4990          05                 //07
4992          07                 //0E
4994          09                 //1C
4996          1C                 //38
4998          1C                 //70

Inject these pokes after Zynaps (CPC Wiki edition) is loaded into memory. I used WinApe poke system, choose Hex not decimal, I assume a multiface on a real CPC works too


I'm struggling to read the code but seems to me the collision code is imprecise by design for speed, this "fix" is just a quick dirty hack, but dodgy as this is it still feels a lot more playable like this.

I was wondering if there is anyone already working on a fix, maybe I can be at least a little bit useful, at least share all my debug notes and thoughts.

Casey - "8Bit_Tin_Shed"


Great job!
And yes this is absolutely the right place to post stuff like this!
Looking forward to trying this out shortly.


IIRC there was a special 'fixed' cpcwiki version of Zynaps, with enhanced menu and bigger loading picture, right?

I don't find it at the moment, but it would be cool the have the new pokes in there. Just mentioning it.  ;) :)
http://futureos.de --> Get the revolutionary FutureOS (Update: 2022.03.09)
http://futureos.cpc-live.com/files/LambdaSpeak_RSX_by_TFM.zip --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.12.26)


Quote from: GUNHED on 18:12, 28 October 21
IIRC there was a special 'fixed' cpcwiki version of Zynaps, with enhanced menu and bigger loading picture, right?

I don't find it at the moment, but it would be cool the have the new pokes in there. Just mentioning it.  ;) :)

I can't seem to find a download for the CPCWIki edition of Zynaps on CPCWiki any more, but it's still available from CPC-POWER (click on the black floppy disc icon and scroll down; it's labelled '(v2)').


That would be awesome if a final version of these pokes found its way into one of the dsk releases.
But I think we could improve these pokes a little.
Or even rewrite some of the collision routine that uses these values.

I'll clean up my notes so they make more sense and share them here for the more experienced coders.

Casey "8bitTinShed"


Great, because it was the missing work when we have done the improved cpcwiki version!
"You make one mistake in your life and the internet will never let you live it down" (Keith Goodyer)


I was so happy to find that version, thanks heaps! Before finding this version I had a version with the broken music.


Finally cleaned up my (long & beginner level) notes for collision improvement "pokes" on disassembled Zynaps.
Hopefully something jumps out for the experienced CPC coders that helps make the pokes better or another approach to make the collisions more accurate.

Cheers - 8bitTinShed

Amstrad CPC "Zynaps" Collision Investigation and "Fix" Pokes
By 8bitTinShed, 2021
Covid19 Lockdown, Australia
Great game from 1987, with some collision detection issues.

SCOPE - "Your ship explodes a number of pixels above a map object"
1. I'm a beginner at Amstrad CPC Assembly, huge knowledge / experience gaps.
2. Probably a few ludicrous assumptions.
3. But hey the pokes seem to mostly fix the worst of the collisions with the map.
GFX Assets
program code
screen buffers for scrolling / flipping
MEMORY DATA VARIABLES (used memory write breakpoints)
7D45 = Ship Y collision data position? (default start position is value 08)
       //Top of screen ship position is 00 bottom is 0C - WTF only 12 possible Y values??
       //But means working with a nibble which is fast?
       //Ship can move smaller units than this? - collision code on Y axis imprecise?
       //If my assumptions are right this not gunna be very accurate by design, hard to rewrite too.
       //INTERESTING - SET back to 08 with a poke and the ship is LOWER than start position
7D43 = Ship X collision position? (default value 14)
       //min 11 left most edge, max 32?
       //more than nibble - and more accurately represents ship pixel position on X axis
4980 = Base addy for collision data Y axis offsets?
       //TODO - Are they offsets for height? why do they not increase or decrease more evenly?
4992 = e.g addy for data checked at default ship Y position offset from 4980 - when crashing into first blue tower
       //Data inside here never changes, these seem to be offsets
49A0 = Scrolling map position data - populated from scrolling routine noted below.
49AD = e.g addy - this is collision spot on first blue tower at default ship Y position
48C8 //start of the Y axis collision detection with map?
4922 //subroutine 
48DF //the collision jump when we hit a map spot in B,C registers from routine at 48C8
564B //Main loop's check of carry flag to jump to death code -
5659 //Death routine start.
48E2 //Collision - set carry flag.

COLLISION ROUTINE   //identified by working backwards from death routine, collision 4 pixels above a tower
48C8 LD HL,#4980    //(#4980 - 00 Registers (changing): BC C000 BC'2855, DE 0600, DE' 3F0B)
48CB CALL #4922
4922 LD A, (IY+#06) // Load Ship Y position into Accumulator
                    // (IY: nearly ALWAYS #7D3F = ALWAYS 55)
                    // (IY+#06 - 7D45 = 08 default --> trying -02 instead -> ship moved UP (ship Y position??)
4925 INC A          //Add 1 to the ship Y position
4926 AND #0F        //logical AND ship Y with 0F - ensures it's in range, clearing left nibble - eg 09 didnt change but 19 would become 08 again
4928 SLA A          //Shift left arithmetic A = result of 08 y position is A = 12 - it gains an order of magnitude? worth noting more than a nibble now
492A LD C,A         //put A into C - (C is now 12)
492B LD B,00        // blank B
492D ADD HL, BC     //4980 gets BC (0012) added to it result - HL = 4992
                    //(offset applied for address pointer based on ship's Y position - WHY!?)
                    //(try another ship position, see what addy it points at)
                    //(4992 is: 0E)
                    //(higher - HL is 498E = 03)
                    //hmm these never change - assuming an offset.
492E LD B, (HL)     //B now 0E - contents of memory at HL(4992)
492F INC HL         //now pointing at 4993 - why? something to check there too.
4930 LD C, (HL)     // C now 00 (default flying at start)
4931 LD HL, #49A0   // it's 00 atm, but might be a variable for collision

4934 LD A, (IY+#04) //load ship X position into accumulator
SKIP                //- B AND C registers SEEM set for Y POS checks
...                 //D & E are set here with ship X position, skipping for now, Y axis way less precise.
493F RET            //(back to 48CE)

48C3                //WE ARE BACK HERE NOW
48D3 LD A, (HL)     //HL NOW 49AD = #78 - these populated from SCROLLING related routine.
48D4 AND B          //AND with B (still 0E from data var at 4992)
48D5 JR NZ, 48E2    //78 AND 0E = NZ result - FOUND A COLLISION
48E2 SCF            //Set Carry Flag - we have a collision to flag - we check later
48E3 RET            //Last return before death routine?
NOTE                //runs same loop again, same result - jump from 48D5
564B JR C,#5659     //IF CARRY FLAG SET trigger death routine (that's flag bit C from register F, not register C) 

SCROLLING MAP -     //This is feeding into vars for the collision routine above
NOTE                //As games scrolls we get one block write per frame everything is shifting left/ up in memory ->
420C LD HL,#49A2    //start reading from here and increment by 1 82 times (52 hex is in BD)
420F LD DE,#49A0    //write what we read into here - scrolling collision detection.
4215 LDIR           // writes to 49A0 -> 49AD too ->  BUT only once per frame, no AF block decrement

                    //SOOO what's feeding into the right hand side of all this?
                    //RIGHT SIDE IS: 49F0 -> 49F1
4217 JP #4277       
NOTE                //THIS BLOCK scrolls top half of map? i broke it to confirm
431A LD B,#40       // this value #40 is from A register on line below on the previous cycle
431C LC (#431B),A   // some simple self modifying code?
431F LD (#49F0),A
4322 OR B           //THIS! - Writing to 49F0 (but not earlier in the sliding window)
NOTE                //THIS BLOCK scrolls bottom half of map?
436D LD B, #40      //this value #40 is from A register on line below on the previous cycle
436F LD (#436E),A   //some simple self modifying code (always sets it to 40?)
4372 LD (#49F1),A
4375 OR B           //writing to 49F1 (second byte we write on the right hand side of the scrolling / sliding)
4376 XOR C          //this never seems to write to 49F1?? because C always same as B?

THE "FIX" POKES (work in progress)
These data memory locations seem to be data for comparing ship
at different Y positions to the scrolling map data.
I revised all the numbers in this range down by 1 over and over
And I did this until I didn't explode unfairly aginast the scrolling map at that Y position.

POKES - I stopped spontaneously combusting:
498C 00           //was 01 - top height bubble thingy lvl 1
498E 01           //was 03 - mid height bubble thingy lvl 1
4990 05           //was 07 - the first blue narrow tunnel thingy lvl 1
4992 07           //was 0E - the default starting position bllue tower crash lvl 1       
4994 09           //was 1C - the first bottom bit of the map on lvl 1
4996 1C           //was 38 - the tiny tiny little blue nob that you hit, and lowest pipes, lvl 1
4998 1C           //was 70 - very bottom map lvl 1

Test changes to these by setting a breakpoint at 5659 - and check value in register B.
Register B is populated by these vars, and persists until the death routine condition.
So this will tell you which of the offsets caused the collision in open space.

Q1. What exactly are these "ship" data vars at 4980? Does anyone experienced know how to derive these values?
So we can set meaningful more accurate values rather than trial and error *wink*
Current guess - Assuming they are offsets for representation of the ship at certain screen positions
But then why do they not increase or decrease more evenly...
Or maybe a gfx format I don't know, but data seems too small for ship gfx

Q2. Assuming I'm right about low precision design can we find enough free memory to hack in a new routine to
improve the accuracy of the Y axis collision code? Maybe it would make scrolling to slow though...
Either way I've never done that sort of thing, maybe it's quick for an experienced coder.

If you read this far you are a bloody legend, and you need a stiff drink, cheers.

Powered by SMFPacks Menu Editor Mod