IRF Posted January 4, 2018 Report Share Posted January 4, 2018 Thanks Norman! Quote Link to comment Share on other sites More sharing options...
IRF Posted January 4, 2018 Report Share Posted January 4, 2018 (edited) GO_ROOM_LEFT ;L948A LD BC,$FE1E ; Given that the AND now comes before the OR, it's possibly more elegant, logical and consistent to use LD BC, $E01E when moving into the room to the left. i.e. For both 'Exit Left' and 'Exit Right' (for which BC=$E000), pass the bits which represent Willy's (unchanged) vertical position through the AND B gate, and then set the bits which determine his (new) horizontal position via the OR C gate. Although it makes no difference to the final outcome. And of course, it's another excellent bit of optimisation that you've come up with! Edited January 4, 2018 by IRF Spider 1 Quote Link to comment Share on other sites More sharing options...
IRF Posted January 4, 2018 Report Share Posted January 4, 2018 (edited) Just to expand on my point about 'consistent logic', when Willy is moving into a vertically adjacent room, the AND B filters the bits which represent Willy's unchanged horizontal position, then the OR C sets the appropriate bits for his new vertical position. So for 'Exit Up', BC=$1FA0. For 'Exit Down', BC=$1F00. Edited January 5, 2018 by IRF Spider 1 Quote Link to comment Share on other sites More sharing options...
IRF Posted January 9, 2018 Report Share Posted January 9, 2018 The following idea only saves a single byte, but I consider it to be a most satisfactory arrangement: - Replace the 'INC HL' at #96C6 with a 'DEC HL'; - Take all the notes of the Title Screen tune, reverse their order, and insert them into the range of spare addresses starting at #8141, such that the last note of the tune occupies the address #8141; - Edit the operand of the LD HL, $0000 command at #88A8, to point at the new position of the first byte of the Title Screen tune (the first note now occupying the highest used address in page #81 of the code). The Guardian Buffer Terminator Byte (value #FF) at #8140 now serves a dual purpose, as it also serves to terminate the Title Screen tune! N.B. Under this arrangement, the Title Screen tune now has a maximum length of 191 bytes (not including the Terminator Byte), because page #82 of the code is used as the Screen Buffer Address look-up table). Spider 1 Quote Link to comment Share on other sites More sharing options...
IRF Posted January 10, 2018 Report Share Posted January 10, 2018 (edited) [Norman Sword's code for Willy's horizontal movement] handles both directions by having one routine, which has variables passed to it. The testing is the same in both directions and..... [is much] shorter than Matthews version. I wonder if a similar process could be used to optimise the code which moves horizontal guardians, so that the code which moves them left and right is shared? IX would already be in use by the guardian loop, but perhaps you could use the IY indexed register-pair to assign variables depending on a horizontal guardian's direction of travel? Or else use the B/C/D/E registers to set the variables? Geoff Mode takes that approach for the code which moves ropes - see #90D7 to #911D in the disassembly of his game engine: https://web.archive.org/web/20030701143111/http://www.cix.co.uk/~morven/jsw/geoff_dis.html Mind you, the existing code for moving horizontal guardians is much shorter than the equivalent Willy-handling code, so it might not be worth optimising/consolidating in the same way, even if it were possible - the table of variables, plus the code which sets up the combined left/right movement regime, might be as long as one half of the current code anyway! I am pleased to report that I've managed to achieve the above (my suggestion in bold). The following code will handle horizontal guardians moving both leftwards and rightwards, and it saves 21 bytes compared with Matthew's original code: Starting at #9133: 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,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 [#916A to #917E is now free; this may be sufficient to implement Norman Sword's 'mid-sprite bounce' - that's my next area for investigation...] Edited June 4, 2019 by IRF Spider 1 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted January 10, 2018 Report Share Posted January 10, 2018 Nice piece of code. My only editing of the original code was to stop the type of guardian being changed whenever the original horizontal code was called. This was because my homing sprite called the horizontal movement whenever it wanted to move horizontally. The original code changed the guardian type. It is noted that the guardian type in your code is not modified. For clarity on your code it would benefit from a few additions regarding the usage of bit 7 (direction). This bit is being toggled in several places, with no mention as to why. e.g. XOR #80 ;restore direction (bit 7) which was inverted XOR #E0 ; invert direction (bit 7) and invert animation bits (6 and 5) and finally for clarity , an explanation of what the carry bit is being used for. ; the direction bit (bit 7 = #80) must be taken into account;animation right adding #20 #80, #a0, #c0, #e0 carry clear with each addition but not #eo+#20 = #00; left adding #e0 #60, #40, #20, #00 carry set with each addition but not #00+#eo = #eo Spider and IRF 2 Quote Link to comment Share on other sites More sharing options...
IRF Posted January 10, 2018 Report Share Posted January 10, 2018 I ran out of time last night. I intend to provide more commentary when I have the time (particularly in relation to the need to complement the Carry Flag), but I think you've grasped the gist of it. I've also come up with a further optimisation which negates the need to take the Carry Flag into account in that way (and saves another four bytes), by replacing the JR C with a JP PO (responding to the Overflow Flag, with the conditionality the same for both left- and right-moving guardians). However, it's a bit of a fiddle as it involves swapping the half-pages of each bidirectional sprite (otherwise they walk backwards!), amongst other changes. It is possible to do it whilst preserving all the original behaviour though. Spider 1 Quote Link to comment Share on other sites More sharing options...
IRF Posted January 10, 2018 Report Share Posted January 10, 2018 Thanks for the compliment BTW! Spider 1 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted January 10, 2018 Report Share Posted January 10, 2018 (edited) ;very little difference to the other version.;;but this has;1) the addition of cell blocking to stop up and down movement via stairs into blocks;2) changes in logic for jumping.;3) removal of some data from the data table ;; some of the data tables entries can be calculated by code. But the overhead of the code is bigger than the data table entry ;e.g entry for (ix+ramp_final_adjust)= (ix+ramp_where_1)-(ix+ramp_step) ;;set variables for these offsetsramp_step equ 0*2ramp_where_1 equ 1*2ramp_where_2 equ 2*2ramp_adjust equ 3*2ramp_final_adjust equ 4*2ramp_animation_reset equ 5*2; ;left data followed by right dataleft_data DB -1, 1 ;0 STEP TO NEXT animation FRAME - replaces inc or dec DB $1f, $22 ;1 POSITION OF RAMP 1 - ramp walk up DB $41, $40 ;2 POSITION OF RAMP 2 - ramp walk down DB -1, 2 ;3 DIRECTION TO ADJUST HL - where to check vertically db $20, $21 ;4 FINAL ADJUST - final adjust of willy to his new moved to position DB 3, 0 ;5 ANIMATION RESET for next frame;----------------------------------- ; ;8FBC: Move Willy (3); Used by the routines at 8DD3 and 8ED4. This routine moves Willy; left or right as necessary.RAMP_LOGIC ;L8FBC LD A,(ROPE_STATUS) ;L85D6;rope status indicator DEC A ;Is Willy on a rope? RET P ;Return if so (Willy's movement along a rope is handled at 935E) LD A,(L85D0) ;L85D0;Willy's direction and movement flags BIT 1,A ;Is Willy moving? RET Z ;Return if not;not on a rope, but moving ld ix,left_data AND $01 ;Is Willy facing left? JR nz,set_left ;go if so 1=LEFT, 0=RIGHT inc ix ;else move IX to right dataset_left: ld c,a ;save direction facing LD HL,(WILLY_ATT) ;L85D3; Willy's attribute buffer coordinates; is the animation still within the same ATT squares ld de,WILLY_ANM ld a,(de) ;(WILLY_ANM);L85D2 ;Willy's animation frame at 85D2 add a,(ix+ramp_step) ;-1 OR +1 step to next animation;if it was 0 then and now -1;or if it was 3 then now 4 ; in both cases bit 2 is set BIT 2,A ;check limits JR NZ,RAMP_CHK ;L8FDC ;move Willy's across a cell boundary;if here still contained within the same animation (att) square, but different phase of animation LD (DE),A ;WILLY_ANM RET ; Willy now needs to move left or right and move into new attribyte squares; this movement also needs to handle the stairs and check for their presenceRAMP_CHK:; three final outcomes for bc; going up bc=-32; going down bc=+32; no ramp/blocked bc=0 push hl ;save for later ; all de increments are positive so preload D ld d,0; if jumping ignore ramp checks LD A,(AIRBORNE) ;L85D1 OR A ;Is Willy jumping? JR NZ,null_offset ;Jump if so;not jumping so check for stairs ld a,(RAMP_DIR) ;L80da ;either 0 or 1; in the original JSW this value is 0 or 1 (my versions use other bits. so get rid the extra bits) and 1 ;get rid of the other bits; this condition swaps on left and right movement cp c ;set the condition for where to check;assume going up ramp ld bc,-32 ld e,(ix+ramp_where_1) jr nz,ramp_decided; if here going down ld bc,+32 ld e,(ix+ramp_where_2)ramp_decided: add hl,de ; add offset to find ramp/stair square ld a,(RAMP) ;L80C4 sub (hl) ; is a ramp here ?;if ramp not found then no offset needed jr nz,null_offset;on a ramp is it going down? or b ;the direction, taken from BC=+32/-32, "A" must have been 0 jr nz,found_ ;branch if going up;going down so locate the possible blocking tile LD A,L ADD A,(ix+ramp_step) ;step across to possible wall LD L,A;is the wall blocking descent ld a,(WALL) ;L80B2 cp (hl) jr nz,found_;a wall is blocking going down ramp- so remove ramp offset - and walk horizontally along ramp/wall ::; come here for no offset-or no ramp actionnull_offset: ld b,d ; ld c,d ;bc=0, no ramp so no offset/shiftfound_: pop hl ;retrieve WILLY_ATT add hl,bc ; add the possible ramp displacement ld a,(WALL) LD B,A ; ld e,(ix+ramp_adjust) ;d is still 0 ld a,l and 31 add a,e ; move across;if negative (-1) then jp m,GO_ROOM_LEFT ;L948A; if 32, then also off screen bit 5,a jp nz,GO_ROOM_RIGHT ;L949E ld a,l ; restore full x position (which has part y position embeded) add a,e ld l,a ;still on screen bit 1,h jr nz,ignore_this; additional check if moving up a ramp; which checks out of line for willies head;c can be -32 +32 or 0 bit 7,c jr z,hor_or_dwn;going up find the tile to check ld e,a sub (ix+ramp_step) ; the direction we are moving ld l,a ;hl adjusted to head tile ld a,b ; the wall tile value cp (hl) ;wall tile? ret z ;return path is blocked;adjust back ld l,ehor_or_dwn:; move vertically and check the squares; after the initial add hl,bc and possible head check; this checks downwards in a line ; ;change logic if jumping downward, willies head can pass through wall block call jump_fix ;z=moving down ld a,b jr z,ignore_this ;zero indicates logic change-- ignore this tile cp (hl) ;head ;wall tile? ret z ;return path is blocked; resume checking vertically downignore_this: ld e,$20 ;D is still 0 ADD HL,DE ;move hl down one row; ;(y+0) if Willy is on or about to up a ramp; ;(y+1) if just walking or; ;(y+2) if Willy is walking down a ramp CP (HL) ;foot ;wall tile? RET Z ;Return path is blocked LD A,(WILLY_Y) ;L85CF; y-coordinate (Y); bc held the ramp shift (b has been re-used but c is still the ramp shift) SRA C ; halve the value from ;c 32>16 ;c 0>0 ;c-32>-16 to get ramp y-shift ADD A,C ; y-position + ramp y shift LD C,A ; save in C; this addition is changing logic depending on movement (jumping)call jump_fix ;z=moving down; if jumping downward this square MUST be checked jr z,force_this; otherwise check if willy occupies 3 squares ld a,c AND $0F ; JR Z,ONLY_TWO ;Jump if notforce_this: LD A,b ;ATT wall tile ADD HL,DE ;point hil at the cell one lower; Addendum for the bottom of the screen... Jumping downward and cell aligned can process of the screen; it is easier to capture/stop problems before they happen BIT 1,H JR NZ,offscreen; ;(y+1) if Willy is on or about to up a ramp; ;(y+2) if just walking or; ;(y+3) if Willy is walking down a ramp CP (HL) ;beneath ;Is there a wall tile down there? RET Z ;return path is blockedoffscreen: OR A ; SBC HL,DE ; move back to feet position ;if here then Willy has been allowed to move up or down a ramp- walked along or jumped into a new attribute square.; so save all the new parameters ONLY_TWO OR A ld e,(ix+ramp_final_adjust) SBC HL,DE ; back to final head position (free to move here) LD (WILLY_ATT),HL ;L85D3;Save Willy's new attribute buffer coordinates LD A,(IX+ramp_animation_reset) ; the animation frame LD (WILLY_ANM),A ;L85D2 LD A,C ;Willy's new pixel y-coordinate LD (WILLY_Y),A ;L85CF RET;-----------------------------------------jump_fix: ld a,(JUMP) ;L85d5 sub 12 ret c ld a,(AIRBORNE) dec a ret Edited January 10, 2018 by Norman Sword IRF and Spider 2 Quote Link to comment Share on other sites More sharing options...
IRF Posted January 10, 2018 Report Share Posted January 10, 2018 (edited) I have compiled various bits of code to try and achieve the same thing (in relation to the movement along ramps in the vicinity of wall tiles), but I haven't yet had a chance to sit down and put it all together into a working test file. It will be interesting to see if it achieves the same thing as your code (assuming mine works!) EDIT: Having now studied Norman's code, it seems to be addressing the same issues. However, I also had a notion to amend the routine at #95C8. Otherwise when Willy walks down a ramp and steps onto an adjacent wall/Earth block ( a la 'On top of the house'), and he's in a position where his front foot is on the wall but his back foot is still on the ramp, then his sprite will be drawn progressively 'sunken down' into the wall as his animation-frame progresses within the same pair of cell-columns - until he transcends the next cell-column boundary and moves beyond the influence of the ramp tile (at which point his sprite will appear to suddenly 'spring back up' onto the top of the wall tile, because the downwards vertical displacement normally caused by the ramp has been cancelled out in this case). Therefore, I would propose to edit the start of the routine at #95C8 as follows (new elements in bold, relocated elements in italics): LD HL, (#85D3) ; Willy's attribute coordinates LD B, #00 ; default vertical offset (in case Willy is not on a ramp) LD A, (#85D1) ; might as well place this earlier - if Willy is jumping then no need to test for underfoot ramp cell OR A JR NZ, vert_offset_dealt_with LD A, (#80DA) ; Ramp direction byte AND #01 LD C, A ADD A, #40 LD E, A LD D, B ; incidental one-byte efficiency here, compared with original code ADD HL, DE LD A, (#80C4) ; ramp attribute byte CP (HL). ; Is Willy's 'up-slope' foot on a ramp cell? JR NZ, vert_offset_dealt_with. ; If not, keep B=0 OR A SBC HL, DE. ; restore Willy's attribute coordnates in HL LD A,C ; A now holds either 0 or 1 XOR #01 ADD A, #40 XOR #41 ; I think this will do the same as the two operations struck-through above, but in one two-byte operation? ; (given the limited possible input values of A) LD E,A ; D already holds 00 ADD HL,DE LD A, (#80B2) ; Earth/wall attribute byte CP (HL). ;Is Willy's 'down-slope' foot on an Earth/wall block? JR Z, vert_offset_dealt_with. ; If so, keep B=0 That then leads into the code originally at #95E4, which calculates the vertical offset when Willy is standing on a ramp. #95F8 is the jump destination labelled as vert_offset_dealt_with in the above. Edited January 11, 2018 by IRF Spider 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.