jetsetdanny Posted July 7, 2019 Report Share Posted July 7, 2019 Great stuff, Norman Sword! :thumbsup: Quote Link to comment Share on other sites More sharing options...
IRF Posted July 8, 2019 Report Share Posted July 8, 2019 (edited) These labels (in the room expansion code) made me chuckle: tile_it: tile_grout: ****** Regarding the clock update, I came up with the use of XOR to toggle between 'am' and 'pm' independently, and suggested it to Metalmickey for his 'As Manufacturer Intended' project. But the rest of the method is an innovation - ditching the use of an indexed register (IX) saves quite a few bytes (no need to use the 'shift opcode' DD), and the comparison against a table of 'upper limit values' for each digit ("clock_master") is rather ingenious! Edited July 8, 2019 by IRF jetsetdanny and Spider 2 Quote Link to comment Share on other sites More sharing options...
IRF Posted July 9, 2019 Report Share Posted July 9, 2019 (edited) I think I might(?) have come up with a further optimisation of the room expansion code - I haven't tried it out yet though... Suggested changes are in red: tile_grout: LD IX,att_master ; 8D36 ;$5E00 Point IX at the first byte of the attribute buffer at 5E00 ld de,char_mastertile_do: ld a,(ix) ld c,a add a,a add a,a add a,a add a,c ;*9 add a,low back_tile ld l,a ld h,high back_tile ld a,(hl) ;tile colour ld (ix),a inc ix ;Crosses page boundary at mid point inc l ld c,d call print_non-ASCII_char ;copies data from (hl) to (de):- SCREEN MAPPED see source code for address ; Label renamed for clarity ld a,d ld d,c inc e jr nz,tile_do ;at this point we cross the page boundary LD A, D ADD A, #08 ld d,a BIT 7, D ; Have we finished drawing the room (i.e. is DE now pointing at #8000)? cp high +(char_master+$1000) jr nz JR Z,tile_do ; Conditionality of jump is reversed ret EDIT: Now that I've tallied up the 'before versus after' difference, it might not be any more efficient in terms of memory after all! There are fewer commands overall though, so perhaps it's marginally faster? In addition to the above, the 'Print a message' (#9680) and 'Print a single character' (#9691) routines would need to be rewritten, as follows: ORG #9680 LD A, (IX+$00) ; Collect a character from the message CALL Print_ASCII_character ; Print it INC IX ; Point IX at the next character in the message INC E ; Point DE at the next character cell LD A,D ; (subtracting 8 from D compensates for the operations performed by the subroutine at 9691) SUB $08 LD D,A DEC C ; Have we printed the entire message yet? JR NZ,$9680 ; If not, jump back to print the next character RET Print_ASCII_character: ; Formerly #9691 LD H, #07 LD L, A SET 7, L ADD HL, HL ADD HL, HL ADD HL, HL Print_non_ASCII-character: ; Formerly #9699 ; Label renamed for clarity LD B, #08 ; There are eight pixel rows in a character bitmap Loop: ; Copy the character bitmap (or triangle UDG, or item graphic) to the screen (or screen buffer) LD A, (HL) LD (DE), A INC HL INC D DJNZ Loop LD A,D ; Subtracting 8 from D compensates for the operations performed by this subroutine SUB $08 LD D,A RET As I say, I haven't tested this out yet. Off the top of my head, I can't think of any reason why it wouldn't work, but careful consideration is needed bearing in mind that the 'Print a (non-ASCII) character' late entry point into the 'Print a single character' subroutine is also used by other code (such as the Impossible Triangle and item-drawing routines). Edited July 9, 2019 by IRF Spider and jetsetdanny 2 Quote Link to comment Share on other sites More sharing options...
IRF Posted July 9, 2019 Report Share Posted July 9, 2019 (edited) EDIT: Now that I've tallied up the 'before versus after' difference, it might not be any more efficient in terms of memory after all! However, a byte could possibly be saved by replacing this (commands in green): LD A, D ADD A, #08 LD D, A BIT 7, D ; Have we finished drawing the room (i.e. is DE now pointing at #8000)? JR Z,tile_do ; Conditionality of jump is reversed RET with this: LD A, D ADD A, #08 LD D, A JP PO, tile_do or JP PE, tile_do ; Overflow Flag is set when ADD 8 takes D from #78 to #80, but not when D goes from #70 to #78 RET Again, I've not tried this out yet. And I'm not currently sure if, when the Overflow Flag is set, whether that translates as Parity Odd or as Parity Even? (But if one doesn't work - presumably causing the routine to bail out after drawing the pixels for the top half of the room only - then the opposite conditionality for the jump should do the trick.) EDIT: In this instance, testing the Sign Flag (i.e. JP P or JP M) would have the same effect as testing Overflow. In either case, there is only an absolute jump available for this purpose, not a relative jump. So only one byte can be saved, not two. Edited July 9, 2019 by IRF Spider and jetsetdanny 2 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 9, 2019 Author Report Share Posted July 9, 2019 (edited) Rope compression: code originally sits from $92a4 up to $93d1 TOATAL saving from code around $102 258 bytes ;----------------------------------------------------------------------------------------------------; the original rope had one entry per byte 00000xxxb; the compact had two entries per byte 11112222b ; where 1111=y and 2222=x and are data entries; the super compact 11223344b ;where 11=y 22=x (odd) 33=y, 44=x (evens) ; SUPER COMPACT ROPE ;------------------------------------------------------------------------------------------------- ;only 45 (at time of looking) smaller ;this mass of code and code change might seem pointless to save around 45 bytes.;Its true purpose is to reduce the rope table from 256 bytes down to around 43 bytes. saving 213 bytes on the rope table org $92a4 ;We are dealing with a rope.draw_rope: LD IY,ytable ;L92A4 ;L8200 set iy at the start of the y table LD (IX+rope09),$00 ; 92A8 ; Initialise the segment count LD A,(IX+rope02) ; 92AC ; copy the initial x position LD (IX+rope03),A ; 92AF ; into the current x position LD (IX+rope05),$80 ; 92B2 ; define the pixel to draw; start at bit 7 ; if hl waa passed as hl=ix;; inc hl ;+1; inc hl ;+2; ld a,(hl); inc hl ;+3; ld (hl),a ; 5 bytes compared to the 12 used ;The following loop draws each segment of the rope from top to bottom.rope_segments: LD A,(IY+$00) ;L92B6 ;L92B6 extract the ls from the current y table position ld b,(ix+rope03) ; X OFFSET add a,b ; ; add the x offset LD L,A ; 92BC ; the ls formed LD H,(IY+$01) ; 92BD ; get the ms from the y table ;hl=address to consider;Hl=address to draw pixel; set some variables up LD d,(IX+rope05) ; ; drawing byte (pixel) ld e,(ix+rope09) ; ; current segment count; are we hooked onto the rope LD A,(rope_status) ; 92C0 ;L85D6 OR A ; 92C3 ; Is Willy on the rope, or has he recently jumped or dropped off it? JR NZ,L92D6 ; 92C4 ; Jump if so; not hooked but is the about to be drawn pixel occupied ld a,d ; ; Pick up the drawing byte AND (HL) ; 92C9 ; Is this segment of rope touching anything else that's been drawn so far (e.g. Willy)? JR Z,L930E ; 92CA ; Jump if not; indicate we hit something here, and hook willy on, at this position ld a,e ; ; Copy the current segment counter into the rope status indicator at L85D6 LD (rope_status),A ; 92CF ;L85d6 SET ropebit,(IX+rope0B) ; 92D2 ; ropebit=0, Signal: Willy is on the rope; again is willy hooked and do we need to adjust willies position and phaseL92D6: cp e ; ; Does the rope status indicator at L85D6 match the current segment counter? JR NZ,L930E ; 92D9 ; Jump if not BIT ropebit,(IX+rope0B) ; 92DB ; ropebit=0, Is Willy on the rope (and hooked to this segment)? JR Z,L930E ; 92DF ; Jump if not ld a,d ; ; Pick up the drawing byte(pixel) in A ; we adjust the position of willy depending on the pixel he is hooked onto;pixel phase position adjust;10000000\ c=2 b=-1;01000000/ ;00100000\ c=3 b=-1;00010000/ ;00001000\ c=0;00000100/ ;00000010\ c=1;00000001/ LD C,$01 ; 92E7 ; C=0=Willy's next animation frame CP $04 ; 92E9 ; bit 0 or 1 JR C,L92FC ; 92EB ; Jump if so dec c ; 92ED ; c=1=Willy's next animation phase CP $10 ; 92EF ; bit 2 or 3? JR C,L92FC ; 92F1 ; Jump if so DEC B ; 92F3 ; Decrement the x-coordinate LD C,$03 ; 92F4 ; c=3=willy's next animation phase CP $40 ; 92F6 ; bit 4 or 5? JR C,L92FC ; 92F8 ; Jump if so dec c ; 92FA ; c=2=Willy's next animation frame L92FC LD (willy_anim),BC ;L92FC ;L85D2 Set Willy's animation frame at L85D2, and temporarily store his x-coordinate at L85D3 LD A,IYl ; 9300 ; Update Willy's pixel y-coordinate location as the rope moves SUB $10 ; 9302 ; PUSH HL ; 9307 ; Save HL briefly ; uses willy y and x to generate its att position in hl (willy_att -which is updated); the call only destroys hl and af; note call is to the opcode before where it used to call CALL update_willy_att_a ; ; Update Willy's attribute address as Willy and the rope moves POP HL ; 930B ; Restore the screen buffer address of the segment of rope under consideration to HL L930E: ;draw pixel to buffer ld a,d ; ;rope05 Draw a pixel of the rope OR (HL) ; 9311 ; LD (HL),A ; 9312 ;; now move the pointers, CALCULATE THE NEXT PIXEL TO DRAW and where;IY IS MOVED DOWN THE table by the offset specified in the rope table ld a,e ; ; rope09 current segment LD c,(IX+rope01) ; ; start offset and direction add A,c ; ; LD H,high rope_table ; 931C ;$83;a is the total offset but I have compressed the data into half its original offset data space. (data is 1/4 original size)and 01111111b ; ; force positive - REMOVE THE side bit sra a ; ; half and find what bit 0 was (odd or even) ld l,a ; ; l is compensated offset into data ld a,(hl) ; ; the carry bit dictates iF the data is held in the high or low nibble; hl not used from here; "L" will be re assigned jr c,nib_low ; ; go depending on odd or even extract rrca rrca rrca rrcanib_low: and 15 ; ; the four bits hold the y offset in 1100b and the x offset in 0011b ld l,a ; ; temp save and 1100b ; ; this is times 4 y value, but y value is a word offset so still needs /2 rrca; move the y position add a,iyl ; ; adjust the y offset ld iyl,a ; ; save new offset; now consider the x ld a,l ; ; how much does the pixel move in the x direction and 3 ld b,a ; ; this is the rotate count jr z,b_was_zero ; ; if no displacement then don't bother calculating new x offset ld a,d ; ; the pixel value from (ix+rope5) ld l,(ix+rope03) ; ; X POS;b=rotate c=rope01=sign l=rope03=x a=d=rope05=bit e=rope09 ; rotate the pixel either left or right and adjust the x-position when pixel has moved to next byte bit 7,c ; ; rope01 jr z,go_leftgo_right: rrca jr nc,go_r1 inc lgo_r1: djnz go_right jr gone go_left: rlca jr nc,go_l1 dec lgo_l1: djnz go_leftgone: ld (ix+rope03),l ; ; the new x offset ld (ix+rope05),a ; ; the new byte(pixel);come here if no shift in the pixel positionb_was_zero: ld a,(ix+rope04) ; ; the length of the rope inc (ix+rope09) ; ; one segment more (note rope09 not used after here, if we abort loop) cp e ; ; have we reached full length yet Jp nz,rope_segments ; ; Jump back to draw the next segment of rope ;Now that the entire rope has been drawn, deal with Willy's movement along it.L935E;has willy just jumped off the rope ld hl,rope_status ; ; ld a,(hl) bit 7,a ; if on the rope this value is less than 128 ; if the value is over 128 then we are flagged as in free flight just after leaving the rope jr z,L936F ; inc (hl) ; ; the period of free flight is counted down RES ropebit,(IX+rope0B) ; 9369 ; ropebit=0, Signal: Willy is not on the rope JR next_entity_draw ; 936D ;L93b3 Jump to consider the next entity ; is he clutching onto the ropeL936F: BIT ropebit,(IX+rope0B) ;L936F ; ropebit=0, Is Willy on the rope? JR Z,next_entity_draw ; 9373 ;L93b3 go If not to next entity;on the rope so decide if rope slide up/down needed LD A,(willy_dir) ; 9375 ;L85D0 Pick up Willy's direction and movement flags from L85D0 BIT 1,A ; 9378 ; Is Willy moving up or down the rope? JR Z,next_entity_draw ; 937A ;L93b3 If not, jump to consider the next entity;calculate the direction of slide RRCA ; 937C ; XOR Willy's direction bit (0=facing right, 1=facing left) with the rope's direction bit;; ;; ; (0=swinging right to left, 1=swinging left to right) XOR (IX+rope00) ; 937D ; RLCA ; 9380 ; RLCA ; 9381 ; Now A=1 if Willy is facing the same direction as the rope is swinging (he will move down the rope),;; ;; ; or -1 otherwise (he will move up the rope) AND $02 ; 9382 ; DEC A ; 9384 ; ;delete this is already set up;; LD HL,rope_status ; 9385 ;L85d6 Increment or decrement the rope status indicator at L85D6 ADD A,(HL) ; 9388 ; LD (HL),A ; 9389 ; LD A,(room_up) ; 938A ;L80EB c=room above LD C,A ; 938D ; LD A,(current_room) ; 938E ;L8420 CP C ; 9391 ; Is the room above the same as the current room JR NZ,L939B ; 9392 ; Jump if so;limit movement up the rope LD A,(HL) ; 9394 ; rope status CP $0C ; 9395 ; check for the minimum value we can move up the rope JR NC,L939B ; 9397 ; Jump if so LD (HL),$0C ; 9399 ; moved to far so set to the minimum; check for limit moving down the ropeL939B: LD A,(HL) ;L939B ; rope status indicator CP (IX+rope04) ; 939C ; Compare it with the length of the rope JR C,next_entity_draw ; 939F ;L93b3 any adjustment that has taken willy off the bottom of the rope detach willy JR Z,next_entity_draw ; 93A1 ;L93b3 let him cling to the last pixel; detach willy from the rope, he has slid off the end LD (HL),$F0 ; 93A3 ; Set the rope status indicator at L85D6 to 0xF0 (Willy has just dropped off the bottom of the rope) ld hl,willy_y LD A,(hl) ; ; Round down Willy's pixel y-coordinate at L85CF to the nearest multiple of 8; AND $F8 ; 93A8 ; LD (hl),A ; ; XOR A ; 93AD ; Initialise the airborne status indicator at L85D1 LD (airborne),A ; 93AE ;L85D1 ; ;The current entity has been dealt with. Time for the next one.next_entity_draw: LD DE,$0008 ;L93B3 ; offset to next entity ADD IX,DE ; 93B6 ; add offset so we point at the next entity JP L91C2 ; 93B8 ; ;+ the rope table which sits at $8300 reduced from 256 bytes rope_table: DEFB (6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0 DEFB (6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0 DEFB (6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0 DEFB (6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0,(6*2+0)*16+6*2+0 DEFB (6*2+1)*16+6*2+1,(6*2+1)*16+6*2+1,(6*2+1)*16+6*2+1,(6*2+1)*16+6*2+1 DEFB (6*2+1)*16+6*2+1,(6*2+1)*16+6*2+1,(6*2+2)*16+6*2+2,(6*2+2)*16+6*2+2 DEFB (4*2+2)*16+6*2+2,(6*2+2)*16+4*2+2,(6*2+2)*16+4*2+2,(6*2+2)*16+4*2+2 DEFB (6*2+2)*16+4*2+2,(4*2+2)*16+4*2+2,(6*2+2)*16+4*2+2,(4*2+2)*16+4*2+2 DEFB (4*2+2)*16+4*2+2,(4*2+1)*16+4*2+2,(4*2+2)*16+4*2+1,(4*2+1)*16+4*2+2 DEFB (4*2+1)*16+4*2+1,(4*2+2)*16+4*2+2,(4*2+3)*16+4*2+2,(4*2+3)*16+4*2+2 DEFB (4*2+3)*16+4*2+3,(4*2+3)*16+4*2+3,(4*2+3)*16+4*2+3 see original listing for references TOTAL SAVING around 258 bytes ($102) Edited July 9, 2019 by Norman Sword IRF, jetsetdanny and Spider 3 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 9, 2019 Author Report Share Posted July 9, 2019 Current saving Total saving Rope compression 258 258cheat code 51 309 room draw 50 359 lower att draw + logo draw 400+ 759+ twinkle 39 798+ clock update 14 812+ IRF, jetsetdanny and Spider 3 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 9, 2019 Author Report Share Posted July 9, 2019 ROOM JUMP ROUTINES sits from $948a to $94F9 this routine is 36 bytes smaller ; see source code for references ; ;948A: Move Willy into the room to the leftmove_room_left ;L948A ; LD BC,$E01E ;$FE1E ; LD HL,room_left ; point at new direction GO_NEW_ROOM: LD A,(HL) ; get new room LD (current_room),A;L8420 ; set new room LD HL,willy_att LD A,(HL) AND B OR C LD (HL),A ;L85D3 ; set new x pos POP HL ; Drop the return address (89D1, in the main loop) from the stack JP enter_new_room ;L8912 ; Draw the room and re-enter the main loop move_room_right: ;L949E ; LD BC,$E000 LD HL,room_right JR GO_NEW_ROOM .move_room_up: ;L94B0 ; LD BC,$1FA0 LD HL,room_up; page reference ld de,$d001+(high (att_work)) XOR AVERT_PROCESS: LD (airborne),A LD A,E LD (willy_att+1),A LD A,D LD (willy_y),A JR GO_NEW_ROOM move_room_down: ;L94D2 ; LD BC,$1F00 LD HL,room_down;page reference ld de,$0000+(high (att_work)) LD A,(airborne) ;L85D1 ; CP $0B ; Is it 0x0B or greater (meaning Willy has already been falling for a while)? JR NC,VERT_PROCESS ; Go if so LD A,$02 ; Otherwise set the airborne status indicator to 2 (Willy; ; will start falling here if there's no floor beneath him) JR VERT_PROCESS IRF 1 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 9, 2019 Author Report Share Posted July 9, 2019 (edited) Current saving Total saving Rope compression 258 258cheat code 51 309room draw 50 359lower att draw +logo draw 400+ 759+twinkle 39 798+clock update 14 812+ room exits 36 848 Edited July 9, 2019 by Norman Sword Spider and jetsetdanny 2 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 9, 2019 Author Report Share Posted July 9, 2019 subtle change to the conveyor routine - saves 9 bytes just a logic flow change: no attempt at reducing code ;94F9: Move the conveyor in the current roommove_conveyor: LD HL,(conv_add) ;L94F9 LD A,H ; 94FC AND $01 ; 94FD RLCA ; 94FF ; RLCA ; 9500 ; RLCA ; 9501 ; ADD A,high char_master' LD H,A ; 9504 ; LD E,L ; 9505 ; LD D,H ; 9506 ; LD A,(conv_len) OR A ; 950A RET Z ; 950B LD B,A ; 950C LD A,(conv_dir) OR A ;********************************* JR NZ,move_conv_right Z,move_con_left change condition and label ex de,hl add one opcode ;*********************************** ;The conveyor is moving left. move_conv_left LD A,(HL) ; 9513 RLC A ; 9514 ; RLC A ; 9516 ; INC H ; 9518 ; INC H ; 9519 ; LD C,(HL) ; 951A RRC C ; 951B ; RRC C ; 951D ;L951F: LD (DE),A ;L951F LD (HL),C ; 9520 INC L ; 9521 INC E ; 9522 DJNZ L951F ; 9523 RET ; 9525 ; ; delete all the code below ;The conveyor is moving right.move_conv_right: L9526 LD A,(HL) ;L9526 RRC A ; 9527 RRC A ; 9529 ; INC H ; 952B INC H ; 952C ; LD C,(HL) ; 952D RLC C ; 952E RLC C ; 9530 ; JR L951F ; 9532 ; a subtle nine bytes shorter by altering one opcode and adding ex de,hl jetsetdanny and IRF 2 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 10, 2019 Author Report Share Posted July 10, 2019 (edited) We can delete the room storage buffer. This is not used in the game and takes up 128 bytes. ( slightly updated:- since this is only referenced twice) We add a new label called S_M_C_pointer_room_data which I will come to later then change part of the routine enter_new_room: at $891a from LD DE,room_layout ; 891A ;L8000 Copy the room definition into the game status buffer at L8000 LD BC,$0100 ; 891D ; LDIR To ld (S_M_C_pointer_room_data),hl ; save where this data is - needed for the room expansion routine ld bc,$80 add hl,bc ld de,room_name LDIR Then change the start of the routine draw_room at $8d33from LD HL,room_layout to S_M_C_pointer_room_data equ $+1 ld hl,$-$ See source listing for references This saves 128 bytes but uses an extra 4 bytes to set up the data Call it a saving of 120 bytes Edited July 10, 2019 by Norman Sword jetsetdanny and IRF 2 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.