Jump to content
Jet Set Willy & Manic Miner Community

Setting a rope's horizontal position by pixel


IRF

Recommended Posts

Please see the attached test file.

 

PREAMBLE: In 'Jet Set Mini', I managed to implement perfectly laterally-inverted ropes, partially by changing the position of the top segment of each rope within its host cell.  (i.e. In original JSW, the top rope segment occupies the leftmost pixel in the defined start-column; whereas in 'Jet Set Mini' the top rope segment occupies the rightmost pixel.)

 

This test file extends that concept further.  I have slightly rewritten the 'Draw the Ropes' routine, so that the precise horizontal pixel-position of the top of each rope in the game may be specified separately. i.e. on a 'rope instance' basis.  The pixel position of the top segment is stored in the highest three bits* of Byte 2 of the Rope Definition (which is copied over, from the second byte of each rope's specification in the room's guardian list, when the 'Room Setup' routine is executed).

 

The value of that three-bit number is then translated into the correct pixel to infill for the top segment, using a similar principle to that which is used in Manic Miner to draw the remaining pixels of air supply at the right-hand end of the air bar (except that I've used the RLC E command here, instead of RRC E, and there is no setting of additional bits during each pass through the DJNZ loop).

 

 

Within the the start-up room (Swimming Pool) in the attached file, there are eight** ropes which are very closely spaced horizontally (only three pixels apart).  I have called this effect a 'Swinging Curtain', as that's what I think it looks like!

 

Note that the game is slowed down somewhat in the room in question, because of the need to perform eight complex rope-drawing operations during each time-frame.

 

 

******

 

* One consequence of this change is that you lose the ability to create an 'Invalid Rope' like the one in the 'Overgrown MegaTree' in 'Jet Set Mini' (the top segment of which is drawn further down the screen than is usually the case, because I assigned an 'invalid' value [greater than #1F] for the x-coordinate of the top segment of rope, in the room's guardian table).  However, that's probably not a great loss - Invalid Ropes can be very 'quirky', especially if they extend down beyond the boundary between the top and bottom half of the playing area, which causes segments to appear in strange places (the one in 'Jet Set Mini' is sufficiently short to prevent this from happening).

 

 

** Note that because there are eight ropes present in the room, it can be quite difficult to dismount the ropes/curtain!  The 'Draw the Ropes' routine usually allows Willy 16 time-frames to elapse, after jumping or falling off a rope, before he can be caught by a rope again.  However, with eight ropes being drawn consecutively in each time-frame, that reduces to two time-frames!  (Although that is not a result of the changes that I made in the attached; it is a curious feature of the JSW game engine, and would be the case in any JSW room with eight ropes.)

Swinging Curtain Test.z80

Edited by IRF
Link to comment
Share on other sites

I've made a minor variation to the previous file - see the attached.  The patch* has been re-written slightly more efficiently, saving three bytes.  And in the test room I've put all eight ropes into adjacent pixels (the top segments are all located within the same cell-column, although they could just as easily have straddled two columns), so the composite whole now resembles a swinging rope ladder.

 

That can be scaled back to achieve a 'fat rope' by having, say, just two ropes sitting adjacent to each other, one pixel apart - which would have the benefit that it doesn't slow the game down to the same extent (as well as only requiring two guardian instances, of course).

 

 

EDIT: *I forgot to say last night: the patch for this and last night's test file is contained in a subroutine at #9718 (which is CALLed from #92AC, near the start of the 'Draw the Ropes' code).

Swinging Ladder Test.z80

Edited by IRF
Link to comment
Share on other sites

Incidentally, aside from the perhaps frivolous 'composite ropes', as seen in the test files above, the ability to set a rope's horizontal position at the individual pixel level could be useful for fine tuning a difficult game, where you want to ensure that a tricky jump onto or off of a rope is just about possible (if the player gets the timing exactly right), without actually becoming impossible!

Edited by IRF
Link to comment
Share on other sites

  • 2 weeks later...

I've re-named this thread to reflect the substantive subject matter. ('Swinging Curtain' was just one example of what can be achieved with this approach.)

 

Here is a short disassembly of the changes made to the original code to implement ropes where the horizontal position is set at the pixel level:

 

Original code (from Skoolkid's disassembly):

 

92A4 LD IY,$8200 Point IY at the first byte of the screen buffer address lookup table at 8200

92A8 LD (IX+$06),$00 Initialise the seventh byte of the rope's buffer to zero; this will count the segments of rope to draw [Note that the Adjacent Ropes patch is in place to prevent overspill of the rope's definition!]

92AC LD A,(IX+$02) Initialise the fourth byte of the rope's buffer; this holds the x-coordinate of the cell in which the segment of rope under consideration will be drawn

92AF LD (IX+$03),A

92B2 LD (IX+$05),$80 Initialise the sixth byte of the rope's buffer to 0x80 (Bit 7 set); the value held here is used to draw the segment of rope under consideration

(N.B. In 'Jet Set Mini', this was changed to LD (IX+$05),$01 which sets Bit 0 instead.)

 

New code:

 

92A4 LD IY, $8200 Point IY at the first byte of the screen buffer address lookup table at 8200

92A8 LD (IX+$06), $00 Initialise the seventh byte of the rope definition in the entity buffer to zero; this will count the segments of rope to draw

92AC CALL $9718 Call a subroutine to initialise the horizontal position of the top segment of rope (by cell-column and by pixel)

92AF NOP x 7 [i could have used some of these NOPs for part of the subroutine, but I decided to keep it all in the same place in the test files, for ease of understanding]

-92B5

 

9718 LD A, (IX+$02) Load up the third byte (Byte 2) of the rope definition to the A register

971B AND $1F Keep only Bits 0-4 (representing the cell-column of the top segment)

971D LD (IX+$03), A Initialise the fourth byte of the rope definition; this holds the x-coordinate of the cell in which the segment of rope under consideration will be drawn

9720 XOR (IX+$02) This bitwise XOR operation leaves the A register holding the pixel-position of the top segment of the rope in Bits 5-7, whilst clearing Bits 0-4 of A

9723 RLCA

9724 RLCA

9725 RLCA The pixel-position of the top segment of rope has been rotated round to occupy Bits 0-2 of the A register; thus A holds a value between 0 and 7

9726 INC A A now holds a value between 1 and 8

9727 LD B, A Copy the value of A into the B register, in preparation for a DJNZ loop later

9728 XOR A The A register is cleared (A=0) and the Carry Flag is reset by this operation

9729 SCF Set the Carry Flag (in light of the previous operation, a CCF operation - complement the Carry Flag - would also work here)

972A RRA Rotate A rightwards - in the first instance, the value of the Carry Flag is rotated in to Bit 7

972B DJNZ $972A The preceding RRA command is performed B number of times, which leaves the A register with one (and only one) set bit

972D LD (IX+$05), A Initialise the sixth byte of the rope definition; the single set bit is used to draw the segment of rope under consideration

9730 RET Return to the rope-drawing routine, to commence the loop (starting at 92B6) which draws each segment in turn

 

With the above in place, if the highest three bits of Byte 2 of a rope's definition hold the value 000, then the top segment of the rope will occupy Bit 7 (the leftmost bit) of the appropriate cell-column (as specified by Bits 0-4 of Byte 2).

If Bits 5-7 of Byte 2 hold the value 111, then the top segment of the rope will be drawn in Bit 0 of its cell-column.

All intermediate values behave as you would expect.

 

And of course, Byte 2 for any guardian is specified on a guardian-instance basis, so only one guardian-class is required to populate a room with ropes that have different pixel-positions.

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.