Jump to content
Jet Set Willy & Manic Miner Community

MM/JSW disassemblies: 20160511


SkoolKid

Recommended Posts

Richard,

 

Sorry to be a pain, but I don't think your latest iteration of the 'Through the Wall' entry in your Manic Miner disassembly is quite accurate yet:

 

http://skoolkit.ca/disassemblies/manic_miner/reference/bugs.html#throughTheWall

 

"This happens because the section of code at 35600 - which is executed during jumping animation step 16, after Willy's y-coordinate has been updated so that he's exactly one cell height above the place he jumped from, but before his x-coordinate has been updated - checks whether there are any nasty tiles in the cells below Willy's sprite. If there are (as is the case here), the code jumps forward to 35665, which makes Willy proceed to the next jumping animation step (as if the bricks were not there), instead of landing on the bricks."

 

Regarding the text highlighted in bold, if you look at the illustration for Jumping Animation Step 16, you will see that there aren't any Fire cells under Willy's sprite (there are actually two 'brick' Earth cells).

 

Part of the confusion relates to the text highlighted in the quote above in italics.  In fact, if you consider a jump from start to finish, it's actually the other way round - Willy's x-coordinate is updated before his sprite is drawn to the screen, but his y-coordinate is updated after his sprite is drawn.  (More comments on that later*.)

 

Now, during a jump the check for Fire cells (to determine whether to jump forward to 35665) can only be determined when the Jumping Animation Counter has reached a value of 16 (or 13).  However, this takes place after the Jumping Animation Counter has been incremented by the command at 36355.  But the Jumping Animation Counter is used to calculate Willy's current y-coordinate at 36330 i.e. before the Jumping Animation Counter is incremented.

 

As a result, as far as your illustrations are concerned, the pertinent check for Fire cells is taking place at Step 15.  At that point, Willy's 'physical presence' is cell-row-aligned, with his back foot directly above the left-most Fire cell (and his front foot above the adjacent 'brick' Earth cell).  However, because the y-coordinate of his sprite hasn't been updated yet, there appears to be a vertical gap (of three pixels) between Willy's back foot and the Fire cell.

 

In contrast, at the point in time represented by the illustration for Step 16, Willy's 'physical presence' is four pixels lower than where his sprite is drawn, so he is not cell-row-aligned.  By now, the Jumping Animation Counter has reached a value of 17, so the checks for Fire cells beneath him are not reached (but in any case he has moved past the cell-column boundary, so he is no longer straddling a Fire cell).

 

 

* As for the order in which Willy's x- and y- coordinates are updated, this is counter-intuitive because the code that progresses Willy's y-coordinate in a jump is at Move Willy (1) i.e. before the code at Move Willy (3), which moves him sideways and causes him to pass from one cell-column to the next.

 

[The 'Draw Willy' routine of course comes after the 'Move Willy' routine in the Main Loop.]

 

However, because the check for Jump keys (which initiates the jumping sequence) is in Move Willy (2), each incrementation of the jump is drawn with the adjustment of the y-coordinate lagging behind that of the x-coordinate. i.e. What you see on the screen is a 'snapshot' taken after Willy's x-coordinate has been moved on, but before his y-coordinate is updated.

 

You can see evidence of this at the end of the jump.  It's the reason why he appears to drop from 4 pixels up, to his final landing position, without his frame of animation being updated (it's 'left-facing frame 2' in both cases; see your illustrations for Jumping Animation Step 17 and 18 - both of which actually represent Jumping Animation Counter values of 18, for the reason discussed earlier).  In the last time-frame of his jump, his sprite is drawn before his y-coordinate is updated.  Then the next time the program passes through the Main Loop, his sprite's position is updated to reflect his true y-coordinate.

 

(I haven't checked this yet, but if either a 'Left' or 'Right' movement key were kept depressed throughout the jump, then the illustration for 'Step 18' may not be as shown - he would either have moved on to 'left-facing frame 1', or else turned around to be in 'right-facing frame 2'.)

 

You can also witness the 'lag' of the y-coordinate behind the x-coordinate if you study the very beginning of the jump, when Willy appears to walk forward by one frame of animation before starting to ascend.  Which doesn't make sense if he's jumping from a position at the edge of a precipice - his sprite appears to walk off the edge (with no supporting structure beneath him) before the jump commences.  But again, it's because in the first time-frame of his jump, his x-coordinate is updated before his sprite is drawn, but his y-coordinate isn't.

 

************

 

Apologies if all that was a bit long-winded, but if I were to try and summarise it:

 

The current illustrations in the MM disassembly represent 'snapshots' taken before Willy's vertical pixel coordinate has been updated, and before the Jumping Animation Counter has been incremented.  Unlike your previous set of illustrations, the latest ones reflect exactly what is seen on the screen.  However, the previous snapshots showed where Willy is located immediately prior to the check for Fire cells underneath him (and the current value of the Jumping Animation Counter at that point), and so they did actually provide a better representation of what is occurring with this quirky aspect of the game engine!

Edited by IRF
Link to comment
Share on other sites

Richard,

 

Sorry to be a pain, but I don't think your latest iteration of the 'Through the Wall' entry in your Manic Miner disassembly is quite accurate yet:

 

[snip]

 

Phew! :)

 

I've just read the 'Through the wall' description a few times to get it straight in my head, and I must admit I'm not seeing the discrepancy between the text and the pictures.

 

When I say that there is a nasty tile below Willy's sprite in step 16, what I mean is that when the nasty tile check is made at the point when the jumping animation counter is 16, Willy's x-coordinate has not yet been updated from what it was in step 15 - at which point there is a nasty tile below Willy's sprite. (His x-coordinate is updated before he's drawn during step 16, though.)

 

Perhaps the wording doesn't make that clear enough. Would it help if I stated the actual x- and y-coordinate values when the nasty tile check is made?

Link to comment
Share on other sites

Hmmm, I wonder are we at cross purposes?

 

I just think that stating "as is the case here" (i.e. there's a nasty below Willy's sprite in step 16) doesn't tally with what one can see in the diagram for Step 16.

 

The illustration labelled 'Step 16' appears to show that Willy has cleared the Fire cell and is straddling two Earth cells, on top of those Earth cells.

 

Whereas in fact, by that point he has sunk four pixels down into the Earth cells (and subsequently drops to the floor beneath). But his sprite's vertical position hasn't been updated to reflect that.

 

At the precise point when a Fire cell is detected underneath Willy, what you see on the screen is shown by your diagram labelled 'Step 15'. Since the Jumping Animation Counter has reached a value of 16 at the point when the Fire cell is detected, labelling that diagram as 'Step 15' seems to me to add to the confusion!

 

N.B. It IS actually possible for him to land in the position shown in the 'Step 16' diagram, if the starting point of his jump is one frame of animation further forward - in that case, in the penultimate time-frame before he lands, he is drawn in exactly the same animation frame (left-facing frame 3) but three pixels above the two Earth cells - again, the update of his y-coordinate lags BEHIND the update of his x-coordinate. So the effective check* for Earth cells underneath Willy interrupts his descent, and his sprite drops straight down onto the bricks without progressing laterally. His jump has effectively ended when he is still displayed a few pixels up; his 'drawn' y-coordinate just has to catch up with his 'internally-set' y-coordinate.

 

(* The code actually checks for Air cells under the left and right halves of his sprite, in turn, and interrupts his fall if either check receives a negative response - but both those checks are bypassed if there is a Fire cell beneath either half of him.)

Edited by IRF
Link to comment
Share on other sites

I think we're in agreement that, during a jump, Willy's true coordinates (as stored internally) are not in sync with his apparent position (as shown on the screen), at the point when the check for fire cells underneath him is made.

 

Where we seem to differ is that I believe the updates to Willy's x-coordinate are ahead of updates to his y-coordinate, whereas you consider his y-coordinate is updated first.

 

It's kind of a 'chicken and egg' scenario, but if you consider that the start of the jump is instigated by the command at 36766, and then if you follow the subsequent code in the order that the program arrives at it, it should hopefully be clear that the x-coordinate is adjusted first, then Willy is drawn, and then his y-coordinate is updated.

Edited by IRF
Link to comment
Share on other sites

Maybe the best way to illustrate what's going on would be to have two sets of diagrams:

 

(1) your previous set, with an explanation that the Step 16 diagram shows where Willy is truly located at the point in time when the check for fire cells is made;

 

(2) a second set, with an explanation that these illustrate what is displayed on the screen at each of the latter time-frames of the jump. This would be what's currently in the disassembly, except that the Step Numbers are out by one. Step 15 should show Willy in left-facing frame 1, 6 pixels above the fire block, then Step 16 is the one labelled as Step 15 in the disassembly, etc. Step 19 just represents Willy's on-screen sprite vertically adjusted to reflect the reality, at the point that the Step 18 check (which brings his jump to an end) was made.

Edited by IRF
Link to comment
Share on other sites

Okay Richard, I've looked again and I'll take back my suggestion that your numbers are out of sync.  Having paused the game mid-jump and PEEKED at the value of the Jumping Animation Counter, the values do tally with what is seen on the screen, as shown by your illustrations.  Specifically, at the very start of the jump when Willy's sprite moves forward one frame of animation before he starts to move vertically upwards, the Jumping Animation Counter is still set to zero.  So there is a 'Step 0' in every jump (I was previously considering that to be Step 1).

 

To keep things simple, perhaps you could just include your earlier 'Step 16' illustration, with a note to the effect that this isn't actually seen on the screen during the jump, but it demonstrates Willy's 'internally-stored' location at the precise point when the check for Fire cells is made:-

 

His vertical position has moved down so that he is exactly one cell above his starting position, and only occupying two cell-rows, while his horizontal position hasn't yet been adjusted to take him across the cell-column boundary and his frame of animation hasn't yet been incremented from left-facing 0 to left-facing 3.

 

As for whether x is incremented before or after y, this really is a classic case of 'chicken and egg'.  Going from one on-screen 'snapshot' to the next, y is incremented first.  But considering the point when the Jump key is pressed as the 'origin', x is incremented before y!

Edited by IRF
Link to comment
Share on other sites

Regarding vertical guardians, perhaps it is worth an entry in the Trivia section that they can extend beyond their upper permitted bounds (i.e. the highest set value for their y-coordinate, corresponding to the lowest extent of their traverse down the screen).

This can occur if the length of their range (the difference between their upper and lower bounds) isn't exactly divisible by the 'speed' of the guardian (i.e. the vertical increment of the guardian in each time frame). It is more common, therefore, with fast vertical guardians.

However, it doesn't happen at the lower extent of their bounds (highest position on the screen), because of the code at 37288-37293 (#91A8-91AD), which ensure that if a vertical guardian 'overshoots' at the top of its range on the screen, its y-coordinate is reset to the lowest permitted value.

 

EDIT: Presumably it would be relatively simple to insert a similar couple of commands (with a relative jump to bypass them, as appropriate) which could ensure that vertical guardians don't overshoot their permitted range at the lowest point of their descent down the screen (highest value of y-coordinate).  Simple that is, except for the fact that the 'Move the guardians' routine is located at a tight spot in the code, and so consolidating to achieve the necessary space to allow for this would be rather time-consuming.

 

FURTHER EDIT: This 'bug' is actually 'fixed' in Manic Miner, as the code for moving vertical guardians doesn't actually update the guardian's y-coordinate to a value outside of its permitted range, if it detects that it has been moved beyond its range.

Conversely, the JSW code for drawing vertical guardians, provides the basis for a fix to the bug in MM whereby the colour of the vertical Skylabs 'bleeds' into the platforms upon which they crash.

Edited by IRF
Link to comment
Share on other sites

Typo alert Richard:

 

Willy's rope status (on or off) seems to be determined by Bit 0 of Byte 11 of the rope definition, not Bit 7 of Byte 11 as stated in the 'Entity Buffer' section of your disassembly:

 

http://skoolkit.ca/disassemblies/jet_set_willy/buffers/gbuffer.html

 

http://skoolkit.ca/disassemblies/jet_set_willy/asm/37310.html#37590

 

By the way, I hope you don't mind these occasional comments and suggestions? Your disassemblies are fantastic resources, and hugely helpful in gaining an understanding of the code. If I come across as pedantic it's only because I believe that 'tweaks' such as this could help readers who follow after me to gain a similar level of understanding!

Edited by IRF
Link to comment
Share on other sites

By the way, I hope you don't mind these occasional comments and suggestions? Your disassemblies are fantastic resources, and hugely helpful in gaining an understanding of the code. If I come across as pedantic it's only because I believe that 'tweaks' such as this could help readers who follow after me to gain a similar level of understanding!

 

No, not at all - keep them coming! I want the disassemblies to be as accurate and comprehensive as possible, and I'm always happy to receive new trivia suggestions and bug reports.

Link to comment
Share on other sites

I notice that in his disassembly, Richard has managed to identify the precise cause of the bug (or quirky feature?) whereby a Fire cell at the top of the screen can kill Willy if he drops off the bottom directly underneath:

 

http://skoolkit.ca/disassemblies/jet_set_willy/reference/bugs.html#longDistanceNasties

 

I had got as far as surmising that it's something to do with the check for Fire cells, underneath the 2x2 square of cells occupied by Willy, somehow wrapping around from the bottom of the screen to the top.

 

However, the 'missing link' in terms of the explanation is that the Attribute Buffer for the occupied room (i.e. occupied by guardians, items and Willy) at #5C00, is immediately followed in the code by the Attribute Buffer for the empty room (i.e. the room without guardians, items or Willy - but, crucially, WITH the Fire cells) at #5E00.

 

Whilst it can be quite a useful bug in terms of preventing Infinite Death Scenarios, I wonder if hypothetically this could be fixed by pointing the check for Fire cells to the Empty Room Attribute Buffer at #5E00 instead of the Empty Room Screen Buffer Occupied Room Attribute Buffer at #5C00?

 

Any thoughts?

 

 

To answer my own question, I think it could just cause more problems than it solves!

 

If the check for Fire cells was applied to the Empty Room Attribute Buffer, then it should still correctly pick up Fire cells within the room, but if Willy's sprite occupied the bottom two cell-rows (i.e. as he's falling off the bottom of the screen), then the check for Fire cells underneath him will probably wrap beyond the bottom of the screen to the Screen Buffer (for an occupied room) at #6000 (which contains the pixel patterns of all the room elements and all the entities within the room).

 

Therefore the check for Fire cells will probably pick up the top pixel-row of the cell that lies in the uppermost cell-row directly above Willy.  So if that cell happens to contain something (not necessarily a Fire cell!) whose first graphics byte (i.e. top row of pixels) matches the attribute byte for the Fire cells in that room, then the program will interpret that as if Willy has landed on a Fire cell, and kill him!

 

Any room element (Earth/Water/Ramp cells) at the top of the screen could potentially cause such a match, giving rise to a 'misdiagnosis' that Willy has stood on a Fire cell!

 

It could even occur if an (uncollected) item lies at the top of the screen, whose first pixel-row matches the colour-attribute of the Fire cells.  (N.B. such a match does actually exist in Tree Root, although the items aren't at the top of that screen.)

 

Or if a horizontal guardian happened to pass along the top of the screen, through the pertinent cell, such that the top pixel pattern of the portion of the guardian that instantaneously occupies that cell, matches the Fire cells' colour-attribute at the precise moment just before Willy drops off the bottom of the screen, then it could also trigger a positive check for a Fire cell 'beneath' him and kill him!

 

I'll take back the elements of my musings that are highlighted in red above - prior to the check for Fire cells in the Main Loop, the Occupied Room Screen Buffer will have been refreshed, and so the data in the range #6000-#601F [the top pixel-row of the playing area] will NOT, at that stage, contain any graphic bytes associated with guardians or items - which aren't drawn until later on during the current pass through the Main Loop.

 

However, for the record I still believe it would be possible for the top pixel-row of Water, Earth, Ramp or Conveyor cells, located in the top cell-row, to potentially match the attribute byte of Fire cells and therefore kill Willy in the manner described above - if the sub-routine at #961E were redirected in the way that I suggested (i.e. to check for Fire cells in the Empty Room Screen Buffer, rather than in the Occupied Room Screen Buffer).

 

Furthermore, the room's conveyor animation (if a conveyor were to be present in the top cell-row of the screen, directly above where Willy is trying to drop off the bottom) could also cause the top pixel-row of the conveyor to re-align and thus cause a byte-match with the Fire cell attribute byte - even if the initial (unrotated) conveyor's first graphic byte didn't cause such a match.  The updated conveyor pixel pattern is written to the Empty Room Screen Buffer by the routine at #94F9, so at the next pass through the Main Loop, the 'screen refresh' [copying Empty Room Screen Buffer to Occupied Room Screen Buffer] retains the latest conveyor graphic.

 

(N.B. As far as I can tell, conveyor animation is the only thing in JSW that causes updates to the Empty Room Screen Buffer within a room - apart from 'quirky' spillovers from the Occupied Room Screen Buffer caused by Invalid Arrows and vertically wrapped-around guardians - so-called 'Trails of Havoc'.)

 

***********

 

ANYWAY, there is a simpler way to prevent the 'Long-Distance Nasties' bug from occurring (although there isn't space for it within the main routine without shuffling code): After Willy's pixel y-coordinate is picked up by the command at #960F, simply compare its value with 224 (#E0) and if it is equal to (or greater than?) that, then jump forward in the code to #961C.

 

And as I previously pointed out, it's questionable whether this is a bug that should be fixed, given that it has its uses for game designers in preventing bigger problems (such as avoiding IDS drops off the bottom of screens).

Edited by IRF
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.