Norman Sword Posted June 21, 2019 Report Share Posted June 21, 2019 JET SET WILLY SOURCE CODEI 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 disassemblyHope its of use to someone.The listing will assemble in Pasmo and output the game.... jetsetdanny, IRF and Spider 2 1 Quote Link to comment Share on other sites More sharing options...
Spider Posted June 21, 2019 Report Share Posted June 21, 2019 (edited) Just seen and approved it, thanks Norman. :) Its generated its own 'support/comments' topic as most downloads submissions do, so we can either use this topic here you've started or that auto generated one if you prefer. I'll just simply close the unused one to prevent duplication/confusion. EDIT... Decided to close the other 'auto generated' topic (with a link to this one) to use instead as its preferable I think, partly as its got more information and partly as its more up-to-date too. Edited July 3, 2019 by Spider jetsetdanny 1 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 2, 2019 Author Report Share Posted July 2, 2019 (edited) 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 Edited July 2, 2019 by Norman Sword IRF, Spider and jetsetdanny 3 Quote Link to comment Share on other sites More sharing options...
IRF Posted July 2, 2019 Report Share Posted July 2, 2019 (edited) Are all the different heads stored in a table? You could almost call this "JSW: The Worzel Gummidge Edition"! :lol: Edited July 2, 2019 by IRF Spider and jetsetdanny 2 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 2, 2019 Author Report Share Posted July 2, 2019 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. jetsetdanny and IRF 2 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 2, 2019 Author Report Share Posted July 2, 2019 (edited) 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_attDEFB $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 ;$5A00LD BC,$0100 ; 890D ;LDIR ; 8910 ; and code at $8b07 LD HL,bottom_att ;L8B07 ;L9A00 LD DE,ATT16 ; 8B0A ;$5A00LD BC,$0100 ; 8B0D ;LDIRBoth of these LDIR routines are replaced with a call to draw_bottom_att which is new code sitting in ram somewhere.This code isdraw_bottom_att ld de,ATT16 ld ix,bottom_att ld hl,bottom_translate; expander subexpand: ld (S_M_C_translate),hldraw_logo_loop ld a,(ix) inc ix cp 255 ret zS_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 routineindexer 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) retLooking 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,$f8db $f0,$f0db $f0,$f0db $01,$02,$03,$04,$05,$06,$97,$97,$06,$05,$04,$03,$02,$01db $f0,$f0db $19,$16,$14,$1a,$15,$1b,$1c,$10,$f0db $19,$16,$14,$1a,$15,$1b,$1c,$10,$f0db $f0,$f0db $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,$44The 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) Edited July 3, 2019 by Norman Sword jetsetdanny, IRF and Spider 3 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 2, 2019 Author Report Share Posted July 2, 2019 (edited) 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 logoLOGO_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. Edited March 11, 2020 by Norman Sword jetsetdanny, IRF and Spider 3 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 3, 2019 Author Report Share Posted July 3, 2019 (edited) Addendum:- to the compression of data part 1 and 2I 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 dataDEFB $46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46 ;line 1DEFB $46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46,$46 ;line 2DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;line 3DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;line 4DEFB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;line 5DEFB $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--- cdb 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 - $46To 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 Edited March 11, 2020 by Norman Sword Spider, IRF and jetsetdanny 3 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 3, 2019 Author Report Share Posted July 3, 2019 (edited) 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,00000000bdb 00000000b,00000000b,00000000b,00000000bdb 00000000b,00000000b,00000000b,00000000bdb 00000000b,00000000b,00000000b,00000000bdb 00000000b,00000000b,00000000b,00000000bdb 00000000b,00000000b,00000000b,00000000bdb 00000000b,00000000b,00000000b,00000000bdb 00100010b,11111000b,10001111b,00011110bdb 00100010b,10001001b,01001000b,10100000bdb 00111110b,11100010b,00101000b,10011100bdb 00100010b,10001011b,11101000b,10000010bdb 00100010b,11111010b,00101111b,00111100bdb 00000000b,00000000b,00000000b,00000000bdb 00000000b,00000000b,00000000b,00000000bdb 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 bytetext1: rlca ;bit out jr nc,clear ld (hl),cclear: 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..... Edited July 3, 2019 by Norman Sword jetsetdanny, Spider and IRF 3 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted July 4, 2019 Author Report Share Posted July 4, 2019 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_skipThese 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),alogo1_graphic ld a,e rlca rlca rlca and 8call 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,clogo_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) IRF 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.