Jump to content
Jet Set Willy & Manic Miner Community

Norman Sword

Contributor
  • Posts

    618
  • Joined

  • Last visited

Everything posted by Norman Sword

  1. Halfway through typing this it posted, with an error message. Hence the retype on post #4
  2. The strike through fell off and is lying somewhere in cyberspace. The op codes in the listings which are unwanted have been rem'ed out and also struck through again. (just in case I paste and copy again) with that statement I am reminded that the original still has only the strike through. So I will edit that as well. Code with the unwanted parts will still work. But since it is not needed best rem'out in addition to the strike through. (or just deleted completely)
  3. Semantics:- Every version of the raster copy routine listed under "source code for JSW" does not use the "a" register. I subsequently added before and after the actual routine a part which modified the Block_Copy routine (which ever variant of the block copy routine as listed in each post). The raster copy routine still does not use the a register, but the modifying code before and after did use the "a" register. I have done the trivial change to each modifying addition to remove the usage of the "a" register throughout the whole raster copy.
  4. All the raster copy posts under the heading "source code for JSW" work as stated. None use the piece of code listed back in APRIL 2017 and quoted in post #62. Because you are reverting between differing pieces of code used over many years, I have expanded each reference to raster copy listed under "source code for JSW" to be self contained. Each and every version works and none use the "A" register.
  5. I have edited three posts to remove the conflict of BLOCK_MOVE32: being used with differing routines. The routine that uses a long line of ldi's and returns without decrementing the "A" register has had its labels changed That block move now uses the labels BLOCKX_MOVE32 and BLOCKX_MOVE31. the inclusion of the X mid label hopefully removing confusion between two very similar routines, which are mentioned sporadically over a few posts.
  6. since the source code for me is just a blank canvas to edit. I am not restricted to worrying about will a piece of code fit in here or there. If I delete a byte in the source code, I immediately have that byte and it can be used anywhere I want in the limits of the memory I am editing. The restrictions are removed. Block move ld hl,source ld de,destination ld bc,size ldir looking at this yet again, but from the no restrictions point of view. The best solution is slightly different Shift_block32: ; new label to distinguish from all the other code ldi Shift_block31 rept31 ldi endm jp pe,Shift_block32 ret we write the code out exactly as specified in JSW but we now use one more byte on each instance and rather than LDIR we use an extra byte and call Shift_block32 or Shift_block31 ; Depending on the value being divisible by 32 or one short This also does not use the "a" register- similar to LDIR on its own. This method also is as close to a replacement LDIR as we can generate in code, returning with the same parameters as would be set with LDIR. so LD HL,CHAR0 ;L869F ;$4000 LD DE,CHAR0+1 ; 86A2 ;$4001 LD BC,$1AFF ; 86A5 ; LD (HL),$00 ; 86A8 ; LDIR ; 86AA ; call shift_block31 This is faster again (marginally) but uses the same registers as the original I suppose you could modify this routine to use a similar raster copy routine as the one posted above. e.g. ----------------------------------------------------------------------------------------------------------------------------------------------------------- ;copy work and attribute screens ld hl, S_M_C_New_Mod ;place to modify ld (hl),$c9 ; modify in a "ret" ld hl,att_work ld de,ATT0 ;;;;ld b,0 ; this was set for usage in a different routine exx ld hl,ytable ld bc,128 ; must be a multiple of 32 ; this is 4*32 ;- that is 4 raster lines before the attributes are written in ;loop executed 128 times on each game loop raster: ld e,(hl) inc l push hl ld h,(hl) ld l,e ld d,h res 5,d call Shift_block32 ;executed 128 times on each game loop jp pe,n_raster exx ; this code is executed 16 times on each game loop ;;;;ld c,32 ; this was set for usage in a different routine call Shift_block32 exx inc b n_raster: pop hl inc l jr nz,raster ld hl,S_M_C_New_Mod ;place to midify Ld (hl),$ea ;opcode for Jp PE,xx rest of code ----------------------------------------------------------------------------------------- Shift_block32: ; new label to distinguish from all the other code ldi Shift_block31: rept31 ldi endm S_M_C_New_Mod Equ $ jp pe,Shift_block32 ;opcode toggled between ( "ret" ) and ( "jp pe,xx" ) ret
  7. Since the last posted raster copy is a lot faster without using the "a" register and we don't want to supply two lots of LDI routines..... Lets just chop up the old LDI routine and make that return without modifying the "a" register. Then we have only one LDI routine. The chopping up of the routine takes 5 bytes to modify and five bytes to put it back. Since these two modifications are executed only once, it is a lot faster than having to re-use the "a" register inside the loop. The Block move from post #58 BLOCK_MOVE32: ldi BLOCK_MOVE31 ldi rept 30 ldi endm S_M_C_fast: equ $ dec a ; change this opcode jr nz,BLOCK_MOVE32 ret ;----------------------------------------------- The raster copy is expanded to become ;modify ld hl,S_M_C_fast ;position to modify ld (hl),$C9 ;opcode value for ret >>>>>>>>>>>>>>>>>>>>>>>>>>>>> ;copy work and attribute screens ld hl,att_work ld de,ATT0 ;;;;;; ld b,0 ; this was set for usage in a different routine exx ld hl,ytable ld bc,128 ; must be a multiple of 32 ; this is 4*32 ;- that is 4 raster lines before the attributes are written in ;loop executed 128 times on each game loop raster: ld e,(hl) inc l push hl ld h,(hl) ld l,e ld d,h res 5,d call BLOCK_MOVE32 ;executed 128 times on each game loop jp pe,n_raster exx ; this code is executed 16 times on each game loop ;;;;ld c,32 ; this was set for usage in a different routine call BLOCK_MOVE32 exx inc b n_raster: pop hl inc l jr nz,raster >>>>>>>>>>>>>>>>>>>>>>>>>>>> ;restore back to old ld hl,S_M_C_fast ld (hl),$3d ;opcode value for dec a ; rest of code which leaves only one ldi routine. That's today's version.....
  8. The original with the "a" register passing the amount of copy was in response to the limited space available in the source code. ld hl,source ld de,destin ld bc,count ldir being 11 bytes in size.. modified to be ld hl,source ld de,destin ld a,count/32 call BLOCK_MOVE32 ; which uses "a" as a counter which is also 11 bytes in size and can be easily fitted into the same size space. IGNORING the raster copy routine for now. Lets look at the format of the original BLOCK_MOVE32 which was BLOCK_MOVE32: ldi BLOCK_MOVE31 ldi rept 30 ldi endm dec a jr nz,BLOCK_MOVE32 ret This has two labels BLOCK_MOVE32 and BLOCK_MOVE31. It could be written out to have every label from BLOCK_MOVE32 down to BLOCK_MOVE01. It doesn't because the other labels would be used infrequently and I am lazy. I can not be bothered writing them all out. Problems using the above routine to move odd amounts........ The bulk of block moves in the game are multiples of 32 and a call to BLOCK_MOVE32 does the job. However we also have cases where we copy a block in a block copy sequence such as. : this code will clear the screen attributes to black on black ld hl,ATT0 ld de,ATT0+1 ld bc,$2ff ld (hl),0 ldir this might seem to not be of the same format. we are copying here $2ff of data which is not a multiple of 32. But look again at the amount. I can re write $2ff in a different way, such as $300-1. Clearly the same value and clearly this is very similar to the format being used in the standard block move. so lets adapt that code ld hl,ATT0 ld de,ATT0+1 ld (hl),0 ld a,$300/32 ; MOVE $300 bytes call BLOCK_MOVE31 ;MOVE $300 bytes -1 e.g. move $2ff bytes <<<<<<< NOTE BLOCK_MOVE31 this has moved $2ff bytes which is what we wanted.... In jsw the vast majority of block moves want to move either a multiple of 32 bytes or one short of a multiple of 32 bytes. Which is why I only expanded BLOCK_MOVE32 and BLOCK_MOVE31 out in the routine to move the data. Going into jsw we have ... And this is just a quick grab from the source code. For all the big block moves LD HL,CHAR0 ;L869F ;$4000 LD DE,CHAR0+1 ; 86A2 ;$4001 LD BC,$1AFF ; 86A5 ; ld a,$1b00/32 LD (HL),$00 ; 86A8 ; LDIR ; 86AA ; call BLOCK_MOVE31 LD HL,code_att ; 86E8 ;L9B80 LD DE,ATT8 ; 86EB ;$5900 LD BC,$0080 ; 86EE ; ld a,$80/32 LDIR ; 86F1 ; call BLOCK_MOVE32 LD HL,CHAR0 ;L8813 ;$4000 LD DE,CHAR0+1 ; 8816 ;$4001 LD BC,$17FF ; 8819 ; ld a,$1800/32 LD (HL),$00 ; 881C ; LDIR call BLOCK_MOVE31 LD HL,logo_att ; 8820 ;L9800 LD BC,$0300 ; 8823 ; ld a,$300/32 LDIR ; 8826 ; call BLOCK_MOVE32 ;recolour line 19 LD HL,ATT19 ; 8828 ;$5A60 LD DE,ATT19+1 ; 882B ;$5A61 LD BC,$001F ; 882E ; ld a,$20/32 LD (HL),$46 ; 8831 ; LDIR call BLOCK_MOVE31 LD HL,ATT19 ; 88B8 ;$5A60 LD DE,ATT19+1 ; 88BB ;$5A61 LD BC,$001F ; 88BE ; ld a,$20/32 LD (HL),$4F ; 88C1 ; LDIR ; 88C3 ; call BLOCK_MOVE31 LD HL,bottom_att ; 8907 ;L9A00 LD DE,ATT16 ; 890A ;$5A00 LD BC,$0100 ; 890D ; ld a,$100 LDIR call BLOCK_MOVE32 LD DE,room_layout ; 891A ;L8000 LD BC,$0100 ; 891D ; ld a,$100/32 LDIR call BLOCK_MOVE32 LD HL,CHAR16 ; 8958 ;$5000 LD DE,CHAR16+1 ; 895B ;$5001 LD BC,$07FF ; 895E ; ld a,$800 LD (HL),$00 ; 8961 ; LDIR call BLOCK_MOVE31 LD HL,att_master ; 89B0 ;$5E00 LD DE,att_work ; 89B3 ;$5C00 LD BC,$0200 ; 89B6 ; ld a,$200/32 LDIR call BLOCK_MOVE32 LD HL,char_master ; 89BB ;$7000 LD DE,char_work ; 89BE ;$6000 LD BC,$1000 ; 89C1 ; ld a,$1000/32 LDIR call BLOCK_MOVE32 LD HL,char_work ;L89F5 ;6000 LD DE,CHAR0 ; 89F8 ;$4000 LD BC,$1000 ; 89FB ; ld a,$1000/32 LDIR ; 89FE ; call BLOCK_MOVE32 LD HL,att_work ; 8A1A ;$5C00 LD DE,att_work+1 ; 8A1D ;$5C01 LD BC,$01FF ; 8A20 ; ld a,$200/32 LD (HL),A ; 8A23 ; <<<<<< a reg problem LDIR call BLOCK_MOVE31 LD HL,att_work ;L8A26 ;$5C00 LD DE,ATT0 ; 8A29 ;$5800 LD BC,$0200 ; 8A2C ; ld a,$200/32 LDIR ; 8A2F ; call BLOCK_MOVE32 LD HL,bottom_att ;L8B07 ;L9A00 LD DE,ATT16 ; 8B0A ;$5A00 LD BC,$0100 ; 8B0D ; ld a,$100/32 LDIR call BLOCK_MOVE32 LD HL,ATT0 ;L8C03 ;$5800 LD DE,ATT0+1 ; 8C06 ;$5801 LD BC,$01FF ; 8C09 ; ld a,$200/32 LD (HL),A ; 8C0C ; <<<<<< problems here with the a register LDIR call BLOCK_MOVE31 LD HL,CHAR0 ;L8C4A ;$4000 LD DE,CHAR0+1 ; 8C4D ;$4001 LD BC,$0FFF ; 8C50 ; ld a,$1000/32 LD (HL),$00 ; 8C53 ; LDIR call BLOCK_MOVE31 LD HL,att_master ; 96F4 ;$5E00 LD DE,ATT0 ; 96F7 ;$5800 LD BC,$0200 ; 96FA ; ld a,$200/32 LDIR ; 96FD ; call BLOCK_MOVE32 LD HL,CHAR0 ; 96FF ;$4000 LD DE,CHAR0+1 ; 9702 ;$4001 LD BC,$0FFF ; 9705 ; ld a,$1000/32 LD (HL),$18 ; 9708 ; LDIR call BLOCK_MOVE31 The above illustrates why we have BLOCK_MOVE32 and BLOCK_MOVE31 . In a game like JSW we are moving multiples of 32 in the vast majority of cases. Only two of the above cases causes a pause and a need to work out how to preserve the a register. (it might contain more instances where the "A" register needs to be preserved) very easy to change and very easy to work out. The problem then comes with , how we manage the raster copy. Which in the recent posting uses a differnt BLOCK_MOVE
  9. Each example I write is self contained unless otherwise stated. The last example I wrote uses no check on the block of 32 ldi's and just returns. The above code "as used in post 54" is an old example which does use "a" as a counter. Give me five minutes and I will test the example as I wrote it and get back to you. But I think it will work as written ;----------------------------------------------------------------------------------------------------------------------- Works exactly as I said it would.
  10. Standard assembler directives:- One of the biggest helps is the macro language that you can build into pieces of standard code that are often used. The standard macro is as such: silly: Macro param1,param2,param3 ld hl,param1 ld de,param2 ld bc,param3 ldir endm. The macro here is defined by the label silly. Every time the word silly is seen in the source code it will replace it with all the code between the MACRO and endm. The word endm is shorthand for "end macro" So How do I use silly in a piece of code ( don't forget this example is called silly, because it is a silly example) I simply write in to the assemble code silly ATT0,ATT1,32 when the code is assembled the above will be substituted with ld hl,ATT0 ld de,ATT1 ld bc,32 LDIR which is the macro expanded and each of the labels re placed with the parameter passed to the macro. e.g ld hl,ATT0 ; here param1 is replaced with ATT0 ld de,ATT1 ; here param2 is replaced with ATT1 ld bc,32 ; here param3 is replaced with 32 LDIR Macros are very helpful to expand code out that is repetitive. another form of macros. is the rept directive. (rept = repeat). so getting back to to the original querry rept 32 ;repeat 32 times ldi endm ; end macro means repeat the line of code between the rept directive and then endm directive 32 times we can create big blocks of code by repeating and nesting : (these examples are just examples not taken from any code) so lets look at move macro count rept count ld a,(hl) ld (de),a inc hl inc d endm endm we can in the assembler now write move 8 and this will generate the inline code ld a,(hl) ld (de),a inc hl inc d ld a,(hl) ld (de),a inc hl inc d ld a,(hl) ld (de),a inc hl inc d ld a,(hl) ld (de),a inc hl inc d ld a,(hl) ld (de),a inc hl inc d ld a,(hl) ld (de),a inc hl inc d ld a,(hl) ld (de),a inc hl inc d ld a,(hl) ld (de),a inc hl inc d ; which is the quickest way of doing this operation possible. we have no loop counter. The above probably seems to be pointless, but consider a piece of code I have mentioned several times and written out an example of once. which is the stack copy. To speed up a stack copy we set up a nest macro similar to the example above. When the macro is expanded we end up with a big block of inline code. (the expansion can end up with 500 or more lines of code) we can also pass counters that can be used and acted upon. Macro's are also literally expanded and can cause no end of problems when the expansion does not seem to do what is wanted. ;-------------------------- TOO MUCH INFORMATION ------------------------------------- short answer REPT is short for REPeaT ENDM is short for END Macro
  11. Yes the BLOCKX_MOVE32 will clear the Parity Even Flag (PE flag) if and only if the last LDI counts the register pair "BC" down to zero. Which is why the line that loads BC with 128 is specifically indicating that "BC" must be set to a multiple of 32. If this was changed to a value which is not divisible by 32. Then the attributes would never be drawn, because the ( "JP PE,n_raster" ) would always branch to ( "n_raster" )
  12. Using a call and a ret to 32 consecutive LDI's . A variation on my last version would probably do what you want.... And this assumption is based on a quick scan of all the changes listed in the above posts. ;copy work and attribute screens ld hl,att_work ld de,ATT0 ;;;; ld b,0 ; this was set for usage in a different routine exx ld hl,ytable ld bc,128 ; must be a multiple of 32 ; this is 4*32 ;- that is 4 raster lines before the attributes are written in ;loop executed 128 times on each game loop raster: ld e,(hl) inc l push hl ld h,(hl) ld l,e ld d,h res 5,d call BLOCKX_MOVE32 ;executed 128 times on each game loop jp pe,n_raster exx ; this code is executed 16 times on each game loop ;;;; ld c,32 ; this was set for usage in a different routine call BLOCKX_MOVE32 exx inc b n_raster: pop hl inc l jr nz,raster ;Note the a register is not used in either routine --------------------------------------------------------------------- BLOCKX_MOVE32: rept 32 ldi endm ret ADDENDUM:- multiple reference through out these posts to BLOCK_MOVE32 or BLOCK_MOVE31.........I will go through all the posts and change the conflicting labels......In this post labels now called BLOCKX_MOVE32
  13. Re branching/ jumping and calling. The program counter is loaded during one of the clock cycles with data. This is the same with call's, Jump's and JR's. The number of clock cycles needed to set the data up is different. Once the program counter is loaded the next clock cycle we move to the new address. What this means is that the speed is fixed no matter where the Program Counter is asked to move to. A relative jump of 0 bytes is executed at the same speed as a relative jump of 127 bytes. Calls and jump's and I will also include ret's are similar the Program counter is loaded and the next clock cycle we execute the operand pointed at by the (possibly) changed Program counter. Each is acted on with no consideration of the amount of relative displacement from the old value. ---------------------------------------------------------------------------- I will re read the posts above this one.... And perhaps comment further.
  14. I would imagine you would end up with a large rule book. example 1:- S_M_C_counter1: equ $+1 ld a,12 inc a and 7 or 8 ld (S_M_C_counter1),a here the value varies between 8 and 15:- your example has failed, we never have a value of zero in the variable example 2:- S_M_C_opcode: inc a direction_switch equ $3c xor $3d ; this is ("inc a") xor ("dec a") ld hl,S_M_C_opcode ld a,(hl) xor direction_switch ld (hl),a here the opcode varies between either "inc a" or "dec a". the code is switching direction. again never zero ----------------------------------------------------- The circumstances can change from once instance to another. The S_M_C_ is alerting you to code that is modifying. The $-$ is making the statement that the value will be changed before the opcode is executed. In a lot of instances we must have an opcode or an initial value. In those cases the value is inserted or the opcode written out. I suppose it is similar to saying a block move is always in this format:- ld hl,source ld de,destination ld bc, count LDIR when the reality says it is a lot of the time, but the variations are vast.
  15. The opcode decides the size of the data used. I can not load the "A" register with 16 bits. In a similar way if I was to specify ld hl,2. I am always loading 16 bits never 8 bits. The $-$ is specifying 0. It is indicating a null value. The opcode is specifying the size of the data. you can not specify ld d,$- the syntax is wrong. you could specify ld d,-$ LD D,$ or any variation on that will load "D" with the low value of the program counter at that point. The value would change on each and every edit of the code if the program counter at that point is changed by edits. The $-$ is a consistent and fixed value of zero If you write enough code you will end up having to use references to data that you do not have. E.g. call $-$ which is a call to somewhere, but you do not have the address. The address is supplied by some other piece of code and in any case can move. So an address needs to be supplied to the assembler $-$ is as good an address as going out of your way to fabricate an address just to assemble the code.
  16. 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.
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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+
  24. 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)
  25. 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
×
×
  • Create New...

Important Information

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