Jump to content
Jet Set Willy & Manic Miner Community

MM Movement and Collision Detection explanation


selfdelmer

Recommended Posts

On 10/7/2025 at 9:07 PM, SymbolShift said:

Should I use the original mechanics (warts and all) to be faithful to the originals? MM mechanics for a MM clone, and JSW mechanics for a JSW clone, or new mechanics altogether? My concern is that someone unfamiliar with the original mechanics quirks, could play my game and interpret them as bad programming.

The superstar solution would be to give the game an "enable bug compatibility" option. I'm not sure what platform you're talking about. On a speccy 48k that would probably require wizard levels of programming on a more modern platform it would still be hard.

Just throwing that out in case it wasn't obvious.

Link to comment
Share on other sites

This bit took me ages to work out using the disassembly from skoolkit.

On 10/7/2025 at 8:07 PM, SymbolShift said:

It appears that Matthew Smith's solution was to simply try and avoid those situations, rather than rewrite the movement mechanics.

As regards JSW, the movement mechanics were altered to fit the situations (such as The Forgotten Abbey), hence the head height bug. In my re-write, I fixed the situations with new block types to keep the MM mechanics. Of course, I did the changes only to fix the bugs and not change the game play.

Link to comment
Share on other sites

1 hour ago, fawtytoo said:

This bit took me ages to work out using the disassembly from skoolkit.

As regards JSW, the movement mechanics were altered to fit the situations (such as The Forgotten Abbey), hence the head height bug. In my re-write, I fixed the situations with new block types to keep the MM mechanics. Of course, I did the changes only to fix the bugs and not change the game play.

Right, MS altered the left movement collision intentionally to allow for certain situations, but side-effects were created as a result of the modification, which were then mostly avoided. Your solution with new block types works very well!

Link to comment
Share on other sites

A big post of z80 code 

The reason for the left right anomaly is simply caused by poor code layout as done by Matthew.

When setting up movement code - it is normal to mirror the code for left and right. This simple procedure allows quick and accurate visual comparisons.

Here the first lot of code is the layout of checking left and right movement when possibly on a ramp

NOTE this has unused opcodes and does not mirror left and right
Expect visual changes - over time on what you can see here. I will probably edit the visual layout.
And correct errors as I see them. 

 

MATTHEWS CODE:-

Used by the routines at 8DD3 and 8ED4. This routine moves Willy left or right if necessary.
8FBC    LD A,($85D0)    Pick up Willy's direction and movement flags from 85D0
8FBF    AND $02            Is Willy moving left or right?
8FC1    RET Z                  Return if not
8FC2    LD A,($85D6)    Pick up the rope status indicator from 85D6
8FC5    DEC A                Is Willy on a rope?
8FC6    BIT 7,A
8FC8    RET Z                 Return if so (Willy's movement along a rope is handled at 935E)
8FC9    LD A,($85D0)    Pick up Willy's direction and movement flags from 85D0
8FCC    AND $01            Is Willy facing right?
8FCE    JP Z,$9042       Jump if so


; LEFT AND RIGHT CODE - DISPLAYED NEXT TO EACH OTHER

Willy is moving right.          ; Willy is moving left.
9042    LD A,($85D2)         ; 8FD1    LD A,($85D2)     Willy's animation frame from 85D2
9045    CP $03                   ; 8FD4    OR A                   Is it 0?
9047    JR Z,$904E            ; 8FD5    JR Z,$8FDC       If so, jump to move Willy's sprite left across a cell boundary
9049    INC A                      ; 8FD7    DEC A                 Change Willy's animation frame at 85D2
904A    LD ($85D2),A         ;8FD8    LD ($85D2),A
904D    RET                        ; 8FDB    RET

Willy's sprite is moving right  ; Willy's sprite is moving left across a cell boundary.
                                                                                       In the comments that follow, (x,y) refers to the coordinates of the top-left
                                                                                       cell currently occupied by Willy's sprite.
904E    LD A,($85D1)         ; 8FDC    LD A,($85D1)     Pick up the airborne status indicator from 85D1
9051    LD BC,$0000         ; 8FDF    LD BC,$0000     Prepare BC for later addition
9054    OR A                      ; 8FE2    CP $00                Is Willy jumping?
9055    JR NZ,$9078        ; 8FE4    JR NZ,$900A      Jump if so
9057    LD HL,($85D3)     ; 8FE6    LD HL,($85D3)   Collect Willy's attribute buffer coordinates from 85D3
                                           ; 8FE9    LD BC,$0000     Prepare BC for later addition (again, redundantly)
905A    LD A,($80DA)       ; 8FEC    LD A,($80DA)    Pick up the direction byte of the ramp definition for the current room from 80DA
905D    DEC A                   ; 8FEF    DEC A                 Now A=0x1F if the ramp goes up to the left, or 0x41 if it goes up to the right
905E    OR $9D                 ; 8FF0    OR $A1
9060    XOR $BF               ; 8FF2    XOR $E0
9062    LD E,A                   ; 8FF4    LD E,A                Point HL at the cell at (x-1,y+1) if the ramp goes up to the left, or at the cell at
                                                                                     (x+1,y+2) if the ramp goes up to the right
9063    LD D,$00              ; 8FF5    LD D,$00
9065    ADD HL,DE           ; 8FF7    ADD HL,DE
9066    LD A,($80C4)       ; 8FF8    LD A,($80C4)    Pick up the attribute byte of the ramp tile for the current room from 80C4
9069    CP (HL)                 ; 8FFB    CP (HL)              Is there a ramp tile in the cell pointed to by HL?
906A    JR NZ,$9078        ; 8FFC    JR NZ,$900A    Jump if not
906C    LD BC,$0020        ; 8FFE    LD BC,$0020    Prepare BC for later addition
906F    LD A,($80DA)       ; 9001    LD A,($80DA)     Pick up the direction byte of the ramp definition for the current room from 80DA
9072    OR A                      ; 9004    OR A                   Does the ramp go up to the right?
9073    JR Z,$9078           ; 9005    JR NZ,$900A     Jump if so
9075    LD BC,$FFE0        ; 9007    LD BC,$FFE0      BC=-32 (the ramp goes up to the left)
9078    LD HL,($85D3)     ; 900A    LD HL,($85D3)   Collect Willy's attribute buffer coordinates from 85D3

; check extremes far right    ; and far left                  - jump room
907B    ADD HL,BC           ;
907C    INC HL                  ;
907D    INC HL                  ;
907E    LD A,L                   ; 900D    LD A,L                 Is Willy's screen x-coordinate 0 (on the far left)?
907F    AND $1F               ; 900E    AND $1F
9081    JP Z,$949E          ; 9010    JP Z,$948A          If so, move Willy into the room to the left;

9084    LD DE,$0020      ;
9087    LD A,($80B2)      ;
                                         ; 9013    ADD HL,BC           Point HL at the cell at (x-1,y+1), or at the cell at (x-1,y) if Willy is on or about to step
                                                                                     onto a ramp that goes up to the left, or at the cell at (x-1,y+2) if Willy is walking down a ramp
                                         ; 9014    DEC HL
                                         ; 9015    LD DE,$0020
908A    ADD HL,DE         ; 9018    ADD HL,DE
                                         ; 9019    LD A,($80B2)        Pick up the attribute byte of the wall tile for the current room from 80B2
908B    CP (HL)               ; 901C    CP (HL)                 Is there a wall tile in the cell pointed to by HL?
908C    RET Z                  ; 901D    RET Z                     Return if so without moving Willy (his path is blocked)
908D    LD A,($85CF)     ; 901E    LD A,($85CF)        Pick up Willy's y-coordinate (Y) from 85CF
9090    SRA C                  ; 9021    SRA C                    Now B=Y (if Willy is neither on nor about to step onto a ramp), or Y+16
                                                                                       (if Willy is walking down a ramp),
                                                                                       or Y-16 (if Willy is on or about to step onto a ramp that goes up to the left)
                                                                                       this will be Willy's new y-coordinate
9092    ADD A,C              ; 9023    ADD A,C
9093    LD B,A                 ; 9024    LD B,A
9094    AND $0F             ; 9025    AND $0F               Is Willy at a point in a jump (left) where his sprite occupies three rows of cells?
9096    JR Z,$90A1         ; 9027    JR Z,$9032           Jump if not (Willy's sprite is cell-aligned)

9098    LD A,($80B2)     ; 9029    LD A,($80B2)        Pick up the attribute byte of the wall tile for the current room from 80B2
909B    ADD HL,DE         ; 902C    ADD HL,DE           Point HL at the cell at (x-1,y+2)
909C    CP (HL)               ; 902D    CP (HL)                 Is there a wall tile there?
909D    RET Z                  ; 902E    RET Z                     Return if so without moving Willy (his path is blocked)
909E    OR A                    ; 902F    OR A                       Point HL at the cell at (x-1,y+1)
909F    SBC HL,DE          ; 9030    SBC HL,DE
90A1    LD A,($80B2)      ;
90A4    OR A                   ; 9032    OR A                        Point HL at the cell at (x-1,y), or at the cell at (x-1,y-1) if Willy is on or about
                                                                                        to step onto a ramp that goes up to the left, or at the cell at (x-1,y+1) if Willy
                                                                                        is walking down a ramp
90A5    SBC HL,DE         ; 9033    SBC HL,DE
90A7    CP (HL)              ;
90A8    RET Z                 ;
90A9    DEC HL              ;
90AA    LD ($85D3),HL ; 9035    LD ($85D3),HL        Save Willy's new attribute buffer coordinates (in HL) at 85D3
90AD    XOR A 
90AE    LD ($85D2),A   ;
90B1    LD A,B               ; 9038    LD A,B                       Save Willy's new y-coordinate at 85CF                 ;
90B2    LD ($85CF),A  ; 9039    LD ($85CF),A
90B5    RET                  ; 903C    LD A,$03                   Change Willy's animation frame at 85D2 from 0 to 3
                                      ; 903E    LD ($85D2),A
                                      ; 9041    RET


;=============================================

The above code laid out with symatry - NOTE the bug can be inserted by just removing the head check.

Here I relay out the code with symetry


Used by the routines at 8DD3 and 8ED4. This routine moves Willy left or right if necessary.
8FC2:

        LD A,($85D6)    Pick up the rope status indicator from 85D6
        DEC A                Is Willy on a rope?
        RET m                Return if so (Willy's movement along a rope is handled at 935E)
        LD A,($85D0)    Pick up Willy's direction and movement flags from 85D0
        bit 1,a                  Is Willy moving left or right?
        RET Z                  Return if not
        bit 0,a                  Is Willy facing right?
;set up some data for later
        LD A,($85D2)     Pick up Willy's animation frame from 85D2
       LD BC,$0000       set no displacement in bc
        JP Z,rampR         Jump if facing right
Code would drop through to rampL

Willy is moving right.   ; Willy is moving left.
rampR:                          ;rampL  

        CP $03                           OR A                      Is it 0?
        JR Z,right              ;         JR Z,left                If so, jump to move Willy's sprite left across a cell boundary
        INC A                    ;         DEC A                   Decrement Willy's animation frame at 85D2
        LD ($85D2),A       ;         LD ($85D2),A
        RET                       ;         RET


Willy's sprite is moving right  ; Willy's sprite is moving left across a cell boundary.
                                                                              In the comments that follow, (x,y) refers to the
                                                                              coordinates of the top-left cell currently occupied by Willy's sprite.
right:                             ; left

       LD A,($85D1)                   LD A,($85D1)        Pick up the airborne status indicator from 85D1
        OR A                     ;         OR A                       Is Willy jumping?
        JR NZ,nrampR     ;         JR NZ,nrampL       Jump if so - NO RAMP ADJUSTMENT
        LD HL,($85D3)    ;         LD HL,($85D3)       Collect Willy's attribute buffer coordinates from 85D3

        LD A,($80DA)      ;         LD A,($80DA)        Pick up the direction byte of the ramp definition for the current room from 80DA
        DEC A                  ;         DEC A                     Now A=0x1F if the ramp goes up to the left, or 0x41 if it goes up to the right
        OR $9D                ;         OR $A1
        XOR $BF              ;         XOR $E0
        LD E,A                  ;         LD E,A                    Point HL at the cell at (x-1,y+1) if the ramp goes up to the left, or at the cell at (x+1,y+2)
                                                                              if the ramp goes up to the right
        LD D,$00             ;         LD D,$00
        ADD HL,DE          ;         ADD HL,DE

; is the ramp undefoot ?
        LD A,($80C4)      ;         LD A,($80C4)        Pick up the attribute byte of the ramp tile for the current room from 80C4
        CP (HL)                ;         CP (HL)                  Is there a ramp tile in the cell pointed to by HL?
        JR NZ,nrampR     ;         JR NZ,nrampL       Jump if not
; set bc for ramp downwards
        LD BC,$0020      ;         LD BC,$0020         Prepare BC for later addition
        LD A,($80DA)     ;         LD A,($80DA)        Pick up the direction byte of the ramp definition for the current room from 80DA
        OR A                    ;         OR A                       Does the ramp go up to the right?
        JR Z,nrampR       ;         JR NZ,nrampL       Jump if so
; set bc for ramp upwards
        LD BC,$FFE0      ;         LD BC,$FFE0         BC=-32 (the ramp goes up to the left)

; before going any further check for going off screen
nrampR:                      ;nrampL:

LD HL,($85D3)           ;            LD HL,($85D3)   Collect Willy's attribute buffer coordinates from 85D3
; position adjust
        INC HL                ;
        INC HL                ;
        LD A,L                 ;         LD A,L                     Is Willy's screen x-coordinate 0 (on the far left)?
        AND $1F              ;         AND $1F
        JP Z,$949E         ;         JP Z,$948A           If so, move Willy into the room to the left;
; the above jumped room at the left/right edge
; adjust position if on a ramp - i.e move up/down - note bc=0 if not on a ramp
    add hl,bc                 ;         ADD HL,BC            this is the ramp adjustment
; re align the checking for walls
                                    ;         DEC HL
        ld de,$0020        ;         LD DE,$0020        Displacement for the tile below
        ld a,($80b2)       ;         LD A,($80B2)        Pick up the attribute byte of the wall tile for the current room from 80B2
         LD B,A               ;         LD B,A                    save wall tile value in b
; head check  - to implement bug - remove the check - can do either left or right - perhaps both
        CP (HL)              ;         CP (HL)                   Is there a wall tile in the cell pointed to by HL?
        RET Z                 ;         RET Z                      Return if so without moving Willy (his path is blocked)
; BODY CHECK
        ADD HL,DE        ;         ADD HL,DE
        CP (HL)              ;         CP (HL)
        RET Z                 ;         RET Z
;calc new y position
        LD A,($85CF)    ;         LD A,($85CF)        Pick up Willy's y-coordinate (Y) from 85CF
        SRA C                ;         SRA C                     Now B=Y (if Willy is neither on nor about to step onto a ramp), or Y+16
                                                                            (if Willy is walking down a ramp), or Y-16 (if Willy is on or about to step onto a ramp
                                                                            that goes up to the left); this will be Willy's new y-coordinate
        ADD A,C            ;         ADD A,C
        LD c,A               ;         LD c,A
; now check if cell aligned
        AND $0F           ;         AND $0F                Is Willy at a point in a jump (left) where his sprite occupies three rows of cells?
        JR Z,ramp3R     ;         JR Z,ramp3L         Jump if not (Willy's sprite is cell-aligned)

; if not aligned check 3rd tile
         LD A,B              ;         LD A,B
        ADD HL,DE       ;         ADD HL,DE            Point HL at the cell at (x-1,y+2)
        CP (HL)             ;         CP (HL)                  Is there a wall tile there?
        RET Z                ;         RET Z                     Return if so without moving Willy (his path is blocked)
        OR A                 ;         OR A                       Point HL at the cell at (x-1,y+1)
        SBC HL,DE       ;         SBC HL,DE             restore back to position before 3rd tile was checked

; adjust position back to level with the top tile
ramp3R:                   ;ramp3L:

      OR A                   ;         OR A
      SBC HL,DE         ;         SBC HL,DE
                                 ;
; and re REALIGN for top left
        DEC HL             ;
; save data and exit
        LD ($85D3),HL ;         LD ($85D3),HL       Save Willy's new attribute buffer coordinates (in HL) at 85D3
        ld a,c                 ;         LD A,c                     Get Willy's new y-coordinate
        LD ($85CF),A   ;         LD ($85CF),A          Save Willy's new y-coordinate at 85CF
        xor a                 ;         LD A,$03                  Change Willy's animation frame at 85D2 from 0 to 3
    ld ($85d2),a         ;         LD ($85D2),A
    RET                       ;         RET

;============================================== 
The Feature that is displayed in the movement code.
When it was implemented it allowed a feature and that feature was used. 
It is similar to the pause bug, attic arrow bug, missing and uncollectable objects etc

Whilst I think my code is correct -  if I notice errors - then I will correct them. The purpose of the code is to show code being laid out as similar for both directions.

                                 ;
 

Edited by Norman Sword
Improving layout - tabs do not translate.
Link to comment
Share on other sites

  • 3 months later...

This is a really good write-up - Wish I'd seen this before I went through the pain of working it out for myself. 

I took a slightly different approach that feels 100% authentic while keeping Willy's coordinate centre within the frame. The one problem I encountered was jumping diagonally through a 2-cell gap next to a wall - e.g. out of the portal and to the right on Kong Beast. If the Y overshot the gap when jumping, the X head check would detect the block above and prevent Willy from seeing the gap. Fixed it with some edge case code, but I would have liked a tidier solution. Didn't help that I'm using floating point.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.