Jump to content


Free space and code optimisation in "JSW"

240 replies to this topic

#231 IRF


    Advanced Member

  • Contributor
  • 3,760 posts

Posted 06 March 2018 - 11:54 PM

I noticed that there are several parts of the JSW code which effectively replicate the same function - namely using the table in page #82 of the code to point HL at the appropriate address for drawing various moving entities onto the pixel display and/or pixel buffer.


So I have rewritten several parts of the code to allow a shared routine to be CALLed (with various entry points) which handles the table at page #82, and saves quite a few bytes (I would estimate about 30-40, all told) in the process:


Entry point from ‘Draw Arrows’/’Draw Guardians’ (Input: B = pixel y-coordinate, C = byte containing x-coordinate):



AND #80


OR #5C




Entry point from ‘Draw Willy’ (Input: B = pixel y-coordinate, A = byte containing x-coordinate):






Entry point for Foot on ‘Game Over’ Screen (Input L = y-coordinate, C = #0F):


LD H, #82

LD A, (HL)



LD H, (HL)



; HL now points at pixel-buffer coordinates (#6xxx); for guardians and arrows, D also points at high byte of attribute-buffer coordinates.




Further code changes to facilitate the above:


In ‘Game Over’, replace the code at #8C71-#8C7F with LD L, A followed by LD C, #0F, then a CALL to the appropriate entry point above and finally a RES 5, H command (adjustment made in order to draw to addresses #4xxx instead of #6xxx).


In ‘Draw Arrows’, the CALL to the above makes the existing commands at #926A-#9277 and #928A-#928C redundant.  The command at #9267 needs to be adjusted to write the arrow y-coordinate to B instead of E, that is then followed by a command to write the arrow x-coordinate to C; then CALL the above; after the CALL have LD E, L; finally, the references to HL at #927C, #9286 and #9289 should be replaced with DE.


In ‘Draw Guardians’, #91D6 writes guardian y-coordinate to B instead of E, follow that with a command which writes guardian byte 02 to C; CALL the above; after the CALL have a PUSH HL then LD H, D; after that, NOP out everything up to (but not including) #91EB; and replace #9220-#922D with POP HL.


[The next two steps rely on the ‘Draw a Sprite’ routine at #9456 having been subject to an earlier rewrite of mine, so that it draws the room’s whole complement of guardians (or Maria), and reacts to any collision after RETurning back to the main guardian-drawing routine.]


In ‘Draw Willy’, after the existing code up to and including #963A, the A register holds Willy's y-coordinate; after that insert LD B, A and LD A, (#85D3), then CALL the appropriate entry point above; #9660-#967F is then redundant; simply point DE at Willy's graphic (the appropriate animation frame, or the Flying Pig if necessary), then set LD C, #01 and JUMP to #9456.


In ‘Draw the Toilet’, replace #95B4-#95BA with LD C, #01 and LD HL, #68BC, then at #95BB change the destination of the CALL to #9456.




The only place where the original code employing the table at #8200 remains unchanged, and I have made no attempt to use the above 'shared subroutine' approach, is within the 'Draw a Rope' routine - I think it would be too complicated to unravel the segment-drawing loop (and it would probably not yield any byte-savings).

#232 jetsetdanny


    Advanced Member

  • Contributor
  • 1,895 posts

Posted 07 March 2018 - 08:19 AM

Thanks a lot, Ian, this optimisation may come in very handy when one needs some spare bytes! :)

#233 IRF


    Advanced Member

  • Contributor
  • 3,760 posts

Posted 09 March 2018 - 01:15 PM

Some changes in logic in the Main Loop which could save a few bytes:

- In between the existing commands at #89CC and #89CE, insert a JR Z, #89E9. Change #89CE and #89DE to unconditional CALLs. Then the commands at #89D9 and #89DC become unnecessary (net saving of three bytes).

- Possibly the three byte command at #89E1 can be done away with too, if the commands at #89E4 and #89E6 are relocated prior to #89CE (the CALL to Move Willy). I would need to check that though, especially if another efficiency that I identified has been implemented:
(The SET (HL) might have to be replaced with a RES (HL) to keep Willy running.)

#234 IRF


    Advanced Member

  • Contributor
  • 3,760 posts

Posted 09 March 2018 - 01:47 PM

Thinking about it, that latter change might mean that Willy is moved and drawn one more time before Game Mode 3 kicks in. Which wouldn't be too much of a problem is he is running towards the toilet, but might mean that he loses a life if he falls into the toilet as part of the end sequence? Area for investigation...

#235 IRF


    Advanced Member

  • Contributor
  • 3,760 posts

Posted 21 March 2018 - 04:04 PM

From post 77 in this thread:

; 100% elimination of all attribute cell block drawing effects
; permits multiple graphic definition with the same colour (attribute) **
; ** Matthews code will still give stair/ramps ramp/stairs stair/floor etc

I think I'm right in saying that the 'multiple graphic definitions with shared colour attributes', made possible in JSW via Norman Sword's approach to expanding the room graphics, would NOT be possible in Manic Miner?

Because of the way that the cavern layouts are distributed: each cell is assigned a block type based purely on its colour attribute, so for example if you had crumbling walls, it would be impossible to distinguish between blocks that are intended to use the graphic defined for crumbly and ones that are meant to be drawn using the solid wall graphic definition.

Therefore you could only have one graphic for such a combined block type; it would use the graphic of the first block type to appear in the list - see http://skoolkid.gith...r/asm/8020.html for the order in which block types are considered.

However, all the blocks drawn with the shared attribute/graphic would exhibit the behaviour of both crumbly and wall (in the example above). i.e. they would stop Willy walking/jumping through them, but they would crumble away when he stands on them.

#236 IRF


    Advanced Member

  • Contributor
  • 3,760 posts

Posted 01 May 2018 - 05:01 PM

Note to self: my shared code for left-right horizontal guardian movement could be optimised further.

e.g. Instead of having LD A, (IX+$06) then LD B,A - just do LD B, (IX+$06).

Also use a shared command at the end LD (HL),A to update the animation frame (i.e. an earlier jump destination).

(Temporarily posting this here because on the PC I'm currently using, I can't seem to edit earlier posts.)

#237 IRF


    Advanced Member

  • Contributor
  • 3,760 posts

Posted 02 May 2018 - 09:58 AM



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.


To contradict myself again, I managed to get my suggested approach to work in Manic Miner. :)


I used three RRCA's at the start of the 'Move the horizontal guardians' routine to rotate the animation frame (loaded up to A) into Bits 5-7, and then three RLCA's at the end of the same routine to rotate the updated frame value back into Bits 0-2, before loading back into guardian Byte 04.  (No need to change 'Draw the horizontal guardians'.)


Even with all those additional rotate commands, there are still at least ten spare bytes left over because of the merging of the left-right movement commands!

#238 jetsetdanny


    Advanced Member

  • Contributor
  • 1,895 posts

Posted 02 May 2018 - 05:45 PM

Well done, Ian, congratulations! :)

#239 Spider


    XOR (HL)

  • Administrator
  • 3,289 posts

Posted 05 May 2018 - 12:51 PM

Well done, Ian, congratulations! :)

I can only concur. :)

  • IRF likes this
Changing order to chaos since 1984

#240 IRF


    Advanced Member

  • Contributor
  • 3,760 posts

Posted 02 July 2018 - 01:43 PM

For the record, in my code which optimises the horizontal guardian movement routine (by using shared code for both left and right movement), there is a further optimisation to be had by replacing:


LD A, (IX+$06) / LD A, (IX+$07)





LD B, (IX+$06) / LD B, (IX+$07)

1 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

    Alexa (1)