Jump to content
Jet Set Willy & Manic Miner Community

Norman Sword

Contributor
  • Posts

    603
  • Joined

  • Last visited

Everything posted by Norman Sword

  1. The usage of $-$. When using self modified code we have the situation that the code is changed depending on what the program flow is. In certain circumstances we know that the reference we see is always modified before the part of the code we are looking at is executed. When we know that the code is changed before it is executed the value stored is of no importance when it is written. So having code say LD A,7 ; and knowing that the value is supplied and always set before we execute the opcode, seems to be pointless. The S_M_C_ is indicating that the code is being modified. The $-$ is indicating that the value will be supplied before the opcode is executed. It is also giving a very good indication of what is being modified.
  2. S_M_C_ Self Modifed Code Quick answer:- The data is part of code that is Self modified. e.g. Self_modified_code An explanation. In every listing or source code I write. I make the distinction between variables, labels and the one part of an assembly listing that can or could cause problems. When writing code it is possible to design code to have multiple entry points, be recursive and even have code that changes by virtue of the code modifying itself. When code modifies itself we can have references to opcodes and variables in the code that might not be directly situated on a label. These references cause problems because they look the same as any other part of the code and will cause unknown problems if edited. It is better to basically red flag the code for example:- I can write FLUX: ld hl,100 more code....... ld hl,200 ld (FLUX+1),hl Editing the code around FLUX looks simple enough, and when the code has only a hundred or so lines easy enough to remember, Consider the situation when your code has grown to 30,000 lines of code with hundreds of routines. Can you now assume you will always remember that FLUX needs to be treated with caution. So to remove those easily forgotten references to code that changes I introduced a standard prefix to any label that will have something modified because of it. The label might be referencing an op-codes or the data of an opcode. The type of reference is unimportant. What the label prefix is forcing on you as you see it in the code and see any reference to that label in the code. Is the caution that what you read in the source listing might NOT be what is seen as the code is run. The prefix reference also forces caution on the code around it. The example above re written:- FLUX: S_M_C_flux equ $+1 ld hl,100 more code....... ld hl,200 ld (S_M_C_flux),hl A quick scan of the code alerts us to the presence of code that is being modified. example 2 S_M_C_ direction: inc a lots of code.... xor a ;kill movement ld (S_M_C_direction),a lots more code... ld a,$3d ;reverse direction ld (S_M_C_direction),a If the label S_M_C_direction: was changed to be just direction: it becomes very easy to edit the op code or move the op code. "direction:" would look to be just another label and the editing of the code directly after the label would seem to be no problem. If the code is part of a program that has lots of program paths, you edit can throw up unexpected problems that can take a long time to find. Far easier to red flag it. so S_M_C_ self modified code or self Modifying code..... Both versions imply the same caution. Addendum:- In the source listing for Jet set willy, I have used the same S_M_C_ prefix. It is used in the only part of Matthews code that modifies itself. at $8D5C we have S_M_C_page , where the page offset is changed
  3. Routine savings Total saving Rope compression 258 258 cheat code 51 309 room draw 50 359 lower att draw + logo draw 400+ 759+ twinkle 39 798+ clock update 14 812+ room exits 36 848 conveyor 9 857 room storage 120 977
  4. 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 $8d33 from 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
  5. 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 room move_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
  6. Current saving Total saving Rope compression 258 258 cheat code 51 309 room draw 50 359 lower att draw + logo draw 400+ 759+ twinkle 39 798+ clock update 14 812+ room exits 36 848
  7. 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 left move_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 A VERT_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
  8. Current saving Total saving Rope compression 258 258 cheat code 51 309 room draw 50 359 lower att draw + logo draw 400+ 759+ twinkle 39 798+ clock update 14 812+
  9. 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 phase L92D6: 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 rrca nib_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_left go_right: rrca jr nc,go_r1 inc l go_r1: djnz go_right jr gone go_left: rlca jr nc,go_l1 dec l go_l1: djnz go_left gone: ld (ix+rope03),l ; ; the new x offset ld (ix+rope05),a ; ; the new byte(pixel) ;come here if no shift in the pixel position b_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 rope L936F: 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 rope L939B: 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)
  10. original code at $8ce3 to $8d33 ; approx figures ; this routine in 38 (approx) byes - the original was 77(approx) byes saving 39(approx) bytes LD BC,$0000 ; 8CE3 ; B=delay, c=Colour LD D,$06 ; 8CE6 ; d=major loop counter delay: DJNZ delay ;L8CE8 ;L8CE8 Delay for about a millisecond delay djnz delay call TWINKLE dec c jr nz,delay dec d jr nz,delay jp display_title TWINKLE ld a,c ld hl,ATT6+10 CALL TWINK LD L,LOW +(ATT6+18) TWINK: LD B,4 TWINK1: INC A AND 7 OR BRIGHT LD (HL),A INC L DJNZ TWINK1 RET See original source listing for references
  11. ; update the clock originally at $8a52 to $8aaa This routine is approx 74 bytes, 14 (approx) bytes smaller ld de,mess_time+4 ld hl,clock_master+4 update_clock: ld a,(de) cp ":" jr z,clock_colon: cp " " jr nz,valid_dig ld a,"0" valid_dig: inc a ld (de),a dec a cp (hl) ; are we at max yet jr nz,clock_out ld a,"0" ld (de),a clock_colon: dec hl dec de jr update_clock ; clock_master: DB "29:59" am_2_pm equ "a" xor "p" ; ;do we need to adjust output ; check 1 is from 11:59 am to 12:00pm ;- toggle am/pm ; check 2 is from 12:59 am to 13:00 ; reset to 1:00 clock_out: ex de,hl ld a,l ; which char was last updated cp low +(mess_time+1) jr nz,clock_updated ;we have just updated unit part of the hour (10:00 change updates the tens part) dec hl ld a,"1" ; is the hour 1x:00 ? cp (hl) ; it all happens on either 12:00 or 13:00, so is the "1" present jr nz,clock_updated ; hour can be 11:00, 12:00 or even 13:00 - see comment above on 10:00 inc hl inc a ; change to "2" ; check for 12:00 cp (hl) JR Z,MIDNIGHT ; just gone 12:00 INC A ; change to "3" ;check for 13:00 CP (HL) JR NZ,clock_updated ; clock now says 13:00, so reset to 1:00 ld hl,$3120 ; " 1" NOTE LS MS switch ld (mess_time),hl jr clock_updated ; clock is on midnight/noon change am to pm and pm to am MIDNIGHT: ld hl,mess_time+5 ld a,(hl) xor am_2_pm ;toggle the am/pm ld (hl),a ; if this extra check to abort the game at midnight was not done, we could carry on. The clock has been correctly changed to am cp "a" ; the midnight change jp z,game_over_time ; >>> this can go to the boot routine - game over etc. clock_updated: Routine is smaller and changes from am to pm/ and pm to am- at 12:00am and 12:00pm routine aborts game at midnight possible to chop bytes from the code- clarity suffers greatly for such small changes
  12. ;8D33: Draw the current room to the screen buffer at 7000 ; this $8d33 to $8d9a (50 bytes approx shorter) ; original $8d33 to $8dd3 ; No attribute errors- draws exactly what is specified. ; the tile printed is the tile specified (in every case) ; routine executes a lot faster draw_room: ;L8D33 ; start by defining each of the six types into the master attribute area ;e.g. place 0=backround 1=floor,2=wall 3=nasty,4=ramp 5=conveyor into the master attribute area ;first part, expand the lower compacted data for the four types LD HL,room_layout ;Point HL at the first room layout byte at L8000 LD de,att_master ;Point IX DE at the first byte of the attribute buffer at 5E00 mosaic: ld a,(hl) ld b,4 tile_it: rlca rlca ld c,a and 3 ld (de),a ld a,c inc de djnz tile_it inc l bit 7,l jr z,mosaic ;Next consider the conveyor tiles (if any). ;draw_conveyor LD A,(conv_len) ; 8D90 ;L80D9 Pick up the length of the conveyor from L80D9 OR A ; 8D93 ; Is there a conveyor in the room? JR Z,draw_ramp ; 8D94 ;L8DA1 Jump if not LD HL,(conv_add) ; 8D96 ;L80D7 Pick up the address of the conveyor's location in the attribute buffer at 5E00 from L80D7 LD B,A ; 8D99 ; B will count the conveyor tiles L8D9D: LD (HL),5 ;L8D9D ; Copy the attribute bytes for the conveyor tiles into the buffer at 5E00 INC HL ; 8D9E ; DJNZ L8D9D ; 8D9F ; ;And finally consider the ramp tiles (if any). draw_ramp: LD A,(ramp_len) ;L8DA1 ;L80DD Pick up the length of the ramp from L80DD OR A ; 8DA4 ; Is there a ramp in the room? jr Z,tile_grout ld b,a LD HL,(ramp_add) ; 8DA6 ;L80DB Pick up the address of the ramp's location in the attribute buffer at 5E00 from L80DB LD A,(ramp_dir) ; 8DA9 ;L80DA) Pick up the ramp direction from L80DA; A=0 (ramp goes up to the left) or 1 (ramp goes up to the right) and 1 ; 0 or 1 rlca ; 0 or 2 sub $21 ; -$21 or -$1f ld e,a LD D,$FF ; 8DB2 ; L8DBB: LD (HL),4 ;L8DBB ; Copy the attribute bytes for the ramp tiles into the buffer at 5E00 ADD HL,DE ; 8DBC ; DJNZ L8DBB ; 8DBD ; ; now draw the tiles ; take the six defined types and expand into the tile- 100% garanteed the correct definition tile_grout: LD IX,att_master ; 8D36 ;$5E00 Point IX at the first byte of the attribute buffer at 5E00 ld de,char_master tile_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 printing_char ;copies data from (hl) to (de):- SCREEN MAPPED see source code for address ld a,d ld d,c inc e jr nz,tile_do ;at this point we cross the page boundary ld d,a cp high +(char_master+$1000) jr nz,tile_do ret saving around 50 bytes - see source listing for references
  13. Cheat code entry:- keyport equ $FE ; this will sit from $8b70 to $8bCd 51(approx) bytes shorter ; original $8b70 to $8c01 ; Here we check the teleport keys. ;CODE FROM $8B70 re arranged and re written teleport_check: ld hl,cheat ld a,(hl) cp 10 jr nz,check_for_cheat ld a,$ef in a,(keyport) BIT 1,A JR NZ,LA_HOP AND $10 XOR $10 RLCA LD B,A ld a,$f7 in a,(keyport) CPL AND $1F OR B LD (current_room),A JP enter_new_room check_for_cheat: LD A,(current_room) CP $1C JR NZ,LA_HOP LD A,(willy_y) sub $d0 JR NZ,LA_HOP ld b,a LD a,(HL) add a,a EX DE,HL ld c,a LD HL,cheat_table add hl,bc ld bc,$21f ld a,$fb cheat_read: in a,(keyport) and c CP (HL) JR NZ,check_cheat2 INC HL ld a,$df djnz cheat_read EX DE,HL INC (HL) LA_HOP: JP main_loop check_cheat2: cp c JR Z,LA_HOP DEC HL DEC HL CP (HL) JR Z,LA_HOP EX DE,HL LD (HL),0 JR LA_HOP - saving around 51 bytes- see source code listing for the references
  14. In response to post #11, how to save a byte. I did wonder why the check was done in such a manner. And went back to the original listed source code. This was an edit of the original source code, and A Mr Matthew Smith chose that method originally, and I just left it. If I was to go through all this code, I have already thought of some areas of code that could be changed. Like a dog chasing its tail, each look draws attention to something else and each change draws attention to something else. Next the clock part 5) Typo manor instead of manner.... changed
  15. Having spent longer writing about what I did than I took to write the code. I will add that this is not how I normally draw the logo triangle. I still prefer the code I created that allows me to scale the logo to any size I need. That code is nothing like the code above.
  16. part 4) ORG $8000 ; fixed screen references CHAR0 EQU $4000 CHAR1 EQU $4020 CHAR2 EQU $4040 CHAR3 EQU $4060 CHAR4 EQU $4080 CHAR5 EQU $40A0 CHAR6 EQU $40C0 CHAR7 EQU $40E0 CHAR8 EQU $4800 CHAR9 EQU $4820 CHAR10 EQU $4840 CHAR11 EQU $4860 CHAR12 EQU $4880 CHAR13 EQU $48A0 CHAR14 EQU $48C0 CHAR15 EQU $48E0 CHAR16 EQU $5000 CHAR17 EQU $5020 CHAR18 EQU $5040 CHAR19 EQU $5060 CHAR20 EQU $5080 CHAR21 EQU $50A0 CHAR22 EQU $50C0 CHAR23 EQU $50E0 ATT0 equ $5800 ATT1 equ $5820 ATT2 equ $5840 ATT3 equ $5860 ATT4 equ $5880 ATT5 equ $58a0 ATT6 equ $58c0 ATT7 equ $58e0 ATT8 equ $5900 ATT9 equ $5920 ATT10 equ $5940 ATT11 equ $5960 ATT12 equ $5980 ATT13 equ $59a0 ATT14 equ $59c0 ATT15 equ $59e0 ATT16 equ $5a00 ATT17 equ $5a20 ATT18 equ $5a40 ATT19 equ $5a60 ATT20 equ $5a70 ATT21 equ $5aa0 ATT22 equ $5ac0 ATT23 equ $5ae0 ;fixed hardware INKS BLACK EQU 0 BLUE EQU 1 RED EQU 2 MAGENTA EQU 3 GREEN EQU 4 CYAN EQU 5 YELLOW EQU 6 WHITE EQU 7 ;hardware colour control BRIGHT EQU 64 FLASH EQU 128 ;================================================= start: call draw_bottom_att call draw_logo hang: jr hang ;======================================================================== draw_bottom_att: ld de,ATT16 ld ix,bottom_att ld hl,bottom_translate jp expand ;======================================================================= ; this draws the attributes for the logo ; ; Slight change in data that is needed for the expansion of the ATT data ; ; If the ink flashes or the ink and paper are the same colour then no graphic overlay ; ; graphic "\" := no bright then set as a "\" graphic ; ; graphic "/" := bright then set as "/" graphic and delete the bright ; draw_logo: ld de,ATT0 ld ix,new_logo_dat ld hl,new_logo_translate ld a,$07 ld (S_M_C_double),a ;an rlca call expand xor a ;the nop opcode ld (S_M_C_double),a ;---------------------------------------------- ; now draw the text on top of the logo ld hl,ATT0 ld de,logo_overlay ld c,FLASH+RED+8*YELLOW ; this can be changed to any flashing colour combination, with differing ink colours text ld a,(de) cp 255 jr z,graphic ld b,8 ;width of data byte text1: rlca ;bit out jr nc,clear ld (hl),c clear: inc hl djnz text1 inc de jr text graphic: ;--------------------------------------- logo_graphics: ; this part adds the graphics LD DE,ATT0 ; 8841 ;$5800 logo_draw: LD A,(DE) ;L8844 ; if ink=paper then ignore or if the flash bit is set then ignore ;$00,$09,$2d,$24 skip ink=paper ; d3 skip flashing tile bit 7,a jr nz,logo_skip ;flashing is the text overlay ld c,a rrca rrca rrca ; rotate paper bit down to ink bits position xor c and 7 jr z,logo_skip ; these are the solid squares ld a,c ; ; NEXT GROUP if bright one way else other ; NOTE the odd value $2c which was changed to $25, this has had its source data changed to $25. ;The other $25's,'s now have bright added ;"\" $08,$29,$2c,$05 ;"/" the rest all have bright now set ld hl,triangle_udg ; set graphics to use bit 6,a ; the bright jr z,logo1_graphic ld hl,triangle_udg+16 and 10111111b ; remove the bright ld (de),a logo1_graphic: ld a,e ; Offset by eight bytes if the position on screen is odd rlca rlca rlca and 8 ; Extract the offset call index1 ; add a to hl returns a=(a+hl) ;ignore the return "a" ld c,d ; save the position HIGH ; Bit 0 in 'd' indicates top or bottom half of screen BIT 0,D ; 8880 ; Set the zero flag if we're still in the top third of the attribute file LD D,high CHAR0 ; 8882 ;$40 Point DE at the top third of the display file JR Z,L8888 ; 8884 ; Jump if we're still in the top third of the attribute file LD D,high CHAR8 ; 8886 ;$48 Point DE at the middle third of the display file L8888: CALL printing_char ; ; Draw a triangle UDG on the screen ld d,c ; ; restore position HIGH logo_skip: ;move to next cell, and check if at the end of the area we are changing INC DE ;L888E ; Point DE at the next byte in the attribute file LD A,D ; 888F ; Have we finished scanning the top two-thirds of the attribute file yet? CP high +(ATT16) ; 8890 ;$5A Jr NZ,logo_draw ; 8892 ;L8844 If not, jump back to examine the next byte ret ;======================================================================== ; sub routine to expand data expand: ld (S_M_C_translate),hl draw_logo_loop: ld a,(ix) inc ix cp 255 ret z S_M_C_translate: equ $+1 ld hl,$-$ call indexer draw_in ld (de),a inc de djnz draw_in jr draw_logo_loop ;======================================================================= ; expand subroutine - find run length and data to write indexer: ld c,a and $f0 rrca rrca rrca rrca inc a ;next opcode changed for double run length S_M_C_double: equ $ nop ;opcode 07 for rlca ld b,a ld a,c and 15 ; - index into hl via "a" and return (hl+"a") in "a" ; general subroutine index1: add a,l ld l,a adc a,h sub l ld h,a ld a,(hl) ret ;=============================== all the logo data ======================= new_logo_translate: ; 0 1 2 3 4 5 6 7 8 9 A B C D DB 0,$68,$05,$2D,$65,$24,$04,$4C,$09,$08,$29,$25,$2C,$44 new_logo_dat: DB $F0 DB $F0 DB $80, $01, $02 DB $c0, $01,$03,$04 DB $b0, $01,$03,$04,$05 DB $a0, $01, $03, $04, $15 DB $90, $01,$03,$04,$05,$07,$05 DB $80, $01,$03,$04,$05,$0d,$08,$05 DB $80, $0a,$03,$0b,$0D,$00,$08,$05 DB $80, $08,$0A,$03,$02,$00,$08,$05 DB $80, $09,$08,$0A,$03,$02,$08,$05 DB $90, $09,$08,$0A,$03,$08,$05 DB $a0, $09,$08,$0A,$08,$05 DB $b0, $09,$08,$08,$05 DB $c0, $09,$08,$05 DB $d0, $09,$0d,$40 DB $Ff ;teminator logo_overlay db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00100010b,11111000b,10001111b,00011110b db 00100010b,10001001b,01001000b,10100000b db 00111110b,11100010b,00101000b,10011100b db 00100010b,10001011b,11101000b,10000010b db 00100010b,11111010b,00101111b,00111100b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db $ff ; manual inspection for value ;======================================================================= bottom_translate: ; 0 1 2 3 4 5 6 7 8 9 a b c d e f db 0,$01,$02,$03,$04,$05,$06,$07,$46,$45,$41,$43,$44 bottom_att db $f8,$f8 db $f0,$f0 db $f0,$f0 db $01,$02,$03,$04,$05,$06,$97,$97,$06,$05,$04,$03,$02,$01 db $f0,$f0 db $19,$16,$14,$1a,$15,$1b,$1c,$10,$f0 db $19,$16,$14,$1a,$15,$1b,$1c,$10,$f0 db $f0,$f0 db $ff ;------------------------------------------------------------------------ ; these bits of data and code are needed to assemble ; the printing_char routine is part of the games normal print routine. ;8431 Triangle UDGs triangle_udg: ;'\' DEFB $C0,$F0,$FC,$FF,$FF,$FF,$FF,$FF ;L8431 DEFB $00,$00,$00,$00,$C0,$F0,$FC,$FF ; 8439 ;'/' DEFB $FF,$FF,$FF,$FF,$FC,$F0,$C0,$00 ; 8441 DEFB $FC,$F0,$C0,$00,$00,$00,$00,$00 ; 8449 This part is part of the games print text. printing_char: LD B,$08 ; 9699 ; There are eight pixel rows in a character bitmap ;This entry point is used by the routine at L87CA to draw a triangle UDG on the title screen, and by the routine at L93D1 ; to draw an item in the current room. print_char: ;L969b LD A,(HL) ;L969B ; Copy the character bitmap (or triangle UDG, or item graphic) to the screen (or screen buffer) LD (DE),A ; 969C ; INC HL ; 969D ; INC D ; 969E ; DJNZ print_char ; 969F ;L969b RET ; 96A1 ; end start ; everything from above assembles into $1AB of code and data. Just the original data was $300 ** NOTE ** proportional spaced font has destroyed the layout of this data and code. I have slightly redone the layout.
  17. Part 2a: The original logo draw and expansion does a lot of checking for the various colours. The result of all these checks is the decision on how any graphic is finally drawn to the screen. There are in the region of 13 differing coloured blocks, and the code decides what it is going to draw based on the colour of the block. The blocks defined seem to be laid out in no order, and the extraction of the blocks to either draw a graphic one way or draw a graphic the other seems to be haphazard. Then we have the problem that one of the colour blocks is changed in colour as it is looked at. Looking at the part that draws the logo from the attributes we can see the various checks being made at the start of the routine. We need a better look at these checks rather than just using checks for specific numbers. The first set of checks are actually looking at two things. OR A JR Z,logo_skip CP $D3 JR Z,logo_skip CP $09 JR Z,logo_skip CP $2D JR Z,logo_skip CP $24 JR Z,logo_skip These checks are concerned with either the flashing logo letters -- Value $d3 or any colour tile where the ink and paper are the same colour. So Instead of doing checks for specific colours I will check for ink and paper match instead. The $d3 match is best changed to a more vague check of flashing ink/paper. This allows the colour to be changed with one instruction at the part the draws the giant text. (assuming we have split the giant text from the logo) Next we have a lot of checks for the various slope graphics. and a special case where the colour is changed. By looking at the data and looking at what is wanted, we can see that the reason we have a special case colour is because that single colour is odd compared to the rest. When that odd colour tile is drawn it ends up as a sloped tile with the same colour as some other sloped tiles. But slopping in the opposite direction. Which is why it is singled out and treated differently. It is easier and more logical to use the built in attributes of the tiles. The logo itself is drawn with no BRIGHT attributes. so instead of all the various checks needed to draw the logo. Lets just use the BRIGHT bit as a simple indicator for the direction of the slope. So if the tile has the BRIGHT bit it slopes one way and a tile without the BRIGHT bit can slope the other way. Doing this removes the special case tile. The tile has its colour changed to what it should be. After checking the tile for the BRIGHT bit, The bit is immediately switched off. This changes the draw routine to the following. logo_graphics: ; this part adds the graphics LD DE,ATT0 logo_draw LD A,(DE) bit 7,a jr nz,logo_skip ld c,a rrca rrca rrca xor c and 7 jr z,logo_skip ld a,c ld hl,triangle_udg bit 6,a jr z,logo1_graphic ld hl,triangle_udg+16 and 10111111b ld (de),a logo1_graphic ld a,e rlca rlca rlca and 8 call index1 ; add a to hl returns a=(a+hl) ;ignore the return "a" ld c,d BIT 0,D LD D,high CHAR0 JR Z,Llow LD D,high CHAR8 Llow CALL printing_char ;the instruction before the normal call, which loads b with 8 ld d,c logo_skip: INC DE LD A,D CP high +(ATT16) Jr NZ,logo_draw ret ;In my code this is a subroutine ; this uses slightly different data. from the original. Part 4 is all the code placed together. (a working example)
  18. Part 3) I have not forgotten part 2a. (numbers quoted are approximations for the size of data fields. They are approximations not definite numbers) We are drawing the impossible triangle logo on the screen. And for most new iterations of the game we change the graphics to incorporate a new heading text. This is ok if we are restricting ourselves to one boring title screen. But it necessitates redrawing the logo each time to have the new text in it. It is easier to separate the logo from the text graphics. Then any editing done to the text, does not change the way we store the logo. We can compress the logo and leave the logo alone for each and every edit. We can also have multiple title screens and the logo can be placed behind any of the new text we generate. This at first looks to be counter productive. We now have two sets of data to compress and probably need two routines and two sets of set up code. One for the logo and one for the text. I admit it does seem strange, but I wanted the ability to have multiple screens, and separating the data and the text overlay revealed a feature of the logo that has been buried due to the nature of the graphics data presented. This is the revelation that the logo is generated from repeating graphics. Every value in the logo data is repeated. and this revelation means we can do an instant halving of the logo data. Yes the immediate reduction from 512 bytes of data to only 256 bytes of data, just because of this fact. We can then off course compress the half size logo. This will reduce the data to 84 (approximate) bytes... Read that number again 84 (approximate) bytes of data for the naked logo. Which makes the original 512 bytes data look a big waste of space. But hang on we now have no text over laying the logo. We need to add that data onto the logo data. The text overlay spoils the figures. The text overlay will consume a lot of data and we do need a quick and easy method of changing the text. Unless you are up to writing yourself an editor to do so. I settled on a simple bit pattern for the overlay text data, one that is visual and easy to edit. Pasmo the assembler does not make the layout of this data easy, but it is still easy enough to edit. The layout consists of Bits within a byte. Since a byte has eight bits, we can write out four bytes in binary and it can represent the 32 attribute squares across the screen. This data table for the text will use 16*4=64 bytes to define the overlay of text on the screen. It is data that is easy to edit without any other help. logo_overlay db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00100010b,11111000b,10001111b,00011110b db 00100010b,10001001b,01001000b,10100000b db 00111110b,11100010b,00101000b,10011100b db 00100010b,10001011b,11101000b,10000010b db 00100010b,11111010b,00101111b,00111100b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db 00000000b,00000000b,00000000b,00000000b db $ff ; manual inspection for value Proportional spaced font, as used in this forum will change the look of the data presented above. But I hope you can still read the word HEADS in the binary data. And finally we need a method of placing the above data on top of the expanded logo data. Which is as follows. text_overlay: ld hl,ATT0 ld de,logo_overlay ld c,FLASH+RED+8*YELLOW text: ld a,(de) cp 255 jr z,graphic ; or return (depends on how this is set up) ld b,8 ;width of data byte text1: rlca ;bit out jr nc,clear ld (hl),c clear: inc hl djnz text1 inc de jr text The end of the routine graphic: ; the routine above is just 25 bytes (approximate) ----------------------------------------------------------------------------------- So we can draw the logo with its overlay of text in this sequence Draw logo (84 bytes approx of data) onto the attribute area of the screen overlay the text (64 bytes of text) onto the attribute area of the screen. then translate the combined attribute data into the graphics needed (part 2b) The two expansion routine are 53 (approx) for the logo draw routine and 25 bytes for the logo overwrite routine. ------------------------------------------------------------------------ A new screen only requires new text data, so we can generate a new logo screen for 64 bytes plus its set up data. We still save hundreds of bytes on the basic data.....
  19. Addendum:- to the compression of data part 1 and 2 I made no attempt at explaining what the compression routine is doing and no attempt at how I manage to compress the data. I started off by just looking at the data and trying to see patterns. No obvious patterns were evident. I then looked at the spread of data. This is just looking at how many values are in the data that I want to compress. In the lower screen attribute data there are less than 16 different values, so I can immediately assign 4 bits to the spread of data. This leaves four bits in a byte. Which has a range of 0 to 15. If I assign those four bits as a counter then I can increase in range from 1 to 16. There being no point in including a nothing count. The method picked also needs the data to be repetitious, having long enough runs of data to have a running count. If the data changes value often, then this method starts to fail. The failure means the data does not compress, but does not take up more space than the uncompressed data. ( this ignores the code to uncompress the data) Now lets look at some of the data DEFB $46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46 ;line 1 DEFB $46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46 ;line 2 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;line 3 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;line 4 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;line 5 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;line 6 DEFB $01,$02,$03,$04,$05,$06,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07 ;line 7 bottom_translate: ;--- 0---1----2----3----4-----5----6----7----8-----9----a----b--- c db 0,$01,$02,$03,$04,$05,$06,$07,$46,$45,$41,$43,$44 Notice bottom translate has a row of numbers written above each of the values in the DB statement. These numbers correspond to the numbers position in the data. The values in the bottom translate are all the differing values in the data we are compressing. Now looking at the data:- The line1 comprises of 16 identical $46. From the bottom translate table we can see that $46 is at an offset of 8 To compress line1 of data we write $F8. The $Fx part of the compression represents the value repeated $f times more- 16 values in total The $x8 part represents the value at offset 8 in the bottom translate data - $46 To compress line2 of data we write $f8 again The $Fx part of the compression represents the value repeated $f times more - 16 values in total The $x8 part represents the value at offset 8 in the bottom translate data - $46 To compress line3 of data we write $F0 The $Fx part of the compression represents the value repeated $f times more - 16 values in total The $x0 part represents the value at offset 0 in the bottom translate data - $00 To compress line4 of data we write $F0 The $Fx part of the compression represents the value repeated $f times more - 16 values in total The $x0 part represents the value at offset 0 in the bottom translate data - $00 To compress line5 of data we write $F0 The $Fx part of the compression represents the value repeated $f times more - 16 values in total The $x0 part represents the value at offset 0 in the bottom translate data - $00 To compress line6 of data we write $F0 The $Fx part of the compression represents the value repeated $f times more - 16 values in total The $x0 part represents the value at offset 0 in the bottom translate data - $00 line7 gets a bit more complicated, here the data is changing and we do not have big repeats so compression breaks down. the first value on line 7 is $01 this compresses to $01 The $0x part of the compression represents the value repeated $0 times more - 1 value in total The $x1 part represents the value at offset 1 in the bottom translate data - $01 the second value on line 7 is $02 this compresses to $02 The $0x part of the compression represents the value repeated $0 times more - 1 value in total The $x2 part represents the value at offset 2 in the bottom translate data - $02 the third value on line 7 is $03 this compresses to $03 The $0x part of the compression represents the value repeated $0 times more - 1 value in total The $x3 part represents the value at offset 3 in the bottom translate data - $03 we can slowly go through all the data and visually compress the data Edited to reformat some data - the data layout is compromised by proportional spaced fonts
  20. Part 2) I write code out of curiosity. So after the quick attribute compress. I wondered how much that routine would compress the logo. The methods I have used before are different in the way they compress, but sometimes just taking a different path shows a better route. So the curiosity part of me did the compression. These compression's are done from visual translations. e.g. I look at the data and work the numbers out. The observant will have noticed that in part 1) there is a label called "draw_logo_loop" and a reference to "logo_translate", which was a good indication that I had written the code and worked out the data. so here is the same kind of data and code for the logo as for the bottom attributes ld de,ATT0 ld ix,LOGO_DAT ld hl,logo_translate call expand ; the routine shown in part 1 logo_translate: ;---------- 0---1----2----3----4-----5----6----7----8-----9----a----b--- c db $00,$28,$05,$d3,$2d,$25,$24,$09,$29,$2c,$04,$08 ;compressed top screen attributes for the logo LOGO_DAT DB $f0,$f0 DB $f0,$f0 DB $f0,$10,$11,$12,$90 DB $30,$23,$00,$23,$00,$23,$00,$01,$23,$05,$23,$00,$23,$30 DB $40,$03,$10,$03,$30,$03,$11,$04,$03,$15,$06,$03,$30,$03,$40 DB $40,$03,$10,$23,$00,$01,$03,$14,$05,$23,$06,$23,$10,$03,$40 DB $40,$03,$10,$03,$00,$11,$04,$03,$15,$16,$0a,$03,$06,$03,$30,$03,$40 DB $30,$13,$10,$23,$04,$05,$03,$16,$0a,$23,$06,$23,$10,$03,$40 DB $70,$18,$14,$19,$1a,$10,$17,$16,$90 DB $70,$17,$18,$14,$12,$10,$17,$16,$90 DB $50,$03,$00,$1b,$03,$07,$03,$08,$03,$04,$12,$03,$07,$06,$03,$20,$03,$50 DB $50,$03,$20,$03,$0b,$03,$07,$03,$08,$14,$03,$07,$06,$03,$20,$03,$50 DB $50,$03,$00,$03,$00,$03,$00,$03,$0b,$03,$07,$18,$03,$07,$06,$43,$50 DB $50,$03,$00,$03,$00,$03,$00,$03,$00,$03,$0b,$17,$03,$07,$16,$00,$03,$70 DB $50,$43,$00,$03,$00,$13,$03,$0b,$23,$06,$00,$03,$70 DB $f0,$10,$1b,$1a,$90 DB $ff Not bad in compression the logo translate uses 12 bytes, while the logo_dat uses vastly less than the 512 bytes of the original. (in the region of 192 bytes (exact figure is not important)) A possible saving of around 430 bytes for this data and the bottom attribute data. whilst this did work, I have modified the data at some point. And it might not work properly now. (it will be very close) What this illustrated to me was my other methods do a better job. In part 2b. I will re_write the part of the routine that draws the logo on the screen, this will save some more memory.
  21. New code:- based on a quick re_write as illustrated by the small heads demo. Part 1) The original uses a big data table to colour in the status area of the screen. And a similar table to colour in the colour table entry screen. That table is just as easy to compress, but I will ignore that data here and concentrate only on the lower screen attribute area and its data. The original lower screen data:- situated in memory in the original game at $9a00 ;9A00: Attributes for the bottom third of the screen bottom_att DEFB $46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46 DEFB $46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DEFB $01,$02,$03,$04,$05,$06,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07 DEFB $07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$06,$05,$04,$03,$02,$01 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DEFB $45,$45,$06,$06,$04,$04,$41,$41,$05,$05,$43,$43,$44,$44,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DEFB $45,$45,$06,$06,$04,$04,$41,$41,$05,$05,$43,$43,$44,$44,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 This data was moved to the lower screen with:- Code at $8907 LD HL,bottom_att ; 8907 ;L9A00 LD DE,ATT16 ; 890A ;$5A00 LD BC,$0100 ; 890D ; LDIR ; 8910 ; and code at $8b07 LD HL,bottom_att ;L8B07 ;L9A00 LD DE,ATT16 ; 8B0A ;$5A00 LD BC,$0100 ; 8B0D ; LDIR Both of these LDIR routines are replaced with a call to draw_bottom_att which is new code sitting in ram somewhere. This code is draw_bottom_att ld de,ATT16 ld ix,bottom_att ld hl,bottom_translate ; expander sub expand: ld (S_M_C_translate),hl draw_logo_loop ld a,(ix) inc ix cp 255 ret z S_M_C_translate equ $+1 ld hl,bottom_translate ;logo_translate << edited to remove this undefined label (in the code here) call indexer expand1 ld (de),a inc de djnz expand1 jr draw_logo_loop ;======================================================================= ; expander sub routine indexer ld c,a rrca rrca rrca rrca and 15 inc a ld b,a ld a,c and 15 ; + index into hl via "a" and return (hl+"a") in "a" index1 add a,l ld l,a adc a,h sub l ld h,a ld a,(hl) ret Looking at the lines and lines of code used above, you might be left wondering how all that saves any memory compared to a simple LDIR. A very quick count of the code comes in at 53 bytes. Now remember the original data was 256 bytes, so we need to be able to save at least 53 bytes. Any more than that and it is smaller in size. But we also get a subroutine which can be used in various ways as a bonus. So here is the original compressed bottom_att db $f8,$f8 db $f0,$f0 db $f0,$f0 db $01,$02,$03,$04,$05,$06,$97,$97,$06,$05,$04,$03,$02,$01 db $f0,$f0 db $19,$16,$14,$1a,$15,$1b,$1c,$10,$f0 db $19,$16,$14,$1a,$15,$1b,$1c,$10,$f0 db $f0,$f0 db $ff bottom_translate: ; 0 1 2 3 4 5 6 7 8 9 a b c db 0,$01,$02,$03,$04,$05,$06,$07,$46,$45,$41,$43,$44 The above is less than 60 bytes (around 56) which means the code plus the data is less than 120 bytes. a saving of over 130 bytes. It is possible to use this method to compress the logo. (with decent gains, but there are better ways)
  22. The heads are stored in a table, which stores only one definition for each head. The clever part is to use a pile of code to extract the heads, and reverse and shift each definition and place it over the original. Maybe not as noticeable but all willies animation is changed so that Willy has eight frames of animation in both directions.
  23. Using the source code I provided. I spent a day changing and deleting code. This is an illustration of what can be achieved in a day. Main point to this demo is the change in animation and definition of willy Addendum:- What else was changed 1) The clock routine. re written to correct the am/pm problem. (Smaller code) 2) sprite glitch and screen copying. Uses LDI and raster copy (visual update) 3) Constant update of status line and dancing willies. Only updates if needed (faster+smaller) 4) The room draw uses my method of expansion and no compares. (faster + a lot smaller) 5) deletion of all code asking for the colour code at the start (more free space) 6) rewrite of the cheat input (faster+smaller) 7) changed all the sprite routines (faster) 8) removed rope bug 9) Changed logo draw expansion routine (twice) (a lot smaller) 10) changed method of colouring in the lower screen (a lot smaller) 11) changed every LDIR over 20 bytes to ldi (faster) 12) changed every keyboard reference to ports. Removed usage of BC registers when reading ports (consistent-bug removal-smaller) How many variations of Willy, are their is in this demo. Ignoring the flying pig there are 16 definitions. HeadsJSW.tap
  24. Raw6jsw.zip View File This is just an assembly listing of Jet Set Willy, which is not the same as a disassembly. Since this uses the skoolkit disassembly as its basis, It has been placed here so it is not viewable to none members. The change from a disassembly makes the code a lot easier to understand and also a lot easier to edit. Submitter Norman Sword Submitted 06/21/2019 Category Other resources  
  25. JET SET WILLY SOURCE CODE I mentioned a long time ago that I would eventually upload a source code for Jet Set Willy. This I have done and the code is in the download section, under "other resources". The version is Raw6jsw.asm but the 6 is just indicating that 6 steps were needed in its evolution from a disassembly Hope its of use to someone. The listing will assemble in Pasmo and output the game....
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.