Jump to content
Jet Set Willy & Manic Miner Community

Free space and code optimisation in "JSW"


jetsetdanny

Recommended Posts

I also noticed that there are apparently random changes to the layouts of the first few rooms!

 

(Oh, and by the way there's a typo in the end-of-game message: "Stike a light, what happened?")

 

I noted that too. :)

 

In particular the 'asterisk' in 'Main Stairway' initially is erm 'in the way' then its not. I also noted that the extra platforms in First Landing were awol then returned. :)

Link to comment
Share on other sites

Yes an increment of IX.

 

The code must also copy the y position.....Which it can do when setting the arrows phase in room set up..

(different from what I have at present... So I will change my own code) 

 

 

If a pair of arrows are defined and they are facing each other and cross on the screen. Then one needs setting as even and the other odd. (x position)

 

Erroneous spelling noted. The assembler code is 540k of ASCII  text. It has become difficult to read and bits and pieces get missed.  

Link to comment
Share on other sites

I've now managed to achieve the shared left-right code for horizontal guardians, including a mid-path bounce (a phenomenon which is best exemplified by the Monks in the room 'Gregorian Chant' in the 'total rewrite of JSW in 48k' project that was uploaded by Norman Sword - 'Gregorian Chant' is a very nicely presented room by the way!).

 

This change used up most (but not all) of the bytes that had been freed up by combining left and right movement into a shared piece of code.

 

 

Starting at #9133 (changes from my initial code are highlighted in bold):

 

      PUSH IX                        ; copy the address of Byte 0 of the guardian definition
      POP HL                         ; to the HL register-pair

 

      LD DE,#E0FF                ; parameters for a

      LD B A,(IX+$06)                ; guardian moving left

      BIT 7,(HL)

      JR Z, left

      LD DE,#2001                 ; parameters for a 

      LD B A,(IX+$07)                ; guardian moving right

 

left:

      LD B,A

 

      LD A,(HL)

      ADD A,D                         ; increment animation-frame of guardian

      BIT 7,(HL)                       ; sets the Zero Flag for a left-moving guardian

      LD (HL),A                        ; update guardian definition Byte 0 with correct animation-frame

      JR Z,carry_okay

      CCF                                 ; Complement the Carry Flag for a right-moving guardian

 

carry_okay:

      JR C,#91B6                     ; not time to update the guardian's x-coordinate; proceed to Move the next guardian

 

      XOR #80

      LD (HL),A                         ; time to update the guardian's x-coordinate, so reset the animation-frame to the first one for the next cell-column

 

      LD A,(IX+$02)                    ; guardian definition byte 2

      LD C,A                               ; temporarily save in the C register

      AND #1F                            ; extract guardian's current x-coordinate

      CP B                                  ; has the guardian reached the extremity of its range in the current direction of travel?

      JR Z,mid_path_toggle   ; if so, jump to toggle the mid-path bounce on/off, and then reverse the guardian's direction of travel

 

      RLC D                                ; moving left, Carry is now set; moving right, Carry is cleared

      INC A                                 ; adjust A to account for width of guardian(?)

      SBC A,(IX+$04)                 ; has the guardian reached a mid-path bounce point?

                                                 ; [N.B. If you use a SUB command instead of a SBC here, then the guardian gets stuck at its mid-point!]

      JR Z, turn_around            ; if mid-path bounce point has been reached, reverse the guardian's direction of travel

 

      LD A,C                               ; retrieve guardian definition byte 2

      ADD A,E                            ; adjust x-coordinate

      LD (IX+$02),A                    ; and save

      JR #91B6                           ; proceed to Move the next guardian

 

mid_path_toggle:

      LD A,(IX+$04)

      XOR #40

      LD (IX+$04),A

 

turn_around:

      LD A,(HL)                           

      XOR #E0                            

      LD (HL),A                           

      JR #91B6                           ; proceed to Move the next guardian

 

There are six spare bytes now remaining at #9179 to #917E.

 

 

The mid-path bounce point is specified by the guardian's (previously unused) definition Byte 4.  EDIT: Perhaps the term 'Intermediate Bounce Point' is more appropriate; it doesn't necessarily have to be mid-way (i.e. halfway) between the leftmost and rightmost extremities of the guardian's horizontal range.

 

(N.B. If you have a quirky guardian which wraps round past the edge of the screen, then set IX+$04 = #80 to avoid an inadvertent mid-path bounce caused by the default value of zero for Byte 4.)

Edited by IRF
Link to comment
Share on other sites

The terminology that I used was "Mid Sprite bounce". Indicating a bounce in the mid part of its path. NOTE I keep on using Mid and not Middle.  

 

Mid has a multitude of definitions  Its preposition definition is      --- in the course of ---

 

 

You define a bounce point in the course of the sprite path.  

Link to comment
Share on other sites

  • 2 weeks later...
  • 2 weeks later...

However, the following method eliminates the need to Complement the Carry Flag.

 

Starting at #9133 (changes from previous code highlighted in bold):

 

      PUSH IX   ; copy the address of Byte 0 of the guardian definition

      POP HL    ; to the HL register-pair

 

      LD DE,#E0FF     ; parameters for a

      LD A,(IX+$06)    ; guardian moving left

      BIT 7,(HL)

      JR NZ, left

      LD DE,#2001     ; parameters for a 

      LD A,(IX+$07)    ; guardian moving right

 

left:

      LD B,A

 

      LD A,(HL)

      ADD A,D                 ; increment animation-frame of guardian

      BIT 7,(HL)               ; sets the Zero Flag for a left-moving guardian

      LD (HL),A                ; update guardian definition Byte 0 with correct animation-frame

      JR Z,carry_okay

      CCF                        ; Complement the Carry Flag for a right-moving guardian

 

carry_okay:

      JP PO,#91B6            ; not time to update the guardian's x-coordinate; proceed to Move the next guardian

 

If we get here then the Overflow Flag has been set (for both directions of travel)

 

      XOR #80

      LD (HL),A               ; time to update the guardian's x-coordinate, so reset the animation-frame to the first one for the next cell-column

 

      LD A,(IX+$02)        ; guardian definition byte 2

      LD C,A                   ; temporarily save in the C register

      AND #1F                ; extract guardian's current x-coordinate

      CP B                       ; has the guardian reached the extremity of its range in the current direction of travel?

      JR Z,turn_around   ; if so, jump to reverse its direction of travel

      LD A,C                   ; retrieve guardian definition byte 2

      ADD A,E                ; adjust x-coordinate

      LD (IX+$02),A        ; and save

      JR #91B6               ; proceed to Move the next guardian

 

turn_around:

      LD A,(HL)               ; we're not updating the x-coordinate after all,

      XOR #E0                ; instead we are switching to consider the other set of four animation-frames

      LD (HL),A               ; [assuming it's an eight-frame bidirectional sprite; if not, then filtering out of unwanted frames is done at the 'Draw the guardians' stage]

      JR #91B6               ; proceed to Move the next guardian

 

[#9166 to #917E is now free - that's four more bytes than with previous method]

 

 

This effectively reverses the status of Bit 7 of the guardian definition Byte 0, so that Bit 7 cleared = Moving Right, Bit 7 set = Moving Left.

 

;right adding #20      #00, #20, #40, #60    The Overflow Flag is clear with each addition but not #60+#20 = #80 (which is minus #80 in two's complement)

;left   adding #E0 (minus #20)       #E0 (minus #20), #C0 (minus #40), #A0 (minus #60), #80 (minus #80)   Overflow clear with each addition but not #80+#E0 = #60

 

 

N.B.  You would now need to adjust all the horizontal guardians' data as follows:

 

- Transpose all the half-pages of the eight-frame bidirectional horizontal sprite (e.g. put right-facing Monk at #B400-#B47F, and left-facing Monk at #B480-#B4FF), so that their sprite-frames are arranged within the data in the same way as Willy's - if you don't do this, then they'll all walk backwards!;

 

- Toggle Bit 7 of Byte 0 for all the horizontal guardian classes (i.e. all the relevant entries in pages #A0-#A3), in order to preserve the initial direction of travel upon Willy's entry to each room (e.g. for the green rolly thing in The Bathroom, change the value of #A1D8 from #01 to #81).

 

 

All of the above is probably not worth the bother just to save another four bytes in the 'Move the guardians' routine.  (Although it will save a few more bytes in the 'Draw Willy' routine as well, because there's no longer a need to swap half-pages when using the Flying Pig as the playing sprite in The Nightmare Room.)

 

It was more of an interesting academic exercise to me, and it allowed me to gain a better grasp of the functioning of the Overflow Flag.  :)

 

The above approach may be more appropriate for optimising the horizontal guardian movement in Manic Miner (i.e. having a shared set of commands for both left and right movement), since the guardians 'face themselves' in their sprite pages rather than being 'back to back', and as a result there would not be a need to swap the two halves of each sprite page.  I haven't tried it out yet though.

Link to comment
Share on other sites

The above approach may be more appropriate for optimising the horizontal guardian movement in Manic Miner (i.e. having a shared set of commands for both left and right movement), since the guardians 'face themselves' in their sprite pages rather than being 'back to back', and as a result there would not be a need to swap the two halves of each sprite page. I haven't tried it out yet though.

 

Having thought about the above, I'm not sure if it's feasible to come up with an arrangement that's more byte-efficient than the current one.

 

Firstly, the direction of travel for horizontal guardians would have to be determined from Bit 2 of Byte 04. But there's no easy way of checking when the value in Byte 4 has spilled over past Bits 0-2, other than by checking for the individual values 08 or -01 (#FF). The Carry Flag wouldn't respond in these circumstances.

 

Maybe if all the values for animation frame were doubled (and the 'Draw the horizontal guardians' routine was amended accordingly, with an additional RRCA inserted at #8DD0), then the Half-Carry Flag could be used. But I don't think there are any Z80 instructions (conditional jumps etc) which are determined by the status of the H Flag.

 

You would need to fundamentally change the function of Byte 04 for horizontal guardians - edit all the horizontal guardian data, so that Bits 5-7 holds the animation frame (with Bits 0-4 unused, although perhaps they could be recycled for other purposes?), rewrite the 'Move the horizontal guardians' routine in accordance with my previous post, and then NOP out the three RRCA's in the 'Draw the horizontal guardians' routine at #8DCE-#8DD0.

 

Probably not worth the hassle.

Link to comment
Share on other sites

  • 4 weeks later...

The two commands at #888F and #8890 can be replaced with a BIT 1,D, and the jump at #8892 changed to a JR Z (different conditionality and a relative jump) - saves two bytes.

 

****

 

In the 'Print a Sprite' routine (#9456), there is replication of certain commands (#9458-##9461 and #9463 are repeated at #9464-#946D and #9470). Placing those commands in a subroutine, and CALLing them twice (with an INC L in between, and the move to the next raster line following afterwards) would save a few bytes.

 

****

 

If the toilet attributes are printed first, then the CALL to draw the toilet's pixels can be replaced with a JUMP, saving one byte as the RET at the end of the draw routine serves to return the program to the Main Loop.

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.