Jump to content
Jet Set Willy & Manic Miner Community

MM/JSW disassemblies: 20160511


SkoolKid

Recommended Posts

Okay, perhaps it should read "From F+1 to F+32", as the table isn't used to calculate an offset when L=0.

 

But this implies that the first pair of offsets at 8300/8380 are not used, and that the pair at 8356/83D6 are used. You see my confusion?

 

I need to (re)examine the code closely at some point to figure out what's going on.

Link to comment
Share on other sites

But this implies that the first pair of offsets at 8300/8380 are not used, and that the pair at 8356/83D6 are used. You see my confusion?

 

I need to (re)examine the code closely at some point to figure out what's going on.

 

Yes, I've thought about it, and in terms of how the algorithm works that points to the correct place in the table, you're right.

 

My initial reading of your explanatory introduction was that the entries at #8355 and #83D5 were unused - but that is because I was thinking of the entries at #8300 and #8380 as being the first entries in their respective half of the table, whereas they are in fact the zeroeth entries.

 

I think the wording in brackets gave rise to my confusion: "(one for each segment of rope)".  Perhaps it could be amended to clarify the matter?  Something along the lines of "(one for each segment of rope, apart from the 0th segment which is drawn at the top of the screen in the cell-column determined by the second byte* of the entity specification, and which does not have any 'offset' applied to its coordinates)"

 

[* By which I mean Byte 1 of the entity specification for the room in which the rope is being drawn, given that the first byte which specifies that this is a rope is Byte 0!]

Edited by IRF
Link to comment
Share on other sites

The way the rope-drawing loop works is that it draws a segment (initially the 0th segment), then increments the coordinates of the segment (using the table at #8300) in preparation for the next segment being drawn during the next pass through the rope-drawing loop.

 

And at the end of the loop, the check "Have we drawn every segment of the rope yet?" is made before the Segment Counter is incremented.

 

Therefore 33 segments (pixels) are drawn in total, for each value of the Rope Animation Frame Index, although the Rope Animation Table is only looked up 32 times in the process.

Edited by IRF
Link to comment
Share on other sites

More suggestions:-

 

'Display the Title Screen and play the theme tune'

http://skoolkid.github.io/jetsetwilly/asm/87CA.html

 

I think it's worth highlighting, in the adjacent sidebar, the role of the AND 01 command at #8872 - it selects which of each pair of Triangle UDGs to draw, depending on whether the current value of the attribute file address being considered is odd or even.  Thus, two adjacent attribute bytes of the same value will select graphic bytes starting at #8431 and #8439 respectively, or else #8441 and #8449.

 

Also, the jump at #8864 is quite cunning, as it ensures that all four Triangle UDGs can be drawn in 'Cyan Ink on Green Paper' attributes:

- attribute bytes set to 'Green Ink on Cyan Paper' bypass the instruction at #886A, before their attributes are swapped round at #886E-8870;

- in contrast, when 'Cyan Ink on Green Paper' attribute bytes are considered, the instruction at #886A is executed but #886E-8870 is bypassed.

 

'The game has just loaded'

http://skoolkid.github.io/jetsetwilly/asm/8400.html

 

The entry at #840C to 8414 - it would be helpful if it said "Set HL=8500 in a roundabout way, in preparation for the [redundant] instructions at #8415 to #841E".  i.e. you have already highlighted the redundant nature of the latter chunk of code, but not the former.

Edited by IRF
Link to comment
Share on other sites

The way the rope-drawing loop works is that it draws a segment (initially the 0th segment), then increments the coordinates of the segment (using the table at #8300) in preparation for the next segment being drawn during the next pass through the rope-drawing loop.

 

And at the end of the loop, the check "Have we drawn every segment of the rope yet?" is made before the Segment Counter is incremented.

 

Therefore 33 segments (pixels) are drawn in total, for each value of the Rope Animation Frame Index, although the Rope Animation Table is only looked up 32 times in the process.

Actually, I think that the table is looked up on the 33rd pass through the rope-drawing loop, but the program doesn't actually implement anything with those values, other than 'behind the scenes' updating of a couple of variables, which aren't then used for anything (because immediately afterwards the relative jump at #9356 is triggered, before another pixel is drawn), and the two variables are re-initialised when the rope is redrawn in the next time-frame anyway.

 

So it's probably safe enough to describe the bytes at #8356-83D6 as 'spare bytes'!

 

EDIT: Playing Devil's Advocate, I think the worst that might happen, if the spare bytes were reused for other purposes, is that:

 

If a high value (such as #FF) were to occupy #8356, then the DJNZ loop at #933D / #934E might take a while to bring the B register back down to zero, and that might cause a brief (~1 millisecond?) delay in the game, at the point when the rope reaches its point of maximum deviation from the vertical?

 

Meanwhile, if an odd value were to be inserted at #83D6, then this could, theoretically, cause a similar effect to the Arrow that triggers the Attic Bug, with the 'Draw the Rope' routine overshooting the 'Screen Buffer Address Lookup Table', causing an address beyond the Screen Buffer to be overwritten.

 

However, this would only have an impact on the game if the routine subsequently attempted to insert the Rope Segment Graphic Byte at such a misplaced address. And that won't happen, again because the relative jump at #9353 is triggered straight away, before the routine gets a chance to draw any more Rope segments!

 

[Caveat: if a modified game had a Rope longer than 32 segments, without the maximum swing being reduced accordingly, then the above is something to be mindful of!!]

Edited by IRF
Link to comment
Share on other sites

I think I have an answer to the conundrum posed by this speculative comment in the 'Through the Wall' entry of the Bugs section of the Manic Miner disassembly:

 

Perhaps the assumption in this code is that if there is a nasty tile below Willy's sprite in step 16, then he will be killed by the nasty before reaching step 17; however, in this particular case Willy's x-coordinate decreases by one during step 16 (as he transitions from animation frame 0 to frame 3), which moves him out of the nasty's range.

 

I think the reason why a positive response to the check for Fire cells under Willy, causes the jumps to #8BDD [in MM] or #8ED4 [in JSW] to be bypassed, is to stop Willy from bouncing sideways off Fire cells as he crosses a cell boundary.

 

If this wasn't the case - i.e. if the relative jumps at #8B29 and #8B3D (in Manic Miner) or #8E4D and #8E54 (in JSW) weren't present in the code - then Willy would be able to perform the quirky manoeuvres seen in the attached rzx recordings! (which are based on modified files with the above bytes NOPped out).

 

(Note that in the Manic Miner recording, Willy actually jumps briefly off the top of the screen!)

MM Fire Bounce.rzx

JSW Fire Bounce 1.rzx

JSW Fire Bounce 2.rzx

Edited by IRF
Link to comment
Share on other sites

The same 'Through the Wall' phenomenon also allows Willy to fall through any standonable block, including Crumbly cells.

 

This fact highlights an asymmetry in the Manic Miner code.  If Willy jumps rightwards over a Fire cell that is adjacent to a Crumbly cell beyond it, then he falls through the Crumbly cell without causing it to crumble.  Whereas if Willy jumps leftwards over a Fire cell that is adjacent to a Crumbly cell beyond it, then he falls through the Crumbly cell, but one pixel row of that Crumbly cell crumbles away.

 

The difference arises because in the code at #8B10-8B58, the checks for (in turn) Crumbly cells and Fire cells under the left of Willy's sprite take place before the checks for (in turn) Crumbly cells and Fire cells under the right of Willy's sprite.

 

See attached rzx recording.

Fire Crumble Jump.rzx

Edited by IRF
Link to comment
Share on other sites

More pedantry from me!

 

In the entry for Vertical Guardians in the 'Entity Buffer' section:

 

http://skoolkid.github.io/jetsetwilly/asm/8100.html

 

Bit 7 of Byte 0 of the vertical guardian definition is described as 'unused'.  I don't believe that is technically the case; it just so happens that in Original JSW it is always reset to 0 at the start of the game.

 

I believe that the value of Bit 7 of Byte 0 (for a vertical guardian' buffer definition entry) actually cycles between values of 1 and 0, every four time-frames [or every eight time-frames, if Bit 4 of Byte 0 is reset], as a result of the regular implementation of the AND A, $20 command at #918E.

 

However, the superimposing of the Animation Frame Mask and Base Sprite Index, by the instructions at #9211-9219, selectively filters the animation frames for all the vertical guardians in Original JSW, in such a way that only four frames of animation are ever displayed.  So the changes to the value of Bit 7 of Byte 0 are only occurring 'behind the scenes', and don't affect what is displayed on the screen.

 

But it is quite possible to have vertical guardians with eight frames of animation, by selecting appropriate values for the Animation Frame Mask (4-7) and Base Sprite Index (0-3), in which case the toggling of Bit 7 of Byte 0 is manifested in the change of guardian sprite that you would see on the screen.

 

N.B. This doesn't work in the same way as for horizontal guardians, for which there are (potentially) four frames when the guardian is moving left, and four different ones when it is moving right.  The 'Move a vertical guardian' code works differently to the 'Move a horizontal guardian' code.  For an eight-frame vertical guardian, all eight frames are toggled through in turn (Frame 0 through to Frame 7, then back to Frame 0), regardless of whether the guardian is moving up or down!

 

EDIT: This could form the basis of fixing the 'not very graceful' vertical guardian in 'On a Branch over the Drive', as follows:

 

http://skoolkid.github.io/jetsetwilly/reference/facts.html#quadridirectionalGuardian

 

(In preparation for the below, shift the 'Flying Saucer' sprites from #B980-B9FF to a spare place in the sprite data, such as #A680-A6FF, and redirect Guardian Class 0E to the appropriate place by changing the value of #A075 from $B9 to $A6.)

 

- Place a laterally inverted version of the sprite currently occupying #B900-B91F, into the addresses at #B980-B99F, by swapping pairs of graphic bytes (e.g. the first two entries for the original sprite are $3C $00, so insert $00 $3C for the first two graphic bytes of the laterally inverted sprite);

- Copy the sprite at #B960-B97F into #B9A0-B9BF;

- Copy the sprite at #B940-B95F into #B9C0-B9DF;

- Copy the sprite at #B920-B93F into #B9E0-B9FF;

- Change the Animation Frame Mask for Guardian 3E from 03 to 07 (by changing the value of A1F1 from $65 to $E5).

 

I haven't tried it yet, but hopefully the resultant guardian will be much more 'graceful'!

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.