diff --git a/build.sh b/build.sh index 2bae963..346f794 100755 --- a/build.sh +++ b/build.sh @@ -31,8 +31,8 @@ $c1541 \ -write firebird \ -write gma1.modified gma1 \ -write gma3 \ - -write gma4 \ - -write gma5 \ + -write gma4.encrypted gma4 \ + -write gma5.encrypted gma5 \ -write gma6.encrypted gma6 # Report checksums @@ -62,8 +62,8 @@ $c1541 \ -write byebyejulie \ -write gma1.modified gma1 \ -write gma3 \ - -write gma4 \ - -write gma5 \ + -write gma4.encrypted gma4 \ + -write gma5.encrypted gma5 \ -write gma6.encrypted gma6 # Report checksums @@ -77,7 +77,7 @@ cd work cp ../original-disks/elite_+4_unpacked.prg . # Assemble the additional code required for flicker-free ships -$beebasm -i ../src/elite-flicker-free-plus4.asm -v > compile.txt +$beebasm -i ../src/elite-flicker-free-plus4.asm -v >> compile.txt # Modify the main game code $python ../src/elite-modify-plus4.py diff --git a/src/elite-flicker-free-plus4.asm b/src/elite-flicker-free-plus4.asm index 1a31ad8..1ea281c 100644 --- a/src/elite-flicker-free-plus4.asm +++ b/src/elite-flicker-free-plus4.asm @@ -44,7 +44,6 @@ GUARD &CE00 \ Guard against assembling over memory used by game XX1 = $0009 INWK = $0009 XX19 = $002A -CNT = $0030 K3 = $0035 K4 = $0043 XX0 = $0057 @@ -56,6 +55,7 @@ X2 = $006D Y2 = $006E XX12 = $0071 XX17 = $009F +CNT = $00AA XX4 = $00AD XX20 = $00AE XX14 = $00FB diff --git a/src/elite-flicker-free.asm b/src/elite-flicker-free.asm index c9fa1c1..6b9295d 100644 --- a/src/elite-flicker-free.asm +++ b/src/elite-flicker-free.asm @@ -19,7 +19,7 @@ \ \ ****************************************************************************** -GUARD &CE00 \ Guard against assembling over memory used by game +GUARD $CE00 \ Guard against assembling over memory used by game \ ****************************************************************************** \ @@ -44,7 +44,6 @@ GUARD &CE00 \ Guard against assembling over memory used by game XX1 = $0009 INWK = $0009 XX19 = $002A -CNT = $0030 K3 = $0035 K4 = $0043 XX0 = $0057 @@ -56,6 +55,7 @@ X2 = $006D Y2 = $006E XX12 = $0071 XX17 = $009F +CNT = $00AA XX4 = $00AD XX20 = $00AE XX14 = $00FB @@ -64,6 +64,26 @@ LL75 = $9FB8 LL30 = $AB91 Y = 72 +K = $0077 +LSP = $007E +K5 = $0085 +K6 = $0089 +XX13 = $00A2 +TYPE = $00A5 +FLAG = $00A9 +CNT2 = $00AB +STP = $00AC +T = $00BB +SWAP = $06F4 +LSX2 = $26A4 +LSY2 = $27A4 +PL9_2 = $7DA4 +PL26 = $7DE0 +PLL4 = $7E5F +CIRCLE = $8044 +WP1 = $80F5 +LL145 = $A013 + \ ****************************************************************************** \ \ Name: SHPPT @@ -263,7 +283,259 @@ ORG $A178 SAVE "ll155.bin", LL155, P% -ORG $CCE0 +\ ****************************************************************************** +\ +\ Name: BLINE +\ Type: Subroutine +\ Category: Drawing circles +\ Summary: Draw a circle segment and add it to the ball line heap +\ +\ ****************************************************************************** + +ORG $2977 + +GUARD $2A12 + +.BLINE + + TXA \ Set K6(3 2) = (T X) + K4(1 0) + ADC K4 \ = y-coord of centre + y-coord of new point + STA K6+2 \ + LDA K4+1 \ so K6(3 2) now contains the y-coordinate of the new + ADC T \ point on the circle but as a screen coordinate, to go + STA K6+3 \ along with the screen y-coordinate in K6(1 0) + + LDA FLAG \ If FLAG = 0, jump down to BL1 + BEQ BL1 + + INC FLAG \ Flag is &FF so this is the first call to BLINE, so + \ increment FLAG to set it to 0, as then the next time + \ we call BLINE it can draw the first line, from this + \ point to the next + +.BL5 + + JSR DrawPlanetLine \ Draw the current line from the old planet + + \ The following inserts a &FF marker into the LSY2 line + \ heap to indicate that the next call to BLINE should + \ store both the (X1, Y1) and (X2, Y2) points. We do + \ this on the very first call to BLINE (when FLAG is + \ &FF), and on subsequent calls if the segment does not + \ fit on-screen, in which case we don't draw or store + \ that segment, and we start a new segment with the next + \ call to BLINE that does fit on-screen + + LDY LSP \ If byte LSP-1 of LSY2 = &FF, jump to BL7 to tidy up + LDA #&FF \ and return from the subroutine, as the point that has + CMP LSY2-1,Y \ been passed to BLINE is the start of a segment, so all + BEQ BL7 \ we need to do is save the coordinate in K5, without + \ moving the pointer in LSP + + STA LSY2,Y \ Otherwise we just tried to plot a segment but it + \ didn't fit on-screen, so put the &FF marker into the + \ heap for this point, so the next call to BLINE starts + \ a new segment + + INC LSP \ Increment LSP to point to the next point in the heap + + BNE BL7 \ Jump to BL7 to tidy up and return from the subroutine + \ (this BNE is effectively a JMP, as LSP will never be + \ zero) + +.BL1 + + LDA K5 \ Set XX15 = K5 = x_lo of previous point + STA XX15 + + LDA K5+1 \ Set XX15+1 = K5+1 = x_hi of previous point + STA XX15+1 + + LDA K5+2 \ Set XX15+2 = K5+2 = y_lo of previous point + STA XX15+2 + + LDA K5+3 \ Set XX15+3 = K5+3 = y_hi of previous point + STA XX15+3 + + LDA K6 \ Set XX15+4 = x_lo of new point + STA XX15+4 + + LDA K6+1 \ Set XX15+5 = x_hi of new point + STA XX15+5 + + LDA K6+2 \ Set XX12 = y_lo of new point + STA XX12 + + LDA K6+3 \ Set XX12+1 = y_hi of new point + STA XX12+1 + + JSR LL145 \ Call LL145 to see if the new line segment needs to be + \ clipped to fit on-screen, returning the clipped line's + \ end-points in (X1, Y1) and (X2, Y2) + + BCS BL5 \ If the C flag is set then the line is not visible on + \ screen anyway, so jump to BL5, to avoid drawing and + \ storing this line + + LDA SWAP \ If SWAP = 0, then we didn't have to swap the line + BEQ BL9 \ coordinates around during the clipping process, so + \ jump to BL9 to skip the following swap + + LDA X1 \ Otherwise the coordinates were swapped by the call to + LDY X2 \ LL145 above, so we swap (X1, Y1) and (X2, Y2) back + STA X2 \ again + STY X1 + LDA Y1 + LDY Y2 + STA Y2 + STY Y1 + +.BL9 + + LDY LSP \ Set Y = LSP + + LDA LSY2-1,Y \ If byte LSP-1 of LSY2 is not &FF, jump down to BL8 + CMP #&FF \ to skip the following (X1, Y1) code + BNE BL8 + + \ Byte LSP-1 of LSY2 is &FF, which indicates that we + \ need to store (X1, Y1) in the heap + + JSR DrawPlanetLine \ Draw the current line from the old planet + + LDA X1 \ Store X1 in the LSP-th byte of LSX2 + STA LSX2,Y + + LDA Y1 \ Store Y1 in the LSP-th byte of LSY2 + STA LSY2,Y + + INY \ Increment Y to point to the next byte in LSX2/LSY2 + +.BL8 + + LDA #&FF \ Set bit 7 of K3+8 so we do not draw the current line + STA K3+8 \ in the call to DrawPlanetLine, but store the + \ coordinates so we we can check them below + + JSR DrawPlanetLine+4 \ Calculate the current line from the old heap, but do + \ not draw it, but store the coordinates (X1, Y1) and + \ (X2, Y2) in K3+4 to K3+7 + + LDA X2 \ Store X2 in the LSP-th byte of LSX2 + STA LSX2,Y + + LDA Y2 \ Store Y2 in the LSP-th byte of LSX2 + STA LSY2,Y + + INY \ Increment Y to point to the next byte in LSX2/LSY2 + + STY LSP \ Update LSP to point to the same as Y + + JSR DrawNewPlanetLine \ Draw a line from (X1, Y1) to (X2, Y2), but only if it + \ is different to the old line in K3+4 to K3+7 + + LDA XX13 \ If XX13 is non-zero, jump up to BL5 to add a &FF + BNE BL5 \ marker to the end of the line heap. XX13 is non-zero + \ after the call to the clipping routine LL145 above if + \ the end of the line was clipped, meaning the next line + \ sent to BLINE can't join onto the end but has to start + \ a new segment, and that's what inserting the &FF + \ marker does + +.BL7 + + LDA K6 \ Copy the data for this step point from K6(3 2 1 0) + STA K5 \ into K5(3 2 1 0), for use in the next call to BLINE: + LDA K6+1 \ + STA K5+1 \ * K5(1 0) = screen x-coordinate of this point +\LDA K6+2 \ +\STA K5+2 \ * K5(3 2) = screen y-coordinate of this point +\LDA K6+3 \ +\STA K5+3 \ They now become the "previous point" in the next call + + JMP PATCH3 \ Jump to patch to implement the commented out + \ instructions above, plus the rest of the routine + +SAVE "bline.bin", BLINE, P% + +\ ****************************************************************************** +\ +\ Name: PL9 (Part 1 of 3) +\ Type: Subroutine +\ Category: Drawing planets +\ Summary: Draw the planet, with either an equator and meridian, or a crater +\ +\ ****************************************************************************** + +ORG $7D8C + +GUARD $7DA4 + +.PL9 + + JSR CIRCLE \ Call CIRCLE to draw the planet's new circle + + BCS PL20A \ If the call to CIRCLE returned with the C flag set, + \ then the circle does not fit on-screen, so jump to + \ PL20A to remove the planet from the screen and return + \ from the subroutine + + LDA K+1 \ If K+1 is zero, jump to PL25 as K(1 0) < 256, so the + BEQ PL25 \ planet fits on the screen and we can draw meridians or + \ craters + +.PL20 + + JMP EraseRestOfPlanet \ We have drawn the new circle, so now we need to erase + \ any lines that are left in the ball line heap, before + \ returning from the subroutine using a tail call + +.PL20A + + JMP WPLS2 \ Call WPLS2 to remove the planet from the screen + +.PL25 + + LDA $1D0F \ Skip craters and meridians if not configured + BEQ PL20 + + JMP PATCH6 \ Jump to PATCH6 for the rest of the routine + +SAVE "pl9.bin", PL9, P% + +\ ****************************************************************************** +\ +\ Name: WPLS2 +\ Type: Subroutine +\ Category: Drawing planets +\ Summary: Remove the planet from the screen +\ +\ ****************************************************************************** + +ORG $80BB + +GUARD $80F5 + +.WPLS2 + + LDY LSX2 \ If LSX2 is non-zero (which indicates the ball line + BNE WP1 \ heap is empty), jump to WP1 to reset the line heap + \ without redrawing the planet + + STY XX14 \ Reset XX14 to the start of the ball line heap (we can + \ set this to 0 rather than 1 to take advantage of the + \ fact that Y is 0 - the effect is the same) + + LDA LSP \ Set XX14+1 to the end of the ball line heap + STA XX14+1 + + JSR EraseRestOfPlanet \ Draw the contents of the ball line heap to erase the + \ old planet + + JMP WP1 \ Reset the ball line heap and return from the + \ subroutine using a tail call + +SAVE "wpls2.bin", WPLS2, P% \ ****************************************************************************** \ @@ -274,6 +546,8 @@ ORG $CCE0 \ \ ****************************************************************************** +ORG $CCE0 + .LLX30 LDY XX14 \ Set Y = XX14, to get the offset within the ship line @@ -423,6 +697,319 @@ ORG $CCE0 JMP LL78 \ Jump down to part 11 +\ ****************************************************************************** +\ +\ Name: EraseRestOfPlanet +\ Type: Subroutine +\ Category: Drawing lines +\ Summary: Draw all remaining lines in the ball line heap to erase the rest +\ of the old planet +\ +\ ****************************************************************************** + +.EraseRestOfPlanet + + LDY XX14 \ Set Y to the offset in XX14, which points to the part + \ of the heap that we are overwriting with new points + + CPY XX14+1 \ If XX14 >= XX14+1, then we have already redrawn all of + BCS eras1 \ the lines from the old circle's ball line heap, so + \ skip the following + + JSR DrawPlanetLine \ Erase the next planet line from the ball line heap + + JMP EraseRestOfPlanet \ Loop back for the next line in the ball line heap + +.eras1 + + RTS \ Return from the subroutine + +\ ****************************************************************************** +\ +\ Name: DrawPlanetLine +\ Type: Subroutine +\ Category: Drawing lines +\ Summary: Draw a segment of the old planet from the ball line heap +\ +\ ------------------------------------------------------------------------------ +\ +\ Other entry points: +\ +\ DrawPlanetLine+4 If bit 7 of K3+8 is set, store the line coordinates in +\ K3+4 to K3+7 (X1, Y1, X2, Y2) and do not draw the line +\ +\ ****************************************************************************** + +.DrawPlanetLine + + LDA #0 \ Clear bit 7 of K3+8 so we draw the current line below + STA K3+8 + + LDA #0 \ Clear bit 7 of K3+9 to indicate that there is no line + STA K3+9 \ to draw (we may change this below) + + LDA XX14 \ If XX14 = 1, then this is the first point from the + CMP #2 \ heap, so jump to plin3 to set the previous coordinate + BCC plin3 \ and return from the subroutine + + LDA X1 \ Save X1, X2, Y1, Y2 and Y on the stack + PHA + LDA Y1 + PHA + LDA X2 + PHA + LDA Y2 + PHA + TYA + PHA + + LDY XX14 \ Set Y to the offset in XX14, which points to the part + \ of the heap that we are overwriting with new points + + CPY XX14+1 \ If XX14 >= XX14+1, then we have already redrawn all of + BCS plin1 \ the lines from the old circle's ball line heap, so + \ jump to plin1 to return from the subroutine + + \ Otherwise we need to draw the line from the heap, to + \ erase it from the screen + + LDA K3+2 \ Set X1 = K3+2 = screen x-coordinate of previous point + STA X1 \ from the old heap + + LDA K3+3 \ Set Y1 = K3+3 = screen y-coordinate of previous point + STA Y1 \ from the old heap + + LDA LSX2,Y \ Set X2 to the y-coordinate from the XX14-th point in + STA X2 \ the heap + + STA K3+2 \ Store the x-coordinate of the point we are overwriting + \ in K3+2, so we can use it on the next iteration + + LDA LSY2,Y \ Set Y2 to the y-coordinate from the XX14-th point in + STA Y2 \ the heap + + STA K3+3 \ Store the y-coordinate of the point we are overwriting + \ in K3+3, so we can use it on the next iteration + + INC XX14 \ Increment XX14 to point to the next coordinate, so we + \ work our way through the current heap + + LDA Y1 \ If Y1 or Y2 = &FF then this indicates a break in the + CMP #&FF \ circle, so jump to plin1 to skip the following and + BEQ plin1 \ return from the subroutine, asthere is no line to + LDA Y2 \ erase + CMP #&FF + BEQ plin1 + + DEC K3+9 \ Decrement K3+9 to &FF to indicate that there is a line + \ to draw + + BIT K3+8 \ If bit 7 of K3+8 is set, jump to plin2 to store the + BMI plin2 \ line coordinates rather than drawing the line + + JSR LL30 \ The coordinates in (X1, Y1) and (X2, Y2) that we just + \ pulled from the ball line heap point to a line that is + \ still on-screen, so call LL30 to draw this line and + \ erase it from the screen + +.plin1 + + PLA \ Restore Y, X1, X2, Y1 and Y2 from the stack + TAY + PLA + STA Y2 + PLA + STA X2 + PLA + STA Y1 + PLA + STA X1 + + RTS \ Return from the subroutine + +.plin2 + + LDA X1 \ Store X1, Y1, X2, Y2 in K3+4 to K3+7 + STA K3+4 + LDA Y1 + STA K3+5 + LDA X2 + STA K3+6 + LDA Y2 + STA K3+7 + + JMP plin1 \ Jump to plin1 to return from the subroutine + +.plin3 + + LDA LSX2+1 \ Store the heap's first coordinate in K3+2 and K3+3 + STA K3+2 + LDA LSY2+1 + STA K3+3 + + INC XX14 \ Increment XX14 to point to the next coordinate, so we + \ work our way through the current heap + + RTS \ Return from the subroutine + +\ ****************************************************************************** +\ +\ Name: DrawNewPlanetLine +\ Type: Subroutine +\ Category: Drawing lines +\ Summary: Draw a ball line, but only if it is different to the old line +\ +\ ------------------------------------------------------------------------------ +\ +\ Arguments: +\ +\ K3+4 to K3+7 The (X1, Y1) and (X2, Y2) coordinates of the old line +\ +\ ****************************************************************************** + +.DrawNewPlanetLine + + BIT K3+9 \ If bit 7 of K3+9 is clear, then there is no old line + BPL nlin2 \ to draw, so jump to nlin2 to draw the new line only + + LDA K3+4 \ If the old line equals the new line, jump to nlin3 + CMP X1 \ to skip drawing both lines + BNE nlin1 + LDA K3+5 + CMP Y1 + BNE nlin1 + LDA K3+6 + CMP X2 + BNE nlin1 + LDA K3+7 + CMP Y2 + BEQ nlin3 + +.nlin1 + + \ If we get here then the old line is differnt to the new + \ line, so we draw them both + + JSR LL30 \ Draw the new line from (X1, Y1) to (X2, Y2) + + LDA K3+4 \ Set up the old line's coordinates + STA X1 + LDA K3+5 + STA Y1 + LDA K3+6 + STA X2 + LDA K3+7 + STA Y2 + +.nlin2 + + JSR LL30 \ Draw the old line to erase it + +.nlin3 + + RTS \ Return from the subroutine SAVE "extra.bin", LLX30, P% +\ ****************************************************************************** +\ +\ Name: BLINE +\ Type: Subroutine +\ Category: Drawing circles +\ Summary: Draw a circle segment and add it to the ball line heap +\ +\ ****************************************************************************** + +ORG $69C0 + +GUARD $6A00 \ Guard against assembling over memory used by game + +.PATCH3 + + \ These are the instructions from the end of BLINE that + \ we move here so there's room for the patch + + LDA K6+2 \ + STA K5+2 \ * K5(3 2) = screen y-coordinate of this point + LDA K6+3 \ + STA K5+3 \ They now become the "previous point" in the next call + + LDA CNT \ Set CNT = CNT + STP + CLC + ADC STP + STA CNT + + RTS \ Return from the subroutine + +\ ****************************************************************************** +\ +\ Name: PLS22 +\ Type: Subroutine +\ Category: Drawing planets +\ Summary: Draw an ellipse or half-ellipse +\ +\ ****************************************************************************** + +.PATCH4 + + \ We replace the following instruction just before PL40 + \ in PLS22 with JMP PATCH4, so we now do this + \ instruction to ensure that it still gets done + + STA CNT2 \ Set CNT2 = (CNT2 + STP) mod 64 + + JMP PLL4 \ Jump back to PLL4 to draw the next segment + +\ ****************************************************************************** +\ +\ Name: CIRCLE2 +\ Type: Subroutine +\ Category: Drawing circles +\ Summary: Draw a circle (for the planet or chart) +\ Deep dive: Drawing circles +\ +\ ****************************************************************************** + +.PATCH5 + + LDX #0 \ Set XX14 = 0, to point to the offset before the first + STX XX14 \ set of circle coordinates in the ball line heap + + LDX LSP \ Set XX14+1 to the last byte of the ball line heap + STX XX14+1 + + LDX #1 \ Set LSP = 1 to reset the ball line heap pointer + STX LSP + + \ We replace the following instructions at CIRCLE2 with + \ JSR PATCH5, so we now do those two instructions to + \ ensure that they still get done + + LDX #&FF \ Set FLAG = &FF to reset the ball line heap in the call + STX FLAG \ to the BLINE routine below + + RTS \ Return from the subroutine + +\ ****************************************************************************** +\ +\ Name: PL9 (Part 1 of 3) +\ Type: Subroutine +\ Category: Drawing planets +\ Summary: Draw the planet, with either an equator and meridian, or a crater +\ +\ ****************************************************************************** + +.PATCH6 + + LDA TYPE \ If the planet type is 128 then it has an equator and + CMP #128 \ a meridian, so this jumps to PL26 if this is not a + BNE P%+5 \ planet with an equator - in other words, if it is a + \ planet with a crater + + JMP PL9_2 \ Otherwise this is a planet with an equator and + \ meridian, so jump to the equator routine in part 2 of + \ PL9 + + JMP PL26 \ Jump to the crater routine + +SAVE "extra2.bin", PATCH3, P% diff --git a/src/elite-modify.py b/src/elite-modify.py index a9ec971..fd5d684 100644 --- a/src/elite-modify.py +++ b/src/elite-modify.py @@ -14,8 +14,17 @@ # It does the following: # # * Decrypt the gma6 file -# * Modify the gma6 file to draw flicker-free ships +# * Modify the gma6 file to draw flicker-free ships and planets # * Encrypt the gma6 file +# +# * Decrypt the gma5 file +# * Modify the gma5 file to draw flicker-free planets +# * Encrypt the gma5 file +# +# * Decrypt the gma4 file +# * Modify the gma4 file to draw flicker-free planets +# * Encrypt the gma4 file +# # * Modify the gma1 file to remove disk protection # # Run this script by changing directory to the folder containing the disk files @@ -86,7 +95,7 @@ print() print("Modifying Commodore 64 Elite") print("Platform: {}".format(platform.upper())) -# Configuration variables +# Configuration variables for gma6 load_address = 0x6A00 - 2 seed = 0x49 @@ -288,9 +297,9 @@ insert_nops(data_block, 0x9FC1, 1) # NOP insert_bytes(data_block, 0x9FD9, [ - 0xC8, # INY - 0xB1, 0x5B, # LDA (V),Y - 0xAA # TAX + 0xC8, # INY + 0xB1, 0x5B, # LDA (V),Y + 0xAA # TAX ]) lda_sta_block = get_offset(0x9FDD) @@ -298,9 +307,9 @@ for n in range(lda_sta_block, lda_sta_block + 4 * 5): data_block[n] = data_block[n + 4] insert_bytes(data_block, 0x9FF1, [ - 0xC8, # INY - 0xB1, 0x5B, # LDA (V),Y - 0xAA # TAX + 0xC8, # INY + 0xB1, 0x5B, # LDA (V),Y + 0xAA # TAX ]) insert_nops(data_block, 0x9FF5, 2) @@ -316,7 +325,7 @@ insert_nops(data_block, 0x9FF5, 2) # To: JMP PATCH2 insert_bytes(data_block, 0xA010, [ - 0x4C, patch2 % 256, patch2 // 256 # JMP PATCH2 + 0x4C, patch2 % 256, patch2 // 256 # JMP PATCH2 ]) # LL9 (Part 11) @@ -359,6 +368,91 @@ elite_file.close() print("[ Modify ] append file extra.bin") +# We now move on to the routines for drawing flicker-free planets + +# Set the addresses for the extra routines (LLX30, PATCH1, PATCH2) that we will +# append to the end of the main game code (where there is a bit of free space) + +erasep = 0xCD3B +patch4 = 0x69D0 +patch5 = 0x69D5 + +# PL9 (Part 1 of 3) +# +# We have already assembled the modified part 1 of PL9 in BeebAsm and saved +# it as the binary file pl9.bin, so now we drop this over the top of the +# existing routine (the new routine is slightly bigger, so it ends by jumping +# to PATCH6, which contains the spill-over). + +insert_binary_file(data_block, 0x7D8C, "pl9.bin") + +# PL9 (Part 2 of 3) +# +# The above modification moves PL20, so we need to modify the branch instruction +# at the start of part 2 of PL9. + +insert_bytes(data_block, 0x7DA8, [ + 0x90, 0xEB # BCC PL20 +]) + +# PL9 (Part 3 of 3) +# +# The above modification moves PL20, so we need to modify the branch instruction +# at the start of part 3 of PL9. + +insert_bytes(data_block, 0x7DE2, [ + 0x30, 0xB1 # BMI PL20 +]) + +# WPLS2 +# +# We have already assembled the modified part 1 of PL9 in BeebAsm and saved +# it as the binary file pl9.bin, so now we drop this over the top of the +# existing routine (which is quite a bit longer, so there is room). + +insert_binary_file(data_block, 0x80BB, "wpls2.bin") + +# PLS22 +# +# This is the modification on either side of PL40, with the label moving two +# bytes backwards to accommodate the modified code. +# +# From: BCS PL40 +# ... +# STA CNT2 +# JMP PLL4 +# .PL40 +# RTS +# +# To: BCS PL40 +# ... +# JMP PATCH4 +# .PL40 +# JMP EraseRestOfPlanet + +insert_bytes(data_block, 0x7F04, [ + 0xB0, 0x0A # BCS PL40 +]) +insert_bytes(data_block, 0x7F0D, [ + 0x4C, patch4 % 256, patch4 // 256, # JMP PATCH4 + 0x4C, erasep % 256, erasep // 256 # JMP EraseRestOfPlanet +]) + +# CIRCLE2 +# +# This is the modification at the start of the routine. +# +# From: LDX #&FF +# STX FLAG +# +# To: JSR PATCH5 +# NOP + +insert_bytes(data_block, 0x805E, [ + 0x20, patch5 % 256, patch5 // 256 # JSR PATCH5 +]) +insert_nops(data_block, 0x8061, 1) + # All the modifications are done, so write the output file for gma6.modified, # which we can use for debugging @@ -386,6 +480,165 @@ output_file.close() print("[ Save ] gma6.encrypted") +# Configuration variables for gma5 + +load_address = 0x1D00 - 2 +seed = 0x36 +scramble_from = 0x1D00 +scramble_to = 0x1D00 + (0x21D4 - 3) # File size - 3 + +# Set up an array to hold the gma5 binary, so we can modify it + +data_block = bytearray() + +# Load the gma5 code file into data_block + +elite_file = open("gma5", "rb") +data_block.extend(elite_file.read()) +elite_file.close() + +print() +print("[ Read ] gma5") + +# Decrypt the gma5 code file + +updated_seed = seed + +for n in range(scramble_to, scramble_from - 1, -1): + new = (data_block[n - load_address] - updated_seed) % 256 + data_block[n - load_address] = new + updated_seed = new + +print("[ Decrypt ] gma5") + +# Write an output file containing the decrypted but unmodified gma5 code, which +# we can use for debugging + +output_file = open("gma5.decrypted", "wb") +output_file.write(data_block) +output_file.close() + +print("[ Save ] gma5.decrypted") + +# BLINE +# +# We have already assembled the modified BLINE in BeebAsm and saved it as the +# binary file bline.bin, so now we drop this over the top of the existing +# routine (the new routine is slightly bigger, so it ends by jumping to PATCH3, +# which contains the spill-over). + +insert_binary_file(data_block, 0x2977, "bline.bin") + +# All the modifications are done, so write the output file for gma5.modified, +# which we can use for debugging + +output_file = open("gma5.modified", "wb") +output_file.write(data_block) +output_file.close() + +print("[ Save ] gma5.modified") + +# Encrypt the gma5 code file + +for n in range(scramble_from, scramble_to): + data_block[n - load_address] = (data_block[n - load_address] + data_block[n + 1 - load_address]) % 256 + +data_block[scramble_to - load_address] = (data_block[scramble_to - load_address] + seed) % 256 + +print("[ Encrypt ] gma5.modified") + +# Write the output file for gma5.encrypted, which contains our modified game +# binary with the flicker-free code + +output_file = open("gma5.encrypted", "wb") +output_file.write(data_block) +output_file.close() + +print("[ Save ] gma5.encrypted") + +# Configuration variables for gma4 + +load_address = 0x4000 - 2 +seed = 0x8E +scramble_from = 0x75E4 +scramble_to = 0x865A + +# Set up an array to hold the gma4 binary, so we can modify it + +data_block = bytearray() + +# Load the gma4 code file into data_block + +elite_file = open("gma4", "rb") +data_block.extend(elite_file.read()) +elite_file.close() + +print() +print("[ Read ] gma4") + +# Decrypt the gma4 code file + +updated_seed = seed + +for n in range(scramble_to, scramble_from - 1, -1): + new = (data_block[n - load_address] - updated_seed) % 256 + data_block[n - load_address] = new + updated_seed = new + +print("[ Decrypt ] gma4") + +# Write an output file containing the decrypted but unmodified gma4 code, which +# we can use for debugging + +output_file = open("gma4.decrypted", "wb") +output_file.write(data_block) +output_file.close() + +print("[ Save ] gma4.decrypted") + +# We now insert the four extra routines required by the modifications into +# the unused space just after the sprites: +# +# PATCH3 +# PATCH4 +# PATCH5 +# PATCH6 +# +# We have already assembled these in BeebAsm and saved them as the binary file +# extra2.bin, so we simply insert this file at the correct address. The contents +# of the GMA4 file is moved after decryption, so although the routines end up at +# $69C0, they actually get loaded and decrypted at $7C3A, so that's the address +# we use when inserting the code into the gm4 file: + +insert_binary_file(data_block, 0x7C3A, "extra2.bin") + +# All the modifications are done, so write the output file for gma4.modified, +# which we can use for debugging + +output_file = open("gma4.modified", "wb") +output_file.write(data_block) +output_file.close() + +print("[ Save ] gma4.modified") + +# Encrypt the gma4 code file + +for n in range(scramble_from, scramble_to): + data_block[n - load_address] = (data_block[n - load_address] + data_block[n + 1 - load_address]) % 256 + +data_block[scramble_to - load_address] = (data_block[scramble_to - load_address] + seed) % 256 + +print("[ Encrypt ] gma4.modified") + +# Write the output file for gma4.encrypted, which contains our modified game +# binary with the flicker-free code + +output_file = open("gma4.encrypted", "wb") +output_file.write(data_block) +output_file.close() + +print("[ Save ] gma4.encrypted") + # Finally, we need to remove the disk protection from gma1, as described here: # https://www.lemon64.com/forum/viewtopic.php?t=67762&start=90