Close

How Did I Do?

A project log for Lunar Lander for the PDP-1

My PDP-1 Replica (PiDP-1) from Obsolescence Guaranteed has arrived and I want to do something cool with it.

michael-gardiMichael Gardi a day ago0 Comments

With game mechanics in place it was time to start making Lunar Lander into an actual game, starting with answering the question posed above, "How did I do?".

Scoring

I described the scoring scheme from the arcade version of Lunar Lander in my Targets log.  Following their lead I implemented the following:

  1. A "Good Landing" is defined as one where the LEM:
    1. Is upright.
    2. Lands inside a target zone.
    3. Has a vertical velocity is less than 100.     (I will probably tighten these up.)
    4. Has a horizontal velocity is less than 50. 
  2. I did not implement the Hard Landing" for 15 points.
  3. The score for a good landing is 50 points x the target multiplier.
  4. A crash is worth 5 points. (I'm thinking about making this only if the LEM hits a landing zone.)
  5. There is also a 50 "gallon" fuel bonus for a good landing.

Good Landings

I had already gotten collision detection working, so now I needed to add code to determine if the LEM was within a "landing zone". To accomplish this I added a couple of tables that enumerated the left and right x coordinates of the six zones. To save me from having to multiply the 50 points bonus x the target multiplier on a machine with no multiply I made a little table with the score value for each target as well.

/ The left endpoints of landing zones.
lzx,    50                    / 5x
        322                   / 2x
        466                   / 3x
        632                   / 1x
        1320                  / 4x
        1642                  / 5x
        0                     / End of data marker.

/ The right endpoints of landing zones.
rzx,    144                   / 5x
        416                   / 2x
        574                   / 3x
        1104                  / 1x
        1414                  / 4x
        1724                  / 5x

/ Scores for successful landings by target multiplier.
skz,    372                   / 5 x 50 = 250
        144                   / 2 x 50 = 100
        226                   / 3 x 50 = 150
        62                    / 1 x 50 = 50
        310                   / 4 x 50 = 200
        372                   / 5 x 50 = 250

These are of course all in octal format.  I added the following code to make the  "soft landing" call.

/ Check for a "soft" landing. On entry scx will have the "center" x value of the LEM.
       lac rot                / Get the LEM's rotation. Must be upright.
       sas (2                 / Upright?
       jmp sex                /   No - Set for explosion.
       init lx, lzx           /  Yes - Setup for landing zone check. Left point.
       init rx, rzx           / Right point.
       init sc, skz           / Score.
    
lx,    lac .                  / Get the left landing zone end point.
       sza i                  / Not Zero?
       jmp sex                /   No - End of landing zone table. Set for explosion.
       dac dgx                /  Yes - Save left end.
rx,    lac .                  / Get the right landing zone end point.
       dac dgy                / Save right end.
    
       lac scx                / Get the x center of the LEM.
       sub dgx                / Check against left edge of landing zone.
       spa                    / Positive?
       jmp nlz                /   No - Point is outside landing zone.
       lac scx                /  Yes - Check right edge of landing zone.
       sub dgy
       sma                    / Negative?
       jmp nlz                /   No - Point is outside landing zone.
       jmp cvv                /  Yes - Hit landing zone check velocity.

nlz,   idx lx                 / Check next landing zone.
       idx rx
       idx sc
       jmp lx

cvv,   lac vy                 /  Yes - Make sure verticle velocity < 100.
       sub (144
       sma                    / Negative?
       jmp sex                /   No - Landing too hard.
       lac vx                 /  Yes - Check horizontal velocity.
       spa                    / Positive?
       cma                    /   No - Compliment want absolute value.
       sub (62                /  Yes - Make sure horizontal velocity < 50.
       sma                    / Negative?
       jmp sex                /   No - Too much drift.

In the above code a jump to sex is NOT a good thing. 

Fuel

The limiting factor in Lunar Lander is fuel. When you run out of fuel the game is over. Implementing fuel ended up being fairly trivial. I created a variable ful and initialized it to 999 "units" (lets say gallons just for fun) at the beginning of a new game. Every time through the main loop I subtract 1 if there is still fuel and the thrust button is pressed. 

/ Process inputs.
pip,    dap pix                / Set return address.
...
ckt,    dzm thr                / Set thrust to off.
        lac cin                / Refetch the input.
        and (100000            / Check for thrust.
        sza i                  / Is thrust?
        jmp pix                /   No - Keep going.
                
        lac ful                /  Yes - Apply thrust velocities if fuel.            
        sza i                  / Is fuel?
        jmp pix                /   No - Don't apply velocities.
        lac vy                 /  Yes - Apply velocities (already calculated).            
        add tv
        dac vy
        lac vx
        sub th
        dac vx    

        lac ful                / Reduce the fuel by 1.
        sub (1
        dac ful
    
        lac (1                 / Indicate that thrust is on. 
        dac thr        

pix,    jmp .                  / Return

Updating Status

I added Fuel (F:) and Score (S:) to the status bar at the top of the screen on the left had side.

/ Draw the fuel status.
dfs,    dap dfx                / Set return address.
        lac (372000            / Set top of fuel position.
        dac dgy
        lac (-361000           / F
        /cma
        dac dgx
        jsp c15
        lac (-344000           / :
        dac dgx
        jsp c10
        lac ful
        dac num                / Save the number.                
        lac (-265000           / Set the x coordinate of the last letter.
        dac dgx                
        jsp ddg                / Display the number.
dfx,    jmp .                  / Return.

/ Draw the score.
drs,    dap dxs                / Set return address.
        lac (346360            / Set top of score position.
        dac dgy
        lac (-361000           / S
        dac dgx
        jsp c14
        lac (-344000           / :
        dac dgx
        jsp c10
        lac sco
        dac num                / Save the number.                
        lac (-265000           / Set the x coordinate of the last letter.
        dac dgx                
        jsp ddg                / Display the number.
dxs,    jmp .                  / Return.

Now here is where my refactoring effort really paid off.  On a "Good Landing" I was able to easily add a little "animation" of the Fuel and Score being updated. I found that just updating these values and immediately carrying on with the game was pretty anticlimactic. Here is the code.

/ Good landing!
sc,     lac .                  / Show the score increasing. Get the score update for this landing site.
        dac tmp                / Save.
slp,    lac sco                / Get the score.
        add (1                
        dac sco                / Update by one.
        jsp drs                / Show the score.
        jsp dtr                / Show terrain.
        lac tmp                / Decrease new score by one.
        sub (1
        dac tmp
        sza                    / Zero?
        jmp slp                /   No - Keep showing score increasing.

        lac (62                /  Yes - Add 50 to fuel.                                            
        dac tmp
sfp,    lac ful                / Get the score.
        add (1                
        dac ful                / Update by one.
        jsp dfs                / Show the fuel.
        jsp dtr                / Show terrain.
        lac tmp                / Decrease new fuel by one.
        sub (1
        dac tmp
        sza                    / Zero?
        jmp sfp                /   No - Keep showing fuel increasing.
        jmp nxr                /  Yes - Restart round.

I was able to show only the elements I wanted to while performing the animated update by calling the appropriate "drawing" subroutines (jsp drs (Score), jsp dsf (Fuel), and jsp dtr (Terrain)).

Here is fuel consumption and scoring in action.

I feel like I could do more here, but OK for now.

Discussions