Skip to content

Latest commit

 

History

History

src

Iridis Alpha: Introduction to the Source Code

This source code is derived from the binary stored in the orig folder. This binary is the one distributed by Minter in 2019 along with the rest of his Vic 20 and C64 games.

It's important to note that this is not a byte-for-byte identical disassembly of the original binary. This is because iridisalpha.prg uses a compressor/decompressor to load itself into memory. So it is only possible to derive the original source from a snapshot of the game while it is running. I reverse-engineered the source code from a Vice snapshot. The hard part of doing it this way is figuring out the correct entry point to launch the game from, which in this case turned out to be address $4000. This was also the point at which I figured out I needed to use Exomizer to compress some of the game data myself, so that I could get the game to load and run.

If you're new to assembly, you should take a look at the common patterns in Iridis Alpha's codebase. These are shared by other Minter games too and the discussion tries to shed light on some of the things that would not be obvious to a beginner in the way assembly code is written. There are also some notes in there intended to help understand C64 internals, such as characters, sprites and interupts.

Before diving into the code, let's take a quick look at how I've broken out the source.

What Each File Contains

iridisalpha.asm

This file contains the source for the main game. All of the other asm files in this directory are included from this file, with the exception of characterandspritedata.asm which is compiled separately and compressed into the final prg file.

bonusphase.asm

This file contains the source for the game's 'Bonus Phase', which is in fact a complete mini-game in it's own right.

charset.asm

This file contains the character sets used in the game, including most of the characters used to construct the planet surfaces

Here's what the start of the file looks like, defining the characterset (font) used for A, B and C.

p200E
        .BYTE $C6,$C6   ;.BYTE $3C,$66,$C6,$DE,$C6,$C6,$C6,$C6
                                                ; CHARACTER $01
                                                ; 00111100     ****  
                                                ; 01100110    **  ** 
                                                ; 11000110   **   ** 
                                                ; 11011110   ** **** 
                                                ; 11000110   **   ** 
                                                ; 11000110   **   ** 
                                                ; 11000110   **   ** 
                                                ; 11000110   **   ** 
        .BYTE $FC,$C6,$C6,$DC,$C6,$C6,$C6
p2017
        .BYTE $DC   ;.BYTE $FC,$C6,$C6,$DC,$C6,$C6,$C6,$DC
                                                ; CHARACTER $02
                                                ; 11111100   ******  
                                                ; 11000110   **   ** 
                                                ; 11000110   **   ** 
                                                ; 11011100   ** ***  
                                                ; 11000110   **   ** 
                                                ; 11000110   **   ** 
                                                ; 11000110   **   ** 
                                                ; 11011100   ** ***  
        .BYTE $3C,$66,$C0,$C0,$C0,$C0,$C6,$7C   ;.BYTE $3C,$66,$C0,$C0,$C0,$C0,$C6,$7C
                                                ; CHARACTER $03
                                                ; 00111100     ****  
                                                ; 01100110    **  ** 
                                                ; 11000000   **      
                                                ; 11000000   **      
                                                ; 11000000   **      
                                                ; 11000000   **      
                                                ; 11000110   **   ** 
                                                ; 01111100    *****  

bonusphase_graphics.asm

sprites.asm

These files contain the game's sprites and some additional character set data. As bonusphase_graphics.asm needs to end up at adress $E000, and since it is not possible to load data directly to that address when loading a C64 binary from tape or image, our build process uses a tool called Exomizer to compress the data in bonusphase_graphics.asm in iridisalpha.prg and then decompress it to $E000 when the program is loading.

The source includes a pseudo bitmap of the sprites that helps you related the data to what will ultimately be painted on screen. Here's the sprite definition of the gilby flying left from sprites.asm:

        ; SPRITE $D3
        ; $00,$00,$00 000000000000000000000000                         
        ; $00,$00,$00 000000000000000000000000                         
        ; $00,$04,$00 000000000000010000000000              *          
        ; $00,$09,$00 000000000000100100000000             *  *        
        ; $02,$8A,$40 000000101000101001000000       * *   * *  *      
        ; $0B,$A2,$90 000010111010001010010000     * *** *   * *  *    
        ; $0E,$A2,$A4 000011101010001010100100     *** * *   * * *  *  
        ; $2A,$AC,$A9 001010101010110010101001   * * * * * **  * * *  *
        ; $2A,$AF,$FE 001010101010111111111110   * * * * * *********** 
        ; $2A,$AC,$A9 001010101010110010101001   * * * * * **  * * *  *
        ; $1A,$A2,$A4 000110101010001010100100    ** * * *   * * *  *  
        ; $0A,$A2,$90 000010101010001010010000     * * * *   * *  *    
        ; $02,$8A,$40 000000101000101001000000       * *   * *  *      
        ; $00,$09,$00 000000000000100100000000             *  *        
        ; $00,$04,$00 000000000000010000000000              *          
        ; $00,$00,$00 000000000000000000000000                         
        ; $00,$00,$00 000000000000000000000000                         
        ; $00,$00,$00 000000000000000000000000                         
        ; $00,$00,$00 000000000000000000000000                         
        ; $00,$00,$00 000000000000000000000000                         
        ; $00,$00,$00 000000000000000000000000                         
        .BYTE $00,$00,$00,$00,$00,$00,$00,$04
        .BYTE $00,$00,$09,$00,$02,$8A,$40,$0B
        .BYTE $A2,$90,$0E,$A2,$A4,$2A,$AC,$A9
        .BYTE $2A,$AF,$FE,$2A,$AC,$A9,$1A,$A2
        .BYTE $A4,$0A,$A2,$90,$02,$8A,$40,$00
        .BYTE $09,$00,$00,$04,$00,$00,$00,$00
        .BYTE $00,$00,$00,$00,$00,$00,$00,$00
        .BYTE $00,$00,$00,$00,$00,$00,$00,$FF

madeinfrance.asm

This is the self-contained pause-mode game, called 'Made in France' or 'MIF' for short. You can access it during game play by pressing 'F1'. This little game was originally released by Minter on Compunet, the source code for that release is available at https://github.com/mwenge/iridisalpha/tree/master/demos/mif.

dna.asm

This is a game within the pause-mode game. Originally released on Compunet, you can access it from with 'Made in France' by pressing '*'. You exit it by pressing '*' again. his little game was also originally released by Minter on Compunet, the source code for that release is available at https://github.com/mwenge/iridisalpha/tree/master/demos/dna.

A Closer Look At iridisalpha.asm

While disassembly is still in progress, this section is a collection of random notes.

The Difficulty Cliff

When I first played this game as a kid I struggled with the sudden jump in difficulty you encounter 3 levels into the game.

After blithely blasting through the initial waves of enemies you suddenly encounter floating dots. You shoot them, they turn into an oval face with a tongue sticking out, gravitate towards you immediately and in a near instant sap all your energy and kill you. The notorious 'licker ships'.

Anecdotally, this difficulty cliff turned out to be a real problem for casual players. Many could never make it beyond this level - there was no obvious way of struggling past it with just 3 lives. If you experimented long enough you would eventually discover the optimal strategy was to fly to the left, turn briefly, shoot and continue running. You needed to pick them off one at a time and make sure they were far enough away from you so that they wouldn't immediately dash towards you and pick you off.

There's no question in my mind that this jump in difficulty was way too sudden and while disassembling the game I was very curious to understand how it was configured and if it would be easy to dial it back in some way.

The enemy ship behaviour for every level is defined by the data structures in level_data.asm. It's a 40 byte structure with a whole bunch of flags that specify a variety of different behaviours for each enemy type. Here's the full list:

; The wave data has the following structure:
; Byte 0 ($00): An index into colorsForAttackShips that applies a color value for the attack ship sprite.
; Byte 1 ($01): Sprite value for the attack ship for the upper planet.
; Byte 2 ($02): THe 'end' sprite value for the attack ship's animation for the upper planet.
; Byte 3 ($03): The animation frame rate for the attack ship.
; Byte 4 ($04): Sprite value for the attack ship for the lower planet.
; Byte 5 ($05): THe 'end' sprite value for the attack ship's animation for the lower planet.
; Byte 6 ($06): Determines if the inital Y Position of the ship is random or uses a default.
; Byte 7 ($07): Determines if the inital Y Position of the ship is random or uses a default.
; Byte 8 ($08): Default initiation Y position for the enemy.
; Byte 9 ($09): Lo Ptr for an animation effect? (Doesn't seem to be used?)
; Byte 10 ($0A): Hi Ptr for an animation effect (Doesn't seem to be used?)?
; Byte 11 ($0B): some kind of rate limiting for attack wave
; Byte 12 ($0C): Lo Ptr for a stage in wave data (never used).
; Byte 13 ($0D): Hi Ptr for a stage in wave data (never used).
; Byte 14 ($0E): Controls the rate at which new enemies are added?
; Byte 15 ($0F): Update rate for attack wave
; Byte 16 ($10): Lo Ptr to the wave data we switch to when the enemy is first hit.
; Byte 17 ($11): Hi Ptr to the wave data we switch to when the enemy is first hit.
; Byte 18 ($12): X Pos movement for attack ship.
; Byte 19 ($13): Y Pos movement pattern for attack ship. An index into yPosMovementPatternForShips1
; Byte 20 ($14): X Pos Frame Rate for Attack ship.
; Byte 21 ($15): Y Pos Frame Rate for Attack ship.
; Byte 22 ($16): Stickiness factor, does the enemy stick to the player sapping their energy if they're near them?
; Byte 23 ($17): Does the enemy gravitate quickly toward the player when its been shot? (Typical lickership behaviour)
; Byte 24 ($18):
; Byte 25 ($19): Lo Ptr for another set of wave data.
; Byte 26 ($1A): Hi Ptr for another set of wave data.
; Byte 27 ($1B): Lo Ptr for another set of wave data.
; Byte 28 ($1C): Hi Ptr for another set of wave data.
; Byte 29 ($1D): Lo Ptr for Explosion animation.
; Byte 30 ($1E): Hi Ptr for Explosion animation.
; Byte 31 ($1F): Lo Ptr for another set of wave data for this level.
; Byte 32 ($20): Hi Ptr for another set of wave data for this level.
; Byte 33 ($21): A flag that tells us whether to load the extra stage data for this enemy.
; Byte 34: ($22): Points multiplier for hitting enemies in this level.
; Byte 35: ($23): Does hitting this enemy increase the gilby's energy?
; Byte 36: ($24) Is the ship a spinning ring, i.e. does it allow the gilby to warp?

It turns out the fields that control the horrible behaviour of the licker ships are these two:

; Byte 22 ($16): Stickiness factor, does the enemy stick to the player sapping their energy if they're near them?
; Byte 23 ($17): Does the enemy gravitate quickly toward the player when its been shot? (Typical lickership behaviour)

When we look at the data for level 3 on planet 1 we see that there's quite a bit to unpick here:

planet1Level3Data
.BYTE $05,LICKERSHIP_SEED,LICKERSHIP_SEED+$02,$04,LICKERSHIP_SEED,LICKERSHIP_SEED+$02,$00,$00
.BYTE $00,$00,$00,$00,$00,$00,$00,$30
.BYTE <planet1Level3Data2ndStage,>planet1Level3Data2ndStage,$FA,$01,$01,$02,$00,$00
.BYTE <nullPtr,>nullPtr,<nullPtr,>nullPtr
.BYTE <lickerShipWaveData,>lickerShipWaveData,<lickerShipWaveData,>lickerShipWaveData
.BYTE $00,$00,$02,$01,$00,$04,$20,$00
planet1Level3Data2ndStage
.BYTE $04,LICKERSHIP_SEED,LICKERSHIP_SEED+$02,$02,LICKERSHIP_SEED,LICKERSHIP_SEED+$02,$00,$00
.BYTE $00,$00,$00,$00,$00,$00,$00,$20
.BYTE <planet1Level3Data3rdStage,>planet1Level3Data3rdStage,$01,$FF,$01,$01,$00,$00
.BYTE <nullPtr,>nullPtr,<nullPtr,>nullPtr
.BYTE <lickerShipWaveData,>lickerShipWaveData,<lickerShipWaveData,>lickerShipWaveData
.BYTE $00,$00,$01,$01,$00,$00,$00,$00
planet1Level3Data3rdStage
.BYTE $06,LICKERSHIP_SEED,LICKERSHIP_SEED+$02,$06,LICKERSHIP_SEED,LICKERSHIP_SEED+$02,$00,$00
.BYTE $00,$00,$00,$00,$00,$00,$00,$33
.BYTE <planet1Level3Data,>planet1Level3Data,$F8,$00,$01,$00,$00,$00
.BYTE <nullPtr,>nullPtr,<nullPtr,>nullPtr
.BYTE <lickerShipWaveData,>lickerShipWaveData,<lickerShipWaveData,>lickerShipWaveData
.BYTE $00,$00,$01,$01,$00,$00,$00,$00

The initial configuration of the licker ship enemy is defined in planet1Level3Data. This controls the behaviour of the ships until you first shoot them. So you can see the sprite defined for the ship is LICKERSHIP_SEED in this initial state, i.e. the floating dot I described earlier. In the second last line we can see a reference to lickerShipWaveData. These are references to a different set of wave data invoked when the enemy is struck by a bullet from your gilby for the first time. What happens is the game switches to using the configuration in lickerShipWaveData when you first it hit with a bullet. In the earlier levels this will be just a spinning ring, but in this level it turns the harmless floating dots into the intensely frustrating licker ships.

planet1Level3Data
.BYTE $05,LICKERSHIP_SEED,LICKERSHIP_SEED+$02,$04,LICKERSHIP_SEED,LICKERSHIP_SEED+$02,$00,$00
.BYTE $00,$00,$00,$00,$00,$00,$00,$30
.BYTE <planet1Level3Data2ndStage,>planet1Level3Data2ndStage,$FA,$01,$01,$02,$00,$00
.BYTE <nullPtr,>nullPtr,<nullPtr,>nullPtr
.BYTE <lickerShipWaveData,>lickerShipWaveData,<lickerShipWaveData,>lickerShipWaveData
.BYTE $00,$00,$02,$01,$00,$04,$20,$00

This is what the licker ship data looks like:

lickerShipWaveData = $1118
.BYTE $0B,LICKERSHIP,LICKERSHIP+$02,$04,LICKERSHIP_INV,LICKERSHIP_INV+$01,$00,$00
.BYTE $00,$00,$00,$00,$00,$00,$00,$20
.BYTE <default2ndStage,>default2ndStage,$00,$00,$02,$02,$01,$01
.BYTE <nullPtr,>nullPtr,<nullPtr,>nullPtr
.BYTE <nullPtr,>nullPtr,<lickerShipWaveData,>lickerShipWaveData
.BYTE $00,$00,$00,$02,$00,$00,$00,$00

This is the configuration data that controls the behaviour and appearance of the licker ships. The bit that defines their behaviour is in the last two bytes of the third line:

.BYTE <default2ndStage,>default2ndStage,$00,$00,$02,$02,$01,$01

By setting these to $01 we're defining two sets of behaviour. The first is to gravitate immediately towards the player and the second is to stick to the player as much as possible, sapping their energy.

This is the place in the code where these settings are inspected to determine the behaviour:

MaybeQuicklyGravitatesToGilby
; Does the enemy gravitate quickly towards the gilby when it is shot?
LDY #$17
LDA (currentShipWaveDataLoPtr),Y
BEQ MaybeStickyAttackShipBehaviour

There is one other piece of configured behaviour of the licker ships that makes them so difficult to get past, one I only noticed when writing this: hitting the licker ships results in no increase in energy!

; Byte 35: ($23): Does hitting this enemy increase the gilby's energy?

The 3rd byte in this line is set to $00:

.BYTE $00,$00,$00,$02,$00,$00,$00,$00

So the licker ship data has this flag set to $00, so not only do the ships immediately jump on you and start sapping your energy, killing any of them during this level results in getting no energy back!

This is clearly stacking the odds way too high against the casual player way too soon in the game in my opinion. So to give the novice player (and me) a chance of progressing and exploring the game I've added a build option that applies the following patch to the game:

diff --git a/src/level_data2.asm b/src/level_data2.asm
index 32ae5f3..221762f 100644
--- a/src/level_data2.asm
+++ b/src/level_data2.asm
@@ -60,10 +60,10 @@ f10F0 = $10F0
lickerShipWaveData = $1118
.BYTE $0B,LICKERSHIP,LICKERSHIP+$02,$04,LICKERSHIP_INV,LICKERSHIP_INV+$01,$00,$00
.BYTE $00,$00,$00,$00,$00,$00,$00,$20
- .BYTE <default2ndStage,>default2ndStage,$00,$00,$02,$02,$01,$01
+ .BYTE <default2ndStage,>default2ndStage,$00,$00,$02,$02,$00,$01
.BYTE <nullPtr,>nullPtr,<nullPtr,>nullPtr
.BYTE <nullPtr,>nullPtr,<lickerShipWaveData,>lickerShipWaveData
- .BYTE $00,$00,$00,$02,$00,$00,$00,$00
+ .BYTE $00,$00,$02,$02,$00,$00,$00,$00
planet1Level11Data = $1140
.BYTE $0E,$D1,$D4,$06,$E4,$E7,$03,$68
.BYTE $11,$00,$00,$00,$00,$00,$00,$00

This toggles off the behaviour of immediately gravitating to the player's ship and allows the player to accumulate energy when killing the licker ships. For me, this provides a nice balance between incrementing the difficulty a bit and giving the player the chance to actually make some progress. To try out the easy mode, do:

make runeasy

You can try it out here:

https://lvllvl.com/c64/?gid=37124df5a665dacc3f8f3d7c868cbda2

Bug: Ships from the last level in the previous game show up when you start a new game

When you start a new game, enemies from the previous game show up in the first wave. For most people starting out this will take the form of a few residual 'licker ships' zapping them just as they're getting started.

This bug happens because the 'wave' data isn't cleared down when a new game starts. So whatever is in there from the previous game gets used until they're flushed out by being killed and replaced with the level's proper enemy data.

This isn't a problem for the first game after Iridis Alpha is loaded because the first level's data is hardcoded in there:

nullPtr = $0000
; This is a pointer table for the data for each of the 4 active ships on the
; top planet and the bottom planet. It gets updated as ships die and levels
; change.
activeShipsWaveDataLoPtrArray = *-$02
; Pointers to top planet ships.
.BYTE <planet1Level1Data2ndStage,<planet1Level1Data2ndStage,<planet1Level1Data2ndStage,<planet1Level1Data2ndStage
.BYTE <nullPtr,<nullPtr ; These two are always zero. This makes it easy
; to use an 'AND #$08' on the index to check
; if it is pointing to a top planet ship or a
; bottom planet one. Note that the array actually starts two bytes
; ahead of the first value ('= *-$02' above). THis means the first 4 are
; reference with index 2,3,4,5 rather than 0,1,2,3.
; Pointers to bottom planet ships.
.BYTE <planet1Level1Data2ndStage,<planet1Level1Data2ndStage,<planet1Level1Data,<planet1Level1Data
activeShipsWaveDataHiPtrArray =*-$02
; Pointers to top planet ships.
.BYTE >planet1Level1Data2ndStage,>planet1Level1Data2ndStage,>planet1Level1Data2ndStage,>planet1Level1Data2ndStage
.BYTE >nullPtr,>nullPtr
; Pointers to bottom planet ships.
.BYTE >planet1Level1Data2ndStage,>planet1Level1Data2ndStage,>planet1Level1Data,>planet1Level1Data

The fix is simple enough, we initialize the active wave data stored in activeShipsWaveDataLoPtrArray and activeShipsWaveDataHiPtrArray with the first level's data whenever we start a new game.

LDA #$0F
STA $D418 ;Select Filter Mode and Volume
JSR ClearPlanetTextureCharsets
JSR InitializeActiveShipArray
JMP PrepareToLaunchIridisAlpha

;------------------------------------------------------------------
; InitializeActiveShipArray
;------------------------------------------------------------------
InitializeActiveShipArray
LDX #$00
InitializeActiveShipLoop
LDA <planet1Level1Data
STA activeShipsWaveDataLoPtrArray,X
LDA >planet1Level1Data
STA activeShipsWaveDataHiPtrArray,X
INX
CPX #$10
BNE InitializeActiveShipLoop
RTS

You can try out the bugfixed version of Iridis Alpha by doing the following:

git checkout bugfixes
make runcustom

GenPlan: The algorithm for generating the planet surfaces

This is the routine Minter devoted some time to in his development diary.

;------------------------------------------------------------------
; GeneratePlanetSurface
;
; This is the routine Minter called 'GenPlan'.
;
; From Jeff Minter's development diary:
; 17 February 1986
; "Redid the graphics completely, came up with some really nice looking
; metallic planet structures that I'll probably stick with. Started to
; write the GenPlan routine that'll generate random planets at will.
; Good to have a C64 that can generate planets in its spare time.
; Wrote pulsation routines for the colours; looks well good with some
; of the planet structures. The metallic look seems to be 'in' at the
; moment so this first planet will go down well. There will be five
; planet surface types in all, I reckon, probably do one with grass
; and sea a bit like 'Sheep in Space', cos I did like that one. It'll
; be nice to have completely different planet surfaces in top and bottom
; of the screen. The neat thing is that all the surfaces have the same
; basic structures, all I do is fit different graphics around each one."
;------------------------------------------------------------------
GeneratePlanetSurface
LDA #<planetSurfaceData
STA planetSurfaceDataPtrLo
LDA #>planetSurfaceData
STA planetSurfaceDataPtrHi
; Clear down the planet surface data from $8000 to $8FFF
LDY #$00
b73C6 LDA #$60
b73C8 STA (planetSurfaceDataPtrLo),Y
DEY
BNE b73C8
INC planetSurfaceDataPtrHi
LDA planetSurfaceDataPtrHi
CMP #$90
BNE b73C6

There are five different planets in the game, each with their own unique set of textures, surfaces and structures. However the algorithm for generating the planets is the same: the difference lies solely in the character set data used to construct them.

The generated planet data gets written to positions $8C00 to $8FFF in memory. The first step is to fill this with 'sea':

        ; Fill $8C00 to $8CFF with a $40,$42 pattern. These are the
        ; character values that represent 'sea' on the planet.
        LDA #$8C
        STA planetSurfaceDataPtrHi
b73D9   LDA #$40
        STA (planetSurfaceDataPtrLo),Y
        LDA #$42
        INY 
        STA (planetSurfaceDataPtrLo),Y
        DEY 
        ; Move the pointers forward by 2 bytes
        LDA planetSurfaceDataPtrLo
        CLC 
        ADC #$02
        STA planetSurfaceDataPtrLo
        LDA planetSurfaceDataPtrHi
        ADC #$00
        STA planetSurfaceDataPtrHi
        ; Loop until $8FFF
        CMP #$90
        BNE b73D9

The values $40 and $42 here refer to the character set bytes $40 and $42 in the current location of the character set, which for Iridis Alphas starts at $2000. When the first level starts, the values at this position are as follows (from charset.asm):

f2200
        .BYTE $00,$00,$20,$00,$8A,$AA,$00,$AA   ;.BYTE $00,$00,$20,$00,$8A,$AA,$00,$AA
                                                ; CHARACTER $40
                                                ; 00000000           
                                                ; 00000000           
                                                ; 00100000     *     
                                                ; 00000000           
                                                ; 10001010   *   * * 
                                                ; 10101010   * * * * 
                                                ; 00000000           
                                                ; 10101010   * * * * 
        .BYTE $00,$00,$00,$00,$8A,$AA,$AA,$00   ;.BYTE $00,$00,$00,$00,$8A,$AA,$AA,$00
                                                ; CHARACTER $42
                                                ; 00000000           
                                                ; 00000000           
                                                ; 00000000           
                                                ; 00000000           
                                                ; 10001010   *   * * 
                                                ; 10101010   * * * * 
                                                ; 10101010   * * * * 
                                                ; 00000000           

Together these create the 'sea' effect that forms the basis of most of the planet's surface.

The next step is to pick a random location on the surface for the 'land':

        ; Pick a random point between $8C00 and $8FFF for 
        ; the start of the land section.
        JSR PutRandomByteInAccumulatorRegister
        AND #$7F
        CLC 
        ADC #$7F
        STA charSetDataPtrHi
        LDA #$00
        STA charSetDataPtrLo
        ; Use the two pointers above to pick a random position
        ; in the planet between $8C00 and $8FFF and store it in
        ; planetPtrLo/planetPtrHi
        JSR StoreRandomPositionInPlanetInPlanetPtr

        ; Randomly generate the length of the land section, but
        ; make it at least 32 bytes.
        JSR PutRandomByteInAccumulatorRegister
        AND #$7F
        CLC 
        ADC #$20
        STA planetSurfaceDataPtrLo

Now, draw the land from the randomly chosen position for up to 256 bytes:

        ; Store $5C,$5E in the randomly chosen position. This is the
        ; left shore of the land.
        LDY #$00
        LDA #$5C
        STA (planetPtrLo),Y
        LDA #$5E
        INY 
        STA (planetPtrLo),Y

        ; Draw the land from the randomly chosen position for up to
        ; 256 bytes, depending on the randomly chosen length of the land
        ; chosen above and storedin planetSurfaceDataPtrLo. 
b741A   INC charSetDataPtrHi
        BNE b7420

        INC charSetDataPtrLo
b7420   JSR StoreRandomPositionInPlanetInPlanetPtr
        LDY #$00
        LDA #$41
        STA (planetPtrLo),Y
        LDA #$43
        INY 
        STA (planetPtrLo),Y
        DEC planetSurfaceDataPtrLo
        BNE b741A

        ; Draw the right short of the land, represented by the chars in
        ; $5D/$5F.
        INY 
        LDA #$5D
        STA (planetPtrLo),Y
        LDA #$5F
        INY 
        STA (planetPtrLo),Y

A Cheat for Awarding Yourself 10000 Bonus Points

In the CheckKeyboardInGame Routine, we find the following:

        ; We can award ourselves a bonus bounty by 
        ; pressing Y at any time, as long as '1C' is the
        ; first character in the hiscore table. Not sure
        ; what this hack is for, testing?
b78A1   CMP #$19 ; Y Pressed
        BNE b7898
        LDA canAwardBonus
        CMP #$1C
        BNE b7898
        INC bonusAwarded
        RTS 

In the above the canAwardBonus byte is the first letter in the name of the player with the top score in the Hi-Score table. By default this is 'YAK':

hiScoreTablePtr           .TEXT "0068000"
canAwardBonus             .TEXT "YAK "
                          .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
                          .TEXT  "0065535RATT"
                          .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
                          .TEXT  "00491"
                          .TEXT "52WULF"
                          .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
                          .TEXT "0032768INCA"
                          .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
                          .TEXT "003"
                          .TEXT "0000MAT "
                          .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
                          .TEXT "0025000PSY "
                          .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
                          .TEXT "0"
                          .TEXT "020000TAK "
                          .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
                          .TEXT "0016384GOAT"
                          .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00
                          .TEXT $00
                          .TEXT "0010000PINK"
                          .BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00
                          .TEXT "0009000FLYD"
                          .BYTE $00,$00,$00,$00,$00,$00,$00
                          .TEXT $00,$00,$00

But if we change 'Y' to $1C like so, we can activate the hack:

hiScoreTablePtr           .TEXT "0068000"
canAwardBonus             .TEXT $1C,"AK "

(Note that $1C is charset code for a bull's head symbol in Iridis Alpha, so it is also possible to enter this as the initial of a high scorer name if we get a score that puts us to the top of the table:

        .BYTE $66,$C3,$7E,$5A,$7E,$7E,$3C,$00   ;.BYTE $66,$C3,$7E,$5A,$7E,$7E,$3C,$00
                                                ; CHARACTER $1c
                                                ; 01100110    **  ** 
                                                ; 11000011   **    **
                                                ; 01111110    ****** 
                                                ; 01011010    * ** * 
                                                ; 01111110    ****** 
                                                ; 01111110    ****** 
                                                ; 00111100     ****  
                                                ; 00000000           

)

Here's the hack in action, we can press Y at any time to give ourselves a bonus of 10000:

I'm guessing this was used for testing the animation routine and left in as an Easter egg.

Bug: Pressing F1 during Attract Mode Allows You to Resume the Game at a Random Level

After a minute or two in the title screen, the game enters 'Attract Mode' and plays a random level on autopilot for a few seconds. If you press F1 during this play you enter the 'Made in France' pause-mode mini game. If you press F1 again you can now start playing the level 'Attract Mode' selected at random.

This is because the CheckKeyboardInGame routine doesn't try to prevent you from entering 'Pause Mode' while Attract Mode is running:

f1WasPressed .BYTE $00
;------------------------------------------------------------------
; CheckKeyboardInGame
;------------------------------------------------------------------
CheckKeyboardInGame
LDA lastKeyPressed
CMP #$40
BNE b786D
LDA #$00
STA f1WasPressed
b786C RTS
b786D LDY f1WasPressed
BNE b786C
LDY inAttractMode
BEQ b787C
LDY #$02
STY inAttractMode
b787C LDY levelRestartInProgress
BNE b786C
LDY gilbyHasJustDied
BNE b786C
CMP #$3E ; Q pressed, to quit game
BNE b788E
; Q was pressed, get ready to quit game.
INC qPressedToQuitGame
RTS
b788E CMP #$04 ; F1 Pressed
BNE b7899
INC f1WasPressed
INC pauseModeSelected
b7898 RTS
b7899 CMP #$3C ; Space pressed
BNE b78A1
INC progressDisplaySelected
RTS
; We can award ourselves a bonus bounty by
; pressing Y at any time, as long as '1C' is the
; first character in the hiscore table. Not sure
; what this hack is for, testing?
b78A1 CMP #$19 ; Y Pressed
BNE b7898
LDA canAwardBonus
CMP #$1C
BNE b7898
INC bonusAwarded
RTS

Here's the cheat in action: