Jump to content
Jet Set Willy & Manic Miner Community

Free space and code optimisation in "JSW"


jetsetdanny

Recommended Posts

I have now tried out the alternative end to the 'Lose a life' routine, and removed the code in 'Room setup' which wipes the bottom screen-third.

 

Another option I'm considering is, instead of just erasing the expired lives, print over them with a bespoke 16x16 graphic indicating their demise. The code which animates the remaining lives wouldn't touch such graphics, I believe.

 

As per the above, instead of the expired lives being overwritten by a blank sprite (32 contiguous zeroes), I have printed a modified version of the Barrel sprite in their place.  (With the three 'X's being replaced by the letters 'RIP'!)

 

I have also tweaked the 'Draw the remaining lives' routine so that the consecutive lives appear in different animation-frames - like in Geoff Mode, but I have gone further than he did so that the adjacent lives are updated at different times as well.

 

It all works fine.  :)

Link to comment
Share on other sites

I have now tried out the alternative end to the 'Lose a life' routine, and removed the code in 'Room setup' which wipes the bottom screen-third.

 

 

As per the above, instead of the expired lives being overwritten by a blank sprite (32 contiguous zeroes), I have printed a modified version of the Barrel sprite in their place.  (With the three 'X's being replaced by the letters 'RIP'!)

 

I have also tweaked the 'Draw the remaining lives' routine so that the consecutive lives appear in different animation-frames - like in Geoff Mode, but I have gone further than he did so that the adjacent lives are updated at different times as well.

 

It all works fine.  :)

 

Further to the above, I've also noticed that if you apply the Infinite Lives POKE, the RIP sprite briefly appears when Willy is killed - overprinting the right-hand dancing Willy in the 'Remaining Lives' bar - but then the rightmost dancing Willy is restored (replacing the RIP sprite) when the game resumes!

Edited by IRF
Link to comment
Share on other sites

  • 2 weeks later...

If the following two commands (five bytes) are added at the start of the subroutine at #9584:

 

LD HL, #85D2

SET 0, (HL)

 

then the eleven bytes at #8A00-#8A0A can be removed from the Main Loop entirely.

 

****

 

To achieve the above:

 

- The four bytes at #9580-83 can be replaced by a relative jump to the code that is currently at #9596 (but that will need to be adjusted to take account of the next step); that saves two bytes;

- The three-byte command at #959A is redundant, and can be removed (remember to adjust the length of the relative jump which takes you to that entry point, from #9539).

Edited by IRF
Link to comment
Share on other sites

A few efficiencies can be found around the IN commands that take signals from the keyboard.

Wherever there is a LD BC,#0000 followed by an IN A,(C) - this can be replaced with a LD A,#00 [the value that was previously being loaded up to B] followed by an IN A,(#FE).

Also, in places where a routine responds to any keypress from one or more entire half-rows of keys*, you can replace this sequence:

AND #1F
CP #1F

which leaves the Zero flag reset if and only if one of the appropriate keys is pressed, with this:

OR #E0
CPL  [Note that the CPL command leaves the Zero Flag unchanged, even if the Accumulator ends up with a value of #00.]

INC A  [This replaced the CPL command, which didn't work.  INC A will set the Zero flag if and only if the previous value of A was #FF i.e. all bits set, because no keys in the relevant half-row are being pressed.]

which has the same effect on the Zero flag, but requires one less byte.

(*Such as pausing/unpausing the game, toggling the music on/off, or pressing a Jump key other than '0'. It wouldn't work when specific keys out of a half-row are being tested, such as Left-Right movement or the SHIFT+SPACE abandon-the-game key combo.  Note that this won't work if the situation requires the precise value in A - as determined by the particular key in the half-row that was pressed - to be used for other purposes.)

Edited by IRF
Link to comment
Share on other sites

Space saving

 

The code from $8aab to $8ac6    

     
8AAB LD BC,$FEFE   Read keys SHIFT-Z-X-C-V
8AAE IN A,©
8AB0 LD E,A              Save the result in E
8AB1 LD B,$7F          Read keys B-N-M-SS-SPACE
8AB3 IN A,©
8AB5 OR E                Combine the results
8AB6 AND $01           Are SHIFT and SPACE being pressed?
8AB8 JP Z,$87CA      If so, quit the game

8ABB LD A,($85E0)   Increment the inactivity timer at 85E0
8ABE INC A
8ABF LD ($85E0),A
8AC2 JR Z,$8AD1      Jump if the inactivity timer is now 0 (no keys have been pressed for a while)
8AC4 LD B,$FD         Read keys A-S-D-F-G

The code from 8AAB to 8ac6 can be replaced by

    CALL $1F54
    JP NC,$87CA
    LD HL,$85E0
    INC (HL)
    JR Z,$8AD1
; c has not been set up yet, so the next instruction sets c 
    LD BC,$FDFE  ;


 
 

;in all the versions of Manic miner or JSW I have posted, I tend to not use BC for the ports

Tendency is
 
    ld a,port_? ;port_? is assigned to the row or even multiple row of keys that will be read
    in a,($fe)
 
The code I actually use is defined in a MACRO, so I will type and see

 

    Read_Port      port_a+port_k  ; this sets up and scans both keyboard rows.  e.g.   row a-s-d-f-g  and row h-j-k-l-enter

 

The reason I do this is to ensure the port is fully assigned when addressed.
It also frees the BC register pair

Edited by Norman Sword
Link to comment
Share on other sites

JG Harston provides a patch to check for wall tiles at head-height in both directions:

 

http://mdfs.net/Software/JSW/JGH/Docs/Patch.htm#wall

 

The patch is made to fit into the available space by using some code efficiencies:

 

Original code: Changed to:

9035 22 D3 85 LD (POSITION),HL 9035 3A B2 80 LD A,(WALL)

9038 78 LD A,B 9038 BE CP (HL)

9039 32 CF 85 LD (YPOSN),A 9039 C8 RET Z

903C 3E 03 LD A,&03 903A 22 D3 85 LD (POSITION),HL

903E 32 D2 85 LD (FRAME),A 903D 3E 03 LD A,&03

9041 C9 RET 903F C3 AE 90 JP &90AE

 

This approach (of using common code at the end of the parts of the 'Move Willy (3)' routine which deal with Willy moving left and moving right) can be taken further, to save a few more bytes:

 

Original code: Changed to:

9035 22 D3 85 LD (POSITION),HL 9035 3A B2 80 LD A,(WALL)

9038 78 LD A,B 9038 BE CP (HL)

9039 32 CF 85 LD (YPOSN),A 9039 C8 RET Z

903C 3E 03 LD A,&03 903A 3E 03 LD A,&03

903E 32 D2 85 LD (FRAME),A 903C C3 AB 90 JP &90AB

9041 C9 RET 903F 00 00 00 Three spare bytes

 

90AA 22 D3 85 LD (POSITION),HL 90AA AF XOR A

90AD AF XOR A 90AB 22 D3 85 LD (POSITION),HL

Link to comment
Share on other sites

I decided to ditch the whole of Matthews code for dealing with ramps. That is the code from  $8fbc  to $90b5 =$105=  259decimal 

 

In essence the code repeats for left and right. I wanted it to be exactly symmetrical, with no deviation in how it handles left or right.

 

So the code I use handles both directions by having one routine, which has  variables passed to it. The testing is the same in both directions and it is around 187 bytes in length or around  72 bytes shorter than Matthews version.

 

The code in the post below has been edited to move the subroutine to inline code. This has reduced its size by 7 bytes. So length is now around 180 bytes or around 79 bytes shorter than Mattthews version.

Edited by Norman Sword
Link to comment
Share on other sites

slight edit to change a comment, which was from code that no longer exists. The comment confused what was happening when testing for extremes of movement left and right.

 

This code has been edited repeatedly to arrive at what is seen

Comments are sometimes the remains of multiple copies, and pastes

 

If I am aware of a misplaced comment, I will delete it or edit it.

 

 

;set variables for these offsets
ramp_frame                  equ 0
ramp_animation            equ 1*2
ramp_where_1              equ 2*2
ramp_where_2              equ 3*2
ramp_condition             equ 4*2
ramp_adjust                  equ 5*2
ramp_exit_screen          equ 6*2
ramp_final_adjust          equ 7*2
ramp_animation_reset   equ 8*2

 

;left data followed by right data
left_data

  db 0, 3                   ;0 VALUE TO JUMP FRAME - limit of animation movement at same position
  DB -1, 1                 ;1 STEP TO NEXT animation FRAME - replaces inc or dec
  DB $1f, $22           ;2 POSITION OF RAMP 1 - ramp walk up
  DB $41, $40          ;3 POSITION OF RAMP 2 - ramp walk down
  DB 0, 1                  ;4 CONDITION FOR RAMP DIRECTION - decision to check for up or down
  DB -1, 2                 ;5 DIRECTION TO ADJUST HL - where to check vertically
  DB 31, 0                ;6 CONDITION TO TEST FOR NEW ROOM (limit of travel)
  DB 0, -1                 ;7 STEP BACK - adjust of hl after vert check
  DB 3, 0                  ;8 ANIMATION RESET for next frame
;-----------------------------------

.
L8FBC:
    LD A,(ROPE_STATUS) ;L85D6
    DEC A
    BIT 7,A
    RET Z

    LD A,(L85D0)
    BIT 1,A
    RET Z

; Willy now needs to move left or right
; this movement needs to handle the stairs and check for their presence
; decide if moving left or right

    ld ix,left_data
    AND $01
    JR nz,skippp
    inc ix         ;switch to right data
skippp:
; Willy is moving

    LD  HL,(WILLY_ATT)    ;L85D3
    LD DE,WILLY_ANM      ;L85D2
    LD  A,(DE)
    cp (ix+ramp_frame)
    JR Z,RAMP_CHK
    add a,(ix+ramp_animation)
    LD  (de),a  ;L85D2
    RET

 

RAMP_CHK:
; all de increments are positive so preload D
    ld d,0
    LD  A,(AIRBORNE) ;L85D1
   OR A 
   JR  NZ,as_is

; three outcomes going up  bc=-32
;  going down                      bc=+32
;  no ramp                           bc=0
    ld bc,-32
    ld e,(ix+ramp_where_1)
    ld a,(RAMP_DIR)         ;either 0 or 1
    and 1                           ;get rid of other bits
    cp (ix+ramp_condition) ; the sign test
; this condition swaps on left and right
    jr z,down_
    ld bc,+32
    ld e,(ix+ramp_where_2)
down_:
    add hl,de                     ; add offset to find ramp/stair square
    ld a,(RAMP)
    sub (HL)
    jr z,found_                   ;if ramp is here keep  bc=shift
;ramp not found so no offset needed
as_is:
    ld b,d
    ld c,d                           ;bc=0 no ramp so no offset/shift

found_:
    ld hl,(WILLY_ATT)

; this test is for extremes of position when moving left or right 
    LD A,L                ;left edge =0     right edge=30
    ADD A,(IX+ramp_adjust) ;move in the direction left or right
    LD L,A               ;left edge =-1     right edge=32
    AND 31              ;left edge=31      right edge=0

  ; if value is zero then move right

    ld de,GO_ROOM_LEFT

    jr nz,exit_other_way
    ld de,GO_ROOM_RIGHT
exit_other_way:
    CP (IX+ramp_exit_screen)  ; have we moved to the extremes?
    JR NZ,same_room
;we have moved far enough to enter a new room
   ex de,hl
   jp (hl)

;now check a vertical line for walls blocking path
same_room:

; just move vertically and check the squares
; this code only checks for WALL's nothing else
; after the initial add hl,bc this checks downwards in a line

 

; the initial adjust is for ramps. e.g. up/down or level

    ADD HL,BC  ;Point HL at the cell at
;                                  ;(y-1)  Willy is on or about to go up a ramp
;                                  ;(y+0) just walking
;                                  ;(y+1) Willy is walking down a ramp
    ld a,(WALL)
;in theory this position could be off the top of the screen
    bit 1,h
    jr nz,ignore_head_check
    cp (hl)        ;head
    ret z                       ;return if path is blocked
ignore_head_check:
; now check vertically down
    LD DE,$0020
    ADD HL,DE         ;point hil at the cell one lower
;                               ;(y+0)  Willy is on or about to go up a ramp
;                               ;(y+1) just walking
;                               ;(y+2) if Willy is walking down a ramp
    CP (HL)     ;foot
    RET Z
    LD B,A
    LD A,(WILLY_Y)  ;L85CF
    SRA C
    ADD A,C
    LD C,A
    AND $0F                ;jumping
    JR Z,ONLY_TWO
    LD A,b
    ADD HL,DE

; check- maybe needlessly- but check anyway. 

    BIT 1,H

    JR NZ,OFFSCREEN
;                               ;(y+1)  Willy is on or about to go up a ramp
;                               ;(y+2) just walking
;                               ;(y+3) Willy is walking down a ramp
    CP (HL)  ;beneath?
    RET Z
OFFSCREEN:
    OR A
    SBC HL,DE          ; move back to feet
; final adjust back to HL=head position
ONLY_TWO: 
    OR A 
    SBC HL,DE          ; back to head position (free to move here)

 

;Adjust HL back

    LD A,L
    ADD A,(IX+ramp_final_adjust)
    LD L,A
    LD A,(IX+ramp_animation_reset) ; the animation frame

:save state:
    LD (WILLY_ANM),A             ;L85D2
    LD (WILLY_ATT),HL           ;L85D3
    LD A,C
    LD (WILLY_Y),A                 ;L85CF
    RET

Edited by Norman Sword
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.