Version of Robotron arcade game using LPC1768, a Gameduino shield, a serial EEPROM (for high scores), two microswitch joysticks and two buttons plus a box to put it in. 20 levels of mayhem.

Dependencies:   25LCxxx_SPI CommonTypes Gameduino mbed

Files at this revision

API Documentation at this revision

Comitter:
RichardE
Date:
Tue Jun 04 20:16:33 2013 +0000
Child:
1:dfd5eaaf96a3
Commit message:
Started conversion from Maple version of game. So far Gameduino seems to have been initialised OK and just displays a sign on message. Lots of commented out code.

Changed in this revision

CommonTypes.lib Show annotated file Show diff for this revision Revisions of this file
Game.h Show annotated file Show diff for this revision Revisions of this file
GameRobotRic.cpp Show annotated file Show diff for this revision Revisions of this file
GameRobotRic.h Show annotated file Show diff for this revision Revisions of this file
Gameduino.lib Show annotated file Show diff for this revision Revisions of this file
HighScoreEntry.cpp Show annotated file Show diff for this revision Revisions of this file
HighScoreEntry.h Show annotated file Show diff for this revision Revisions of this file
HighScoreTable.cpp Show annotated file Show diff for this revision Revisions of this file
HighScoreTable.h Show annotated file Show diff for this revision Revisions of this file
I2CEEPROM.cpp Show annotated file Show diff for this revision Revisions of this file
I2CEEPROM.h Show annotated file Show diff for this revision Revisions of this file
Level.cpp Show annotated file Show diff for this revision Revisions of this file
Level.h Show annotated file Show diff for this revision Revisions of this file
Level0.cpp Show annotated file Show diff for this revision Revisions of this file
Level0.h Show annotated file Show diff for this revision Revisions of this file
Level1.cpp Show annotated file Show diff for this revision Revisions of this file
Level1.h Show annotated file Show diff for this revision Revisions of this file
Level2.cpp Show annotated file Show diff for this revision Revisions of this file
Level2.h Show annotated file Show diff for this revision Revisions of this file
LevelCollection.cpp Show annotated file Show diff for this revision Revisions of this file
LevelCollection.h Show annotated file Show diff for this revision Revisions of this file
LevelNormal.cpp Show annotated file Show diff for this revision Revisions of this file
LevelNormal.h Show annotated file Show diff for this revision Revisions of this file
PlayerName.cpp Show annotated file Show diff for this revision Revisions of this file
PlayerName.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommonTypes.lib	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/users/RichardE/code/CommonTypes/#033e112463bb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Game.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,27 @@
+/*
+ * SOURCE FILE : Game.h
+ *
+ * Abstract base class for all games.
+ *
+ */
+
+#ifndef GameIncluded
+  
+  #define GameIncluded
+
+  class Game {
+    
+  public :
+
+    /*****************/
+    /* PLAY THE GAME */
+    /*****************/
+    // This NEVER exits.
+    void Play( void );
+    
+  };
+    
+#endif
+
+/* END of Game.h */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GameRobotRic.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,142 @@
+/*
+ * SOURCE FILE : GameRobotRic.cpp
+ *
+ * The RobotRic game class.
+ *
+ */
+
+#include "GameRobotRic.h"          // this module's prototypes
+#include "Types.h"                 // various integer types etc.
+#include "LevelCollection.h"       // all the levels
+#if 0
+    #include "RobotRicCharacterSet.h"  // character set used in this game
+    #include "GDExtra.h"               // extra Gameduino functions
+    #include "GDConst.h"               // a few more Gameduino constants
+    #include "ArenaConst.h"            // gameplay arena constants
+    #include "I2CEEPROM.h"                         // for access to serial EEPROM
+    #include "HighScoreEntry.h"                 // for getting player's name for high score table
+#endif
+
+// Number of lives player starts with.
+#define START_LIVES 5
+
+// Pin allocations for I2C communications link.
+#define EEPROM_SCL 5
+#define EEPROM_SDA 7
+#define EEPROM_WP 8
+
+// Address of EEPROM set using A0, A1 and A2 pins.
+#define ADDRESS_OF_EEPROM 0
+
+/**************************/
+/* CHECK FOR A HIGH SCORE */
+/**************************/
+// Pass pointer to high score table in highScores.
+// Pass score that was achieved in score.
+void GameRobotRic::CheckForHighScore( HighScoreTable *highScores, UInt32 score ) {
+#if 0
+    UInt8 tablePos;
+    // Enter name into high score table if score is high enough.
+    if( ( tablePos = highScores->GetPositionInTable( player.Score ) ) < highScores->GetCapacity() ) {
+        // Player has made it onto the high score table.
+        // Get player to input name.
+        HighScoreEntry nameGetter;
+        PlayerName name;
+        nameGetter.GetName( &name, &controls );
+        // Add name and score to table.
+        highScores->Add( tablePos, &name, score );
+    }
+#endif
+}
+
+/*****************/
+/* PLAY THE GAME */
+/*****************/
+// This NEVER exits.
+void GameRobotRic::Play( void ) {
+    // Make a digital output for use with Gameduino.
+    DigitalOut cs( p8 );
+    // Initialise an SPI link for communications with Gameduino.
+    // Use pin 5 for MOSI.
+    // Use pin 6 for MISO.
+    // Use pin 7 for SCK.
+    SPI spi( p5, p6, p7 );
+    // 8MHz clock should be OK.
+    spi.frequency( 8000000 );
+    // Set SPI format to use.
+    // Use 8 bits per SPI frame.
+    // Use SPI mode 0.
+    spi.format( 8, 0 );
+    // Make a Gameduino and pass SPI link and digital output for chip select.
+    Gameduino gd( &spi, &cs );
+    // Reset the Gameduino.
+    gd.begin();
+    // Lets have a default ASCII character set.
+    gd.ascii();
+    // Display sign on message.
+    gd.putstr( 3, 10, "RobotRic is up and running!" );
+#if 0
+    // Initialise I2C communications (to talk to serial EEPROM).
+  Wire.begin( EEPROM_SDA, EEPROM_SCL );
+    // Initialise serial EEPROM object with EEPROM address of zero.
+    I2CEEPROM eeprom;
+    eeprom.Open( &Wire, ADDRESS_OF_EEPROM, EEPROM_WP );
+    // Create a high score table that uses the EEPROM.
+    HighScoreTable highScores( &eeprom );
+#endif
+  // Start on the attract level.
+  UInt8 levelNumber = LevelCollection::AttractLevel;
+#if 0
+  player.Lives = START_LIVES;
+#endif
+  LevelCollection levels;
+  Level *level;
+  Level::LevelExitCode exitCode;
+#if 0
+  // Initialise panel controls.
+  controls.InitialisePins();
+  // Specify controls player should use.
+  player.SetControls( &controls );
+  // Restrict players movement.
+  player.MovementRestricted = true;
+  player.Bounds = &ArenaRectangle;
+#endif
+  // Repeat forever.
+  while( true ) {
+#if 0
+    // Get level specified by level number.
+    level = levels.GetLevel( levelNumber );
+    // If failed to get level with that number go back to first normal level.
+    // This will happen if player completes last level.
+    if( level == NULL ) {
+      levelNumber = LevelCollection::FirstNormalLevel;
+      // Refetch level.
+      level = levels.GetLevel( levelNumber );
+    }
+        // Pass reference to high score table.
+        level->SetHighScores( &highScores );
+    // Set player that is playing the level.
+    level->SetPlayer( &player );
+    // Play the level.
+    exitCode = level->Play();
+    // If player was killed then decrement lives otherwise
+    // advance to next level.
+    switch( exitCode ) {
+    case Level::GameOver :
+            // TODO : Do some sort of game over fuss.
+            CheckForHighScore( &highScores, player.Score );
+            // Go back to attract level and reset player lives and score.
+            levelNumber = LevelCollection::AttractLevel;
+            player.Lives = START_LIVES;
+            player.Score = 0;
+      break;
+    case Level::Completed :
+      levelNumber++;
+      break;
+    }
+#endif
+    // Finished with Gameduino.
+    gd.end();
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GameRobotRic.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,47 @@
+/*
+ * SOURCE FILE : GameRobotRic.h
+ *
+ * The RobotRic game class.
+ *
+ */
+
+#ifndef GameRobotRicIncluded
+  
+  #define GameRobotRicIncluded
+
+  #include "Gameduino.h"          // Gameduino stuff
+  #include "Game.h"               // base class for all games
+  // #include "PlayerObject.h"
+  #include "HighScoreTable.h"     // for high score table stored in external EEPROM
+
+  class GameRobotRic : public Game {
+    
+  public :
+
+    /*****************/
+    /* PLAY THE GAME */
+    /*****************/
+    // This NEVER exits.
+    void Play( void );
+
+  private :
+  
+    // The one and only player.
+    // PlayerObject player;
+    
+    // Controls used by player.
+    // PanelControls controls;
+    
+    /**************************/
+    /* CHECK FOR A HIGH SCORE */
+    /**************************/
+    // Pass pointer to high score table in highScores.
+    // Pass score that was achieved in score.
+    void CheckForHighScore( HighScoreTable *highScores, UInt32 score );
+
+  };
+    
+#endif
+
+/* END of GameRobotRic.h */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Gameduino.lib	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/users/RichardE/code/Gameduino/#f6a33c5f0f7f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HighScoreEntry.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,173 @@
+/*
+ * SOURCE FILE : HighScoreEntry.cpp
+ *
+ * Definition of class HighScoreEntry.
+ * Routine to allow player to enter their name using joysticks.
+ *
+ */
+
+#include "HighScoreEntry.h"
+#include "Gameduino.h"       // Gameduino stuff
+#if 0
+    #include "GDExtra.h"         // more Gameduino stuff
+    #include "GDConst.h"         // Gameduino constants
+    #include "CharBlocks.h"      // blocks of characters in program memory
+    #include "CharFrame.h"       // for drawing frames made of characters
+    #include "CharCodes.h"       // character codes
+    #include "FrameCounter.h"    // counter updated every vertical flyback
+#endif
+
+/***************/
+/* CONSTRUCTOR */
+/***************/
+HighScoreEntry::HighScoreEntry() :
+  cursorPos( 0 )
+{
+}
+
+/**************/
+/* DESTRUCTOR */
+/**************/
+HighScoreEntry::~HighScoreEntry() {
+}
+
+/*********************/
+/* GET A PLAYER NAME */
+/*********************/
+// Pass pointer to place to store name in name.
+// Pass pointer to controls to read in controls.
+#if 0
+void HighScoreEntry::GetName( PlayerName *name, PanelControls *controls ) {
+  UInt16 inputs;
+  UInt8 countdown = 0;
+  char *curPtr;
+  // Initialise name to all 'A' characters.
+  for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
+    name->Name[ i ] = 'A';
+  }
+  // Draw screen.
+  DrawScreen();
+  // Wait until player releases all controls.
+  WaitControls( controls, false );
+  // Start at leftmost character.
+  cursorPos = 0;
+  // Loop until cursor moves beyond rightmost character.
+  while( cursorPos < PlayerName::Length ) {
+    // Read panel controls.
+    controls->Read();
+    inputs = controls->GetInputs();
+    // Point to character under cursor.
+    curPtr = name->Name + cursorPos;
+    // Only react to controls every so often to slow things down.
+    if( countdown == 0 ) {
+      countdown = 10;
+      if( inputs & PanelControls::Up1 ) {
+        // Joystick up selects next character up.
+        if( *curPtr >= PlayerName::MaxChar ) {
+          *curPtr = PlayerName::MinChar;
+        }
+        else {
+          (*curPtr)++;
+        }
+      }
+      else if( inputs & PanelControls::Down1 ) {
+        // Joystick down selects previous character down.
+        if( *curPtr <= PlayerName::MinChar ) {
+          *curPtr = PlayerName::MaxChar;
+        }
+        else {
+          (*curPtr)--;
+        }
+      }
+      else if( inputs & PanelControls::Left1 ) {
+        // Joystick left moves cursor back.
+        if( cursorPos > 0 ) {
+          cursorPos--;
+          // Wait until all controls released.
+          WaitControls( controls, false );
+        }
+      }
+      else if( inputs & PanelControls::Right1 ) {
+        // Joystick right moves cursor forwards.
+        cursorPos++;
+        // Wait until all controls released.
+        WaitControls( controls, false );
+      }
+    }
+    else {
+      countdown--;
+    }
+    // Wait for vertical flyback. Then draw name and do animation.
+    GD.waitvblank();
+    FrameCounter++;
+    DrawName( name );
+    Animate();
+  }
+  // Wait until player releases all controls before returning.
+  WaitControls( controls, false );
+}
+#endif
+
+/*********************/
+/* WAIT FOR CONTROLS */
+/*********************/
+// Pass pointer to controls to read in controls.
+// Pass true in waitActivate to wait for a control to be used.
+// Pass false to wait for release.
+#if 0
+void HighScoreEntry::WaitControls( PanelControls *controls, bool waitActivate ) {
+  boolean released = false;
+  UInt16 inputs;
+  while( ! released ) {
+    controls->Read();
+    inputs = controls->GetInputs();
+    released = ( waitActivate ? ( inputs != 0 ) : ( inputs == 0 ) );
+    if( ! released ) {
+      GD.waitvblank();
+      FrameCounter++;
+      Animate();
+    }
+  }
+}
+#endif
+
+/*******************/
+/* DRAW THE SCREEN */
+/*******************/
+void HighScoreEntry::DrawScreen( void ) {
+#if 0
+  GD.waitvblank();
+  // Clear the screen to zero characters.
+  GD.fill( RAM_PIC, 0, RAM_PIC_SIZE );
+  // Turn off all the sprites.
+  for( UInt16 s = 0; s < SPRITE_COUNT; ++s ) {
+    GD.sprite( s, 0, 400, 0, 0 );
+  }
+  // Draw border around screen.
+  CharFrame::Draw( 0, 0, VISIBLE_CHAR_WIDTH, VISIBLE_CHAR_HEIGHT );
+  // Draw logo.
+  GDExtra::WriteProgCharBlock( 2, 2, CharBlocks::EnterNameInstructionText );
+#endif
+}
+
+/********************************/
+/* DRAW THE NAME AND THE CURSOR */
+/********************************/
+// Pass player name in name.
+void HighScoreEntry::DrawName( PlayerName *name ) {
+#if 0
+  GD.putstr( 21, 11, name->Name );
+  UInt16 address = RAM_PIC + 12 * SCREEN_CHAR_WIDTH + 21;
+  for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
+    GD.wr( address, ( i == cursorPos ) ? ArrowUp : ' ' );
+    address++;
+  }
+#endif
+}
+
+/********************/
+/* UPDATE ANIMATION */
+/********************/
+void HighScoreEntry::Animate( void ) {
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HighScoreEntry.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,72 @@
+/*
+ * SOURCE FILE : HighScoreEntry.h
+ *
+ * Definition of class HighScoreEntry.
+ * Routine to allow player to enter their name using joysticks.
+ *
+ */
+
+#ifndef HighScoreEntryDefined
+
+  #define HighScoreEntryDefined
+
+  #include "Types.h"
+  // #include "PanelControls.h"   // for reading panel controls.
+  #include "PlayerName.h"
+  
+  class HighScoreEntry {
+
+  public :
+
+    /***************/
+    /* CONSTRUCTOR */
+    /***************/
+    HighScoreEntry();
+
+    /**************/
+    /* DESTRUCTOR */
+    /**************/
+    virtual ~HighScoreEntry();
+
+    /*********************/
+    /* GET A PLAYER NAME */
+    /*********************/
+    // Pass pointer to place to store name in name.
+    // Pass pointer to controls to read in controls.
+    // void GetName( PlayerName *name, PanelControls *controls );
+
+private :
+
+    // Position of cursor (zero for first character).
+    UInt8 cursorPos;
+
+    /*********************/
+    /* WAIT FOR CONTROLS */
+    /*********************/
+    // Pass pointer to controls to read in controls.
+    // Pass true in waitActivate to wait for a control to be used.
+    // Pass false to wait for release.
+    // void WaitControls( PanelControls *controls, bool waitActivate );
+
+    /*******************/
+    /* DRAW THE SCREEN */
+    /*******************/
+    void DrawScreen( void );    
+
+    /********************************/
+    /* DRAW THE NAME AND THE CURSOR */
+    /********************************/
+    // Pass player name in name.
+    void DrawName( PlayerName *name );
+    
+    /********************/
+    /* UPDATE ANIMATION */
+    /********************/
+    void Animate( void );
+
+  };
+
+#endif
+
+/* END of HighScoreEntry.h */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HighScoreTable.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,259 @@
+/*
+ * SOURCE FILE : HighScoreTable.cpp
+ *
+ * Definition of class HighScoreTable.
+ * Maintains a table of high scores with a name and a score for each entry in the table.
+ *
+ * The table is stored in EEPROM at an address specified when you call the constructor.
+ * The table is structured as follows. This shows a table with a capacity of 3.
+ *
+ * Byte offset      Usage
+ * -----------      -----
+ * 0                Index of highest score in data that follows
+ * 1                Index of second highest score in data that follows
+ * 2                Index of third highest score in data that follows
+ *
+ * 3                First character of player's name
+ * 4                Second character of player's name
+ * 5                Third character of player's name
+ * 6                LSB of score (in BCD)
+ * 7                Byte 1 of score (in BCD)
+ * 8                Byte 2 of score (in BCD)
+ * 9                MSB of score (in BCD)
+ * 10               Unused
+ *
+ * 11               First character of player's name
+ * 12               Second character of player's name
+ * 13               Third character of player's name
+ * 14               LSB of score (in BCD)
+ * 15               Byte 1 of score (in BCD)
+ * 16               Byte 2 of score (in BCD)
+ * 17               MSB of score (in BCD)
+ * 18               Unused
+ *
+ * 19               First character of player's name
+ * 20               Second character of player's name
+ * 21               Third character of player's name
+ * 22               LSB of score (in BCD)
+ * 23               Byte 1 of score (in BCD)
+ * 24               Byte 2 of score (in BCD)
+ * 25               MSB of score (in BCD)
+ * 26               Unused
+ *
+ * So, assuming the capacity of the table is N, the first N bytes form an index which is used to locate
+ * items in the remaining N*8 bytes that follow. This is done so that inserting a new entry only involves
+ * overwriting one name/score record and updating the index. You don't have to re-write all the records
+ * that move down the table to make room for the new one.
+ *
+ */
+
+#include "HighScoreTable.h"
+
+/***************/
+/* CONSTRUCTOR */
+/***************/
+// Pass pointer to an I2C EEPROM which contains the high scores.
+HighScoreTable::HighScoreTable( I2CEEPROM *e ) :
+    eeprom( e )
+{
+}
+
+/**************/
+/* DESTRUCTOR */
+/**************/
+HighScoreTable::~HighScoreTable() {
+}
+
+/****************************************/
+/* VALIDATE EEPROM USED FOR HIGH SCORES */
+/****************************************/
+// Checks EEPROM used for high scores and
+// if any of it looks like nonsense it
+// rewrites the whole table with defaults.
+void HighScoreTable::ValidateEEPROM( void ) {
+  // Check if contents of EEPROM make sense.
+  // If not then rewrite EEPROM with defaults.
+  if( ! EEPROMValid() ) {
+    WriteEEPROMDefaults();
+  }
+}
+
+/**********************************************/
+/* DETERMINE POSITION OF A SCORE IN THE TABLE */
+/**********************************************/
+// Pass score in score.
+// Returns position in table (0 is top score).
+// If position returned is >= capacity of table then score is not high
+// enough to place in table.
+UInt8 HighScoreTable::GetPositionInTable( UInt32 score ) const {
+  // Look through table for a score less than the one passed.
+  PlayerName name;
+  UInt32 tableScore = (UInt32)0;
+  for( UInt8 i = 0; i < capacity; ++i ) {
+    Get( i, &name, &tableScore );
+    if( tableScore < score ) {
+      // Found a score that is less.
+      // Return index at which it was found.
+      return i;
+    }
+  }
+  // No score found that is less than the one passed.
+  // Return capacity of table to indicate not found.
+  return capacity;
+}
+
+/*********************************/
+/* ADD ENTRY TO HIGH SCORE TABLE */
+/*********************************/
+// Pass position in table to put entry in pos.
+// Pass name of player in name.
+// Pass score in score.
+void HighScoreTable::Add( UInt8 pos, const PlayerName *name, UInt32 score ) {
+    // Read the entire index, high scores and names out of EEPROM.
+    // Going to do manipulations in RAM to minimise the number of
+    // writes we need to do to EEPROM. Remember every time we write
+    // a single byte a whole page is written so might as well
+    // write a whole page in one go. Only drawback is more RAM
+    // is required.
+    UInt8 buffer[ memoryUsed ];
+    if( eeprom->ReadBytes( eepromAddress, buffer, memoryUsed ) ) {
+        // Fetch index for lowest score in the table.
+        UInt8 index = buffer[ capacity - 1 ];
+        // Make sure index is within range.
+        if( index < capacity ) {
+            // Point to section of buffer that contains name and score for
+            // lowest score.
+            UInt8 *address = buffer + capacity + ( index << 3 );
+            // Copy characters of name into buffer.
+            for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
+                *address++ = name->Name[ i ];
+            }
+            // Copy bytes of score into buffer.
+            *((UInt32*)address) = score;
+            address += 4;
+            // Move all entries in the index below insertion point down one
+            // to make room for new entry.
+            for( UInt8 i = capacity - 1; i > pos; --i ) {
+                buffer[ i ] = buffer[ i - 1 ];
+            }
+            // Insert index of newly written record at insertion point.
+            buffer[ pos ] = index;
+            // Write the buffer back to EEPROM.
+            eeprom->WriteBytes( eepromAddress, buffer, memoryUsed ); 
+        }
+    }
+}
+
+/****************************/
+/* GET ENTRY FROM THE TABLE */
+/****************************/
+// Pass position to fetch from in pos.
+// Player name is returned in object pointed to by name.
+// Player score is returned in integer pointed to by score.
+void HighScoreTable::Get( UInt8 pos, PlayerName *name, UInt32 *score ) const {
+    // Write default values to name and score.
+  for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
+    name->Name[ i ] = (UInt8)'X';
+  }
+  name->Name[ PlayerName::Length ] = 0;
+    *score = 0;
+  // Fetch index from EEPROM.
+  UInt8 index;
+    if( ! eeprom->ReadBytes( eepromAddress + pos, &index, 1 ) ) {
+        return;
+    }
+  // Point to appropriate part of data table.
+  UInt16 address = eepromAddress + capacity + ( index << 3 );
+  // Read out characters and store in name.
+    if( ! eeprom->ReadBytes( address, (UInt8*)name->Name, PlayerName::Length ) ) {
+        return;
+    }
+  name->Name[ PlayerName::Length ] = 0;
+    address += PlayerName::Length;
+  // Read out score.
+    eeprom->ReadBytes( address, (UInt8*)score, 4 );
+}
+
+/********************************/
+/* DETERMINE IF EEPROM IS VALID */
+/********************************/
+// Returns true if EEPROM is valid.
+bool HighScoreTable::EEPROMValid( void ) {
+  UInt8 b, b2;
+  // Check all entries in the index are within range and are unique.
+  for( UInt8 i = 0; i < capacity; ++i ) {
+    // Read byte from EEPROM.
+        if( ! eeprom->ReadBytes( eepromAddress + i, &b, 1 ) ) {
+            return false;
+        }
+    // Check index read is less than capacity.
+    if( b >= capacity ) {
+      return false;
+    }
+    // Check if any of the following bytes in the index have
+    // the same value.
+    for( UInt8 j = i + 1; j < capacity; ++j ) {
+            if( ! eeprom->ReadBytes( eepromAddress + j, &b2, 1 ) ) {
+                return false;
+            }
+      if( b == b2 ) {
+        return false;
+      }
+    }
+  }
+  // Check all entries in the data part of the table are valid.
+  UInt16 address = eepromAddress + capacity;
+  for( UInt8 i = 0; i < capacity; ++i ) {
+    // Check name consists only of uppercase letters.
+    for( UInt8 j = 0; j < PlayerName::Length; ++j ) {
+            // Read byte from EEPROM.
+            if( ! eeprom->ReadBytes( address++, &b, 1 ) ) {
+                return false;
+            }
+      if( ( b < PlayerName::MinChar ) || ( b > PlayerName::MaxChar ) ) {
+        return false;
+      }
+    }
+    // Check score consists only of valid BCD numbers.
+    for( UInt8 j = 0; j < 4; ++j ) {
+            // Read byte from EEPROM.
+            if( ! eeprom->ReadBytes( address++, &b, 1 ) ) {
+                return false;
+            }
+      if( ( ( b & 0x0F ) > 0x09 ) || ( ( b & 0xF0 ) > 0x90 ) ) {
+        return false;
+      }
+    }
+    // Skip over unused byte.
+    address++;
+  }
+  // EEPROM is valid
+  return true;
+}
+
+/****************************/
+/* WRITE DEFAULTS TO EEPROM */
+/****************************/
+// This may take a second or two to execute!
+void HighScoreTable::WriteEEPROMDefaults( void ) {
+    UInt8 buffer[ memoryUsed ];
+  // Write index with ascending integers.
+    UInt8 *ptr = buffer;
+  for( UInt8 i = 0; i < capacity; ++i ) {
+    *ptr++ =  i;
+  }
+  // Write data table with zero score entries.  
+  for( UInt8 i = 0; i < capacity; ++i ) {
+    // Write a name of "AAA".
+    for( UInt8 j = 0; j < PlayerName::Length; ++j ) {
+            *ptr++ = (UInt8)'A';
+    }
+        // Write a score of zero.
+    *((UInt32*)ptr) = 0;
+        ptr += 4;
+        // Write zero to unused byte.
+        *ptr++ = 0;    
+    }
+    // Write the buffer to EEPROM.
+    eeprom->WriteBytes( eepromAddress, buffer, memoryUsed ); 
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HighScoreTable.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,111 @@
+/*
+ * SOURCE FILE : HighScoreTable.h
+ *
+ * Definition of class HighScoreTable.
+ * Maintains a table of high scores with a name and a score for each entry in the table.
+ *
+ */
+
+#ifndef HighScoreTableDefined
+
+  #define HighScoreTableDefined
+
+  #include "Types.h"
+  #include "PlayerName.h"
+  #include "I2CEEPROM.h"
+  
+  class HighScoreTable {
+
+  public :
+
+    /***************/
+    /* CONSTRUCTOR */
+    /***************/
+        // Pass pointer to an I2C EEPROM which contains the high scores.
+    HighScoreTable( I2CEEPROM *e );
+
+    /**************/
+    /* DESTRUCTOR */
+    /**************/
+    virtual ~HighScoreTable();
+
+        /***************************************/
+        /* GET EEPROM USED BY HIGH SCORE TABLE */
+        /***************************************/
+        I2CEEPROM *GetEEPROM( void ) const {
+            return eeprom;
+        }
+        
+    /****************************************/
+    /* VALIDATE EEPROM USED FOR HIGH SCORES */
+    /****************************************/
+    // Checks EEPROM used for high scores and
+    // if any of it looks like nonsense it
+    // rewrites the whole table with defaults.
+    void ValidateEEPROM( void );
+
+    /********************************/
+    /* DETERMINE IF EEPROM IS VALID */
+    /********************************/
+    // Returns true if EEPROM is valid.
+    bool EEPROMValid( void );
+    
+  /*************************/
+    /* GET CAPACITY OF TABLE */
+    /*************************/
+    // Returns capacity of table.
+    UInt8 GetCapacity( void ) const {
+      return capacity;
+    }
+    
+    /**********************************************/
+    /* DETERMINE POSITION OF A SCORE IN THE TABLE */
+    /**********************************************/
+    // Pass score in score.
+    // Returns position in table (0 is top score).
+    // If position returned is >= capacity of table then score is not high
+    // enough to place in table.
+    UInt8 GetPositionInTable( UInt32 score ) const;
+    
+    /*********************************/
+    /* ADD ENTRY TO HIGH SCORE TABLE */
+    /*********************************/
+    // Pass position in table to put entry in pos.
+    // Pass name of player in name.
+    // Pass score in score.
+    void Add( UInt8 pos, const PlayerName *name, UInt32 score );
+
+    /****************************/
+    /* GET ENTRY FROM THE TABLE */
+    /****************************/
+    // Pass position to fetch from in pos.
+    // Player name is returned in object pointed to by name.
+    // Player score is returned in integer pointed to by score.
+    void Get( UInt8 pos, PlayerName *name, UInt32 *score ) const;
+    
+  private :
+
+    // Change the following to suit.
+    enum {
+      eepromAddress = 0,    // address in EEPROM where high score table starts
+      capacity = 10,        // number of entries in table
+            // Amount of memory used in EEPROM.
+            // You need capacity bytes for the index and then
+            // eight bytes for each high score and name.
+            memoryUsed = capacity + ( capacity << 3 ),
+    };
+
+        // Pointer to EEPROM that holds high scores.
+        I2CEEPROM *eeprom;
+        
+    /****************************/
+    /* WRITE DEFAULTS TO EEPROM */
+    /****************************/
+    void WriteEEPROMDefaults( void );
+    
+  };
+
+#endif
+
+/* END of HighScoreTable.h */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/I2CEEPROM.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,191 @@
+/*
+ * SOURCE FILE : I2CEEPROM.cpp
+ *
+ * Definition of class I2CEEPROM.
+ * Rountines for communicating with a serial EEPROM over an I2C link.
+ * EEPROM in question is a Microchip 24AA512.
+ * Remember you need pullup resistors on the SCL, SDA and WP lines.
+ *
+ */
+
+#include "I2CEEPROM.h"
+
+/***************/
+/* CONSTRUCTOR */
+/***************/
+I2CEEPROM::I2CEEPROM() :
+    isOpen( false ),
+    // wire( (TwoWire*)NULL ),
+    wp( 8 )
+{
+}
+
+/**************/
+/* DESTRUCTOR */
+/**************/
+I2CEEPROM::~I2CEEPROM() {
+}
+
+/**************************************/
+/* PREPARE TO COMMUNICATE WITH EEPROM */
+/**************************************/
+// Pass pointer to TwoWire object to use for I2C communications
+// which should have been initialised and opened before calling this.
+// Pass 3 bit address of EEPROM (as set by A0, A1 and A2 pins) in ea.
+// Pass pin number to use for write protect in wp.
+#if 0
+void I2CEEPROM::Open( TwoWire *wire, UInt8 ea, UInt8 wp ) {
+    if( ! isOpen ) {
+        // Save pointer to TwoWire object.
+        this->wire = wire;
+        // Calculate slave address.
+        slaveAddress = (UInt8)( ( ea & 0x7 ) | 0x50 );
+        // Save write protect pin number.
+        this->wp = wp;
+        // Configure write protect pin as open drain output.
+        pinMode( wp, OUTPUT_OPEN_DRAIN );
+        // Write protect EEPROM.
+        digitalWrite( wp, HIGH );
+        isOpen = true;
+    }
+}
+#endif
+
+/*********************************************/
+/* SHUT DOWN COMMUNICATIONS LINK WITH EEPROM */
+/*********************************************/
+void I2CEEPROM::Close( void ) {
+    isOpen = false;
+}
+
+// Size of each chunk read or written.
+#define CHUNK_SIZE ( WIRE_BUFSIZ - 2 )
+
+/************************************/
+/* ATTEMPT TO READ A CHUNK OF BYTES */
+/************************************/
+// Pass address within EEPROM in address.
+// Pass pointer to buffer for bytes read in buffer.
+// Returns false if a failure occurred whilst reading EEPROM.
+// Pass number of bytes to read in count.
+// Returns true if successful, false if not.
+// The number of bytes read must not exceed CHUNK_SIZE.
+bool I2CEEPROM::ReadChunk( UInt16 address, UInt8 *buffer, UInt8 count ) {
+#if 0
+  // First send address you want to read from.
+  wire->beginTransmission( slaveAddress );
+  // Add high byte of EEPROM address to read from.
+  wire->send( ( address >> 8 ) & 0xFF );
+  // Add low byte of EEPROM address to read from.
+  wire->send( address & 0xFF );
+  // Send the packet and return false on failure.
+  if( wire->endTransmission() != SUCCESS ) {
+        return false;
+    }
+  // Now read back data.
+  wire->requestFrom( slaveAddress, count );
+    UInt16 readCount = 0;
+  while( ( wire->available() > 0 ) && ( readCount < count ) ) {
+        *buffer++ = wire->receive();
+        readCount++;
+  }
+    return true;
+#else
+  return false;
+#endif
+}
+
+/*************************************/
+/* ATTEMPT TO READ A NUMBER OF BYTES */
+/*************************************/
+// Pass address within EEPROM in address.
+// Pass pointer to buffer for bytes read in buffer.
+// Returns false if a failure occurred whilst reading EEPROM.
+// Pass number of bytes to read in count.
+// Returns true if successful, false if not.
+bool I2CEEPROM::ReadBytes( UInt16 address, UInt8 *buffer, UInt16 count ) {
+#if 0
+    bool ok = true;
+    // Keep reading chunks until all bytes read.
+    while( ( count > 0 ) && ok ) {
+        if( count > CHUNK_SIZE ) {
+            ok = ReadChunk( address, buffer, (UInt8)CHUNK_SIZE );
+            address += CHUNK_SIZE;
+            buffer += CHUNK_SIZE;
+            count -= CHUNK_SIZE;
+        }
+        else {
+            ok = ReadChunk( address, buffer, (UInt8)count );
+            count = 0;
+        }
+    }
+    // Return true on success.
+    return ok;
+#else
+  return false;
+#endif
+}
+
+/**************************************/
+/* ATTEMPT TO WRITE A CHUNK TO EEPROM */
+/**************************************/
+// Pass address within EEPROM in address.
+// Pass pointer to buffer of bytes to write in buffer.
+// Pass number of bytes to write in count.
+// Returns true if successful, false if not.
+// The number of bytes written must not exceed CHUNK_SIZE.
+bool I2CEEPROM::WriteChunk( UInt16 address, const UInt8 *buffer, UInt8 count ) {
+#if 0
+  // First send address you want to write to.
+  wire->beginTransmission( slaveAddress );
+  // Add high byte of EEPROM address to write to.
+  wire->send( ( address >> 8 ) & 0xFF );
+  // Add low byte of EEPROM address to write to.
+  wire->send( address & 0xFF );
+    // Add buffer bytes.
+    wire->send( (uint8*)buffer, count );
+  // Send the packet.
+    // Return true if successful.
+  return ( wire->endTransmission() == SUCCESS );
+#else
+  return false;
+#endif
+}
+
+/**************************************/
+/* ATTEMPT TO WRITE A NUMBER OF BYTES */
+/**************************************/
+// Pass address within EEPROM in address.
+// Pass pointer to buffer of bytes to write in buffer.
+// Pass number of bytes to write in count.
+// Returns true if successful, false if not.
+bool I2CEEPROM::WriteBytes( UInt16 address, const UInt8 *buffer, UInt16 count ) {
+#if 0
+    bool ok = true;
+    // Write enable EEPROM and wait a bit.
+    digitalWrite( wp, LOW );
+    delay( 1 );
+    // Keep writing chunks until all bytes written.
+    while( ( count > 0 ) && ok ) {
+        if( count > CHUNK_SIZE ) {
+            ok = WriteChunk( address, buffer, (UInt8)CHUNK_SIZE );
+            address += CHUNK_SIZE;
+            buffer += CHUNK_SIZE;
+            count -= CHUNK_SIZE;
+        }
+        else {
+            ok = WriteChunk( address, buffer, (UInt8)count );
+            count = 0;
+        }
+        // Wait a lot to allow page to be written.
+        delay( 6 );
+    }
+    // Write protect EEPROM.
+    digitalWrite( wp, HIGH );
+    // Return true on success.
+    return ok;
+#else
+  return false;
+#endif
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/I2CEEPROM.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,113 @@
+/*
+ * SOURCE FILE : I2CEEPROM.h
+ *
+ * Definition of class I2CEEPROM.
+ * Rountines for communicating with a serial EEPROM over an I2C link.
+ * EEPROM in question is a Microchip 24AA512.
+ * Remember you need pullup resistors on the SCL, SDA and WP lines.
+ *
+ */
+
+#ifndef I2CEEPROMDefined
+
+  #define I2CEEPROMDefined
+
+    #include "Types.h"
+    // #include "CDFWire.h"        // tweaked version of Wire library
+    
+  class I2CEEPROM {
+
+  public :
+
+    /***************/
+    /* CONSTRUCTOR */
+    /***************/
+    I2CEEPROM();
+        
+    /**************/
+    /* DESTRUCTOR */
+    /**************/
+    virtual ~I2CEEPROM();
+
+        /**************************************/
+        /* PREPARE TO COMMUNICATE WITH EEPROM */
+        /**************************************/
+        // Pass pointer to TwoWire object to use for I2C communications.
+        // Pass 3 bit address of EEPROM (as set by A0, A1 and A2 pins) in ea.
+        // Pass pin number to use for write protect in wp.
+        // void Open( TwoWire *wire, UInt8 ea, UInt8 wp );
+        
+        /*********************************************/
+        /* SHUT DOWN COMMUNICATIONS LINK WITH EEPROM */
+        /*********************************************/
+        void Close( void );
+        
+        /*****************************************/
+        /* DETERMINE IF LINK WITH EEPROM IS OPEN */
+        /*****************************************/
+        // Returns true if link is open.
+        bool IsOpen( void ) {
+            return isOpen;
+        }
+        
+        /*************************************/
+        /* ATTEMPT TO READ A NUMBER OF BYTES */
+        /*************************************/
+        // Pass address within EEPROM in address.
+        // Pass pointer to buffer for bytes read in buffer.
+        // Pass number of bytes to read in count.
+        // Returns true if successful, false if not.
+        bool ReadBytes( UInt16 address, UInt8 *buffer, UInt16 count );
+
+        /**************************************/
+        /* ATTEMPT TO WRITE A NUMBER OF BYTES */
+        /**************************************/
+        // Pass address within EEPROM in address.
+        // Pass pointer to buffer of bytes to write in buffer.
+        // Pass number of bytes to write in count.
+        // Returns true if successful, false if not.
+        bool WriteBytes( UInt16 address, const UInt8 *buffer, UInt16 count );
+        
+private :
+
+        // Indicates connection with EEPROM is open.
+        bool isOpen;
+
+        // Pointer to object that does I2C communications.
+        // TwoWire *wire;
+        
+        // Slave address consisting of three bits that identify the
+        // particular EEPROM on the I2C bus, plus bits 3 to 7 are
+        // set to 01010 binary (see 24AA512 dtasheet).
+        UInt8 slaveAddress;
+        
+        // Pin number for write protect pin.
+        UInt8 wp;
+
+        /************************************/
+        /* ATTEMPT TO READ A CHUNK OF BYTES */
+        /************************************/
+        // Pass address within EEPROM in address.
+        // Pass pointer to buffer for bytes read in buffer.
+        // Returns false if a failure occurred whilst reading EEPROM.
+        // Pass number of bytes to read in count.
+        // Returns true if successful, false if not.
+        // The number of bytes read must not exceed CHUNK_SIZE.
+        bool ReadChunk( UInt16 address, UInt8 *buffer, UInt8 count );
+
+        /**************************************/
+        /* ATTEMPT TO WRITE A CHUNK TO EEPROM */
+        /**************************************/
+        // Pass address within EEPROM in address.
+        // Pass pointer to buffer of bytes to write in buffer.
+        // Pass number of bytes to write in count.
+        // Returns true if successful, false if not.
+        // The number of bytes written must not exceed WIRE_BUFSIZ - 2.
+        bool WriteChunk( UInt16 address, const UInt8 *buffer, UInt8 count );
+
+  };
+
+#endif
+
+/* END of I2CEEPROM.h */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Level.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,26 @@
+/*
+ * SOURCE FILE : Level.cpp
+ *
+ * Definition of class Level.
+ * Base class for all levels.
+ *
+ */
+
+#include "Level.h"
+
+/***************/
+/* CONSTRUCTOR */
+/***************/
+Level::Level() :
+  LevelNumber( 0 ),
+  highScores( (HighScoreTable*)NULL )
+  // player( (PlayerObject*)NULL )
+{
+}
+
+/**************/
+/* DESTRUCTOR */
+/**************/
+Level::~Level() {
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Level.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,102 @@
+/*
+ * SOURCE FILE : Level.h
+ *
+ * Definition of class Level.
+ * Base class for all levels.
+ *
+ */
+
+#ifndef LevelDefined
+
+  #define LevelDefined
+
+  #include "Types.h"
+  #include "Gameduino.h"               // Gameduino library
+  #include "HighScoreTable.h"
+#if 0
+  #include "GDConst.h"                 // a few more Gameduino constants
+  #include "GDExtra.h"                 // a few more Gameduino related functions
+  #include "ArenaConst.h"
+  #include "SpriteImageId.h"
+  #include "CharCodes.h"               // character codes
+  #include "GameObject.h"
+  #include "GruntObject.h"
+  #include "BlueMeanyObject.h"
+  #include "CrusherObject.h"
+    #include "BrainObject.h"
+  #include "StringData.h"
+  #include "CharFrame.h"
+  #include "SoundManager.h"
+  #include "Sounds.h"
+#endif
+  
+  class Level {
+
+  public :
+
+    // Number of this level.
+    UInt8 LevelNumber;
+    
+    /***************/
+    /* CONSTRUCTOR */
+    /***************/
+    Level();
+
+    /**************/
+    /* DESTRUCTOR */
+    /**************/
+    virtual ~Level();
+
+    /************************/
+    /* SET HIGH SCORE TABLE */
+    /************************/
+    // Pass pointer to EEPROM in e.
+    void SetHighScores( HighScoreTable *hst ) {
+        highScores = hst;
+    }
+        
+    /***************************************/
+    /* SET PLAYER WHO IS PLAYING THE LEVEL */
+    /***************************************/
+    // Pass pointer to player in p.
+#if 0
+    void SetPlayer( PlayerObject *p ) {
+      player = p;
+    }
+#endif
+    
+    // Enumeration of reasons why level ended.
+    enum LevelExitCode {
+      Completed,       // level was completed
+      GameOver,        // player has no more lives
+    };
+    
+    /**************/
+    /* PLAY LEVEL */
+    /**************/
+    // Returns code indicating how level ended.
+    virtual LevelExitCode Play( void ) = 0;
+    
+  protected :
+  
+        // Pointer to high score table.
+        HighScoreTable *highScores;
+        
+    // Player playing the level.
+    // PlayerObject *player;
+    
+    /*************/
+    /* PLAY LOOP */
+    /*************/
+    // Returns code indicating how level ended.
+    // This method should be called from the Play method after the
+    // level data has been initialised and the return value returned
+    // by the Play method.
+    virtual LevelExitCode PlayLoop( void ) = 0;
+
+  };
+
+#endif
+
+/* END of Level.h */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Level0.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,107 @@
+/*
+ * SOURCE FILE : Level0.cpp
+ *
+ * Definition of class Level0.
+ *
+ */
+
+#include "Level0.h"
+#if 0
+    #include "CharBlocks.h"
+    #include "EEPROMDump.h"
+#endif
+
+/***************/
+/* CONSTRUCTOR */
+/***************/
+Level0::Level0() {
+}
+
+/**************/
+/* DESTRUCTOR */
+/**************/
+Level0::~Level0() {
+}
+
+/**************/
+/* PLAY LEVEL */
+/**************/
+// Returns code indicating how level ended.
+Level::LevelExitCode Level0::Play( void ) {
+  return PlayLoop();
+}
+
+static const char startText[] = "OPERATE EITHER JOYSTICK TO START GAME";
+
+/********************/
+/* DRAW HIGH SCORES */
+/********************/
+void Level0::DrawHighScores( void ) {
+#if 0
+  // Draw high score table.
+  GDExtra::WriteProgString( 16, 11, StringData::HighScoresString );
+  PlayerName name;
+  UInt32 score;
+  UInt8 y = 13;
+  for( UInt8 i = 0; i < highScores->GetCapacity(); ++i ) {
+    highScores->Get( i, &name, &score );
+    GD.putstr( 18, y, name.Name );
+    GDExtra::WriteBCDNumber( 22, y, score, 8 );
+    y += 2;
+  }
+#endif
+}
+
+/*************/
+/* PLAY LOOP */
+/*************/
+// Returns code indicating how level ended.
+// This method should be called from the Play method after the
+// level data has been initialised and the return value returned
+// by the Play method.
+Level::LevelExitCode Level0::PlayLoop( void ) {
+#if 0
+  // Set screen background to black.
+  GD.wr( BG_COLOR, RGB( 0, 0, 0 ) );
+  GDExtra::ClearScreen( TransparentChar );
+  GDExtra::HideAllSprites();
+  SoundManager::Instance.SilenceAll();
+  // Draw border around screen.
+  CharFrame::Draw( 0, 0, VISIBLE_CHAR_WIDTH, VISIBLE_CHAR_HEIGHT );
+  // Draw big block of characters that read "ROBOTRIC".
+  GDExtra::WriteProgCharBlock( 2, 2, CharBlocks::RobotRicText );
+    // Write message telling user how to start game.
+    GDExtra::WriteProgString( 2, VISIBLE_CHAR_HEIGHT - 3, startText );
+    // Validate high scores in EEPROM which will re-write the entire
+    // table with default data if it finds nonsense in the EEPROM.
+    // Then check if EEPROM now makes sense. If it does then display
+    // the high score table. If it does not then chances are there
+    // is no EEPROM connected so don't bother with high scores.
+    if( highScores != (HighScoreTable*)NULL ) {
+        highScores->ValidateEEPROM();
+        if( highScores->EEPROMValid() ) {
+            DrawHighScores();
+        }
+    }
+  // Must have a player with non-NULL controls.
+  PanelControls *controls;
+  if(
+    ( player != (PlayerObject*)NULL ) &&
+    ( ( controls = player->GetControls() ) != (PanelControls*)NULL )
+  ) {
+    // Wait until all panel controls are released.
+    UInt16 inputs;
+    do {
+      controls->Read();
+      inputs = controls->GetInputs();
+    } while( inputs != 0 );
+    // Wait until a panel control is activated.
+    do {
+      controls->Read();
+      inputs = controls->GetInputs();
+    } while( inputs == 0 );
+  }
+#endif
+  return Completed;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Level0.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,55 @@
+/*
+ * SOURCE FILE : Level0.h
+ *
+ * Definition of class Level0.
+ *
+ */
+
+#ifndef Level0Defined
+
+  #define Level0Defined
+
+  #include "Level.h"
+  
+  class Level0 : public Level {
+
+  public :
+
+    /***************/
+    /* CONSTRUCTOR */
+    /***************/
+    Level0();
+
+    /**************/
+    /* DESTRUCTOR */
+    /**************/
+    virtual ~Level0();
+
+    /**************/
+    /* PLAY LEVEL */
+    /**************/
+    // Returns code indicating how level ended.
+    virtual LevelExitCode Play( void );    
+
+  protected :
+  
+        /********************/
+        /* DRAW HIGH SCORES */
+        /********************/
+        void DrawHighScores( void );
+
+    /*************/
+    /* PLAY LOOP */
+    /*************/
+    // Returns code indicating how level ended.
+    // This method should be called from the Play method after the
+    // level data has been initialised and the return value returned
+    // by the Play method.
+    LevelExitCode PlayLoop( void );
+
+  };
+
+#endif
+
+/* END of Level0.h */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Level1.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,53 @@
+/*
+ * SOURCE FILE : Level1.cpp
+ *
+ * Definition of class Level1.
+ * Machine written by program MapleRobotRicLevelGenerator.
+ * DO NOT EDIT BY HAND!
+ *
+ */
+
+#include "Level1.h"
+
+/**************/
+/* PLAY LEVEL */
+/**************/
+// Returns code indicating how level ended.
+Level::LevelExitCode Level1::Play( void ) {
+#if 0
+  LevelData dataForThisLevel;
+  GameObject **ptr = dataForThisLevel.Enemies;
+  UInt8 i, humanCount, enemyCount = 0;
+  // Enemies of type GruntObject.
+  #define GRUNTOBJECTCOUNT 5
+  GruntObject gruntobjects[ GRUNTOBJECTCOUNT ];
+  for( i = 0; i < GRUNTOBJECTCOUNT; ++i ) {
+    if( enemyCount < LevelData::MaxEnemies ) {
+      *ptr++ = gruntobjects + i;
+      enemyCount++;
+    }
+  }
+  // Enemies of type CrusherObject.
+  #define CRUSHEROBJECTCOUNT 5
+  CrusherObject crusherobjects[ CRUSHEROBJECTCOUNT ];
+  for( i = 0; i < CRUSHEROBJECTCOUNT; ++i ) {
+    if( enemyCount < LevelData::MaxEnemies ) {
+      *ptr++ = crusherobjects + i;
+      enemyCount++;
+    }
+  }
+  // Humans.
+  #define HUMANCOUNT 5
+  HumanObject humans[ HUMANCOUNT ];
+  ptr = dataForThisLevel.Humans;
+  humanCount = ( HUMANCOUNT > LevelData::MaxHumans ) ? LevelData::MaxHumans : HUMANCOUNT;
+  for( i = 0; i < humanCount; ++i ) {
+    *ptr++ = humans + i;
+  }
+  DataForLevel = &dataForThisLevel;
+  return PlayLoop();
+#else
+  return Completed;
+#endif
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Level1.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,30 @@
+/*
+ * SOURCE FILE : Level1.h
+ *
+ * Definition of class Level1.
+ * Machine written by program MapleRobotRicLevelGenerator.
+ * DO NOT EDIT BY HAND!
+ *
+ */
+
+#ifndef Level1Defined
+
+  #define Level1Defined
+
+  #include "LevelNormal.h"
+
+  class Level1 : public LevelNormal {
+
+  public :
+
+    /**************/
+    /* PLAY LEVEL */
+    /**************/
+    // Returns code indicating how level ended.
+    virtual LevelExitCode Play( void );
+
+  };
+
+#endif
+
+/* END of Level1.h */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Level2.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,52 @@
+/*
+ * SOURCE FILE : Level2.cpp
+ *
+ * Definition of class Level2.
+ * Machine written by program MapleRobotRicLevelGenerator.
+ * DO NOT EDIT BY HAND!
+ *
+ */
+
+#include "Level2.h"
+
+/**************/
+/* PLAY LEVEL */
+/**************/
+// Returns code indicating how level ended.
+Level::LevelExitCode Level2::Play( void ) {
+#if 0
+  LevelData dataForThisLevel;
+  GameObject **ptr = dataForThisLevel.Enemies;
+  UInt8 i, humanCount, enemyCount = 0;
+  // Enemies of type GruntObject.
+  #define GRUNTOBJECTCOUNT 10
+  GruntObject gruntobjects[ GRUNTOBJECTCOUNT ];
+  for( i = 0; i < GRUNTOBJECTCOUNT; ++i ) {
+    if( enemyCount < LevelData::MaxEnemies ) {
+      *ptr++ = gruntobjects + i;
+      enemyCount++;
+    }
+  }
+  // Enemies of type BrainObject.
+  #define BRAINOBJECTCOUNT 2
+  BrainObject brainobjects[ BRAINOBJECTCOUNT ];
+  for( i = 0; i < BRAINOBJECTCOUNT; ++i ) {
+    if( enemyCount < LevelData::MaxEnemies ) {
+      *ptr++ = brainobjects + i;
+      enemyCount++;
+    }
+  }
+  // Humans.
+  #define HUMANCOUNT 6
+  HumanObject humans[ HUMANCOUNT ];
+  ptr = dataForThisLevel.Humans;
+  humanCount = ( HUMANCOUNT > LevelData::MaxHumans ) ? LevelData::MaxHumans : HUMANCOUNT;
+  for( i = 0; i < humanCount; ++i ) {
+    *ptr++ = humans + i;
+  }
+  DataForLevel = &dataForThisLevel;
+  return PlayLoop();
+#else
+  return Completed;
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Level2.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,30 @@
+/*
+ * SOURCE FILE : Level2.h
+ *
+ * Definition of class Level2.
+ * Machine written by program MapleRobotRicLevelGenerator.
+ * DO NOT EDIT BY HAND!
+ *
+ */
+
+#ifndef Level2Defined
+
+  #define Level2Defined
+
+  #include "LevelNormal.h"
+
+  class Level2 : public LevelNormal {
+
+  public :
+
+    /**************/
+    /* PLAY LEVEL */
+    /**************/
+    // Returns code indicating how level ended.
+    virtual LevelExitCode Play( void );
+
+  };
+
+#endif
+
+/* END of Level2.h */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LevelCollection.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,128 @@
+/*
+ * SOURCE FILE : LevelCollection.cpp
+ *
+ * Definition of class LevelCollection.
+ *
+ */
+
+#include <stdio.h>
+#include "LevelCollection.h"
+#include "Level0.h"
+#include "Level1.h"
+#include "Level2.h"
+#if 0
+    #include "Level3.h"
+    #include "Level4.h"
+    #include "Level5.h"
+    #include "Level6.h"
+    #include "Level7.h"
+    #include "Level8.h"
+    #include "Level9.h"
+    #include "Level10.h"
+    #include "Level10.h"
+    #include "Level11.h"
+    #include "Level12.h"
+    #include "Level13.h"
+    #include "Level14.h"
+    #include "Level15.h"
+    #include "Level16.h"
+    #include "Level17.h"
+    #include "Level18.h"
+    #include "Level19.h"
+    #include "Level20.h"
+#endif
+
+/***************/
+/* CONSTRUCTOR */
+/***************/
+LevelCollection::LevelCollection() {
+}
+
+/**************/
+/* DESTRUCTOR */
+/**************/
+LevelCollection::~LevelCollection() {
+}
+
+#define LEVELCOUNT 3
+
+/************************/
+/* GET NUMBER OF LEVELS */
+/************************/
+UInt8 LevelCollection::GetLevelCount( void ) const {
+  return LEVELCOUNT;
+}
+
+// Individual levels.
+static Level0 level0;  // Not a real level. This is attract mode.
+static Level1 level1;
+static Level2 level2;
+#if 0
+static Level3 level3;
+static Level4 level4;
+static Level5 level5;
+static Level6 level6;
+static Level7 level7;
+static Level8 level8;
+static Level9 level9;
+static Level10 level10;
+static Level11 level11;
+static Level12 level12;
+static Level13 level13;
+static Level14 level14;
+static Level15 level15;
+static Level16 level16;
+static Level17 level17;
+static Level18 level18;
+static Level19 level19;
+static Level20 level20;
+#endif
+
+// Pointers to all the levels.
+// If I have got this right then each pointer in the array points to a
+// Level that is NOT const, but the array itself is const and cannot be modified.
+static Level* const levels[ LEVELCOUNT ] = {
+  &level0,
+  &level1,
+  &level2,
+#if 0
+    &level3,
+  &level4,
+  &level5,
+  &level6,
+    &level7,
+  &level8,
+  &level9,
+  &level10,
+  &level11,
+  &level12,
+    &level13,
+  &level14,
+  &level15,
+  &level16,
+    &level17,
+  &level18,
+  &level19,
+  &level20,
+#endif
+};
+
+/***************/
+/* GET A LEVEL */
+/***************/
+// Pass level number in levelNumber.
+// Returns pointer to level or NULL if no such level.
+Level *LevelCollection::GetLevel( UInt8 levelNumber ) {
+  if( levelNumber >= LEVELCOUNT ) {
+    return (Level*)NULL;
+  }
+  else {
+    // Fetch pointer to level from array and tag it with the
+    // correct level number before returning it.
+    Level *level = levels[ levelNumber ];
+    level->LevelNumber = levelNumber;
+    return level;
+  }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LevelCollection.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,51 @@
+/*
+ * SOURCE FILE : LevelCollection.h
+ *
+ * Definition of class LevelCollection.
+ *
+ */
+
+#ifndef LevelCollectionDefined
+
+  #define LevelCollectionDefined
+  
+  #include "Types.h"
+  #include "Level.h"
+
+  class LevelCollection {
+
+  public :
+
+    enum {
+      AttractLevel = 0,        // just ticking over encouraging player to start
+      FirstNormalLevel = 1,    // first real level excluding attract mode
+    };
+    
+    /***************/
+    /* CONSTRUCTOR */
+    /***************/
+    LevelCollection();
+
+    /**************/
+    /* DESTRUCTOR */
+    /**************/
+    virtual ~LevelCollection();
+
+    /************************/
+    /* GET NUMBER OF LEVELS */
+    /************************/
+    UInt8 GetLevelCount( void ) const;
+
+    /***************/
+    /* GET A LEVEL */
+    /***************/
+    // Pass level number in levelNumber.
+    // Returns pointer to level or NULL if no such level.
+    Level *GetLevel( UInt8 levelNumber );
+    
+  };
+
+#endif
+
+/* END of LevelCollection.h */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LevelNormal.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,376 @@
+/*
+ * SOURCE FILE : LevelNormal.cpp
+ *
+ * Definition of class LevelNormal.
+ * Base class for all "normal" levels.
+ * i.e. Levels that are not special attract modes
+ * but have enemies who are trying to kill you
+ * and so on.
+ *
+ */
+
+#include "LevelNormal.h"
+#if 0
+    #include "GameObjectLocator.h"
+    #include "FrameCounter.h"
+    #include "SpriteNumber.h"
+#endif
+
+// Current instance being processed.
+LevelNormal *LevelNormal::currentInstance;
+
+/***************/
+/* CONSTRUCTOR */
+/***************/
+LevelNormal::LevelNormal() {
+}
+
+/**************/
+/* DESTRUCTOR */
+/**************/
+LevelNormal::~LevelNormal() {
+}
+
+/********************/
+/* INITIALISE LEVEL */
+/********************/
+void LevelNormal::InitialiseLevel( void ) {
+#if 0
+    // Note that if you re-arrange the following code you may need to adjust the
+    // SpriteNumber enumeration in SpriteNumber.h.
+  UInt8 spriteNumber = FirstEnemySprite;
+  // Initialise enemies.
+  GameObject::InitialiseAll( DataForLevel->Enemies, LevelData::MaxEnemies, &spriteNumber );
+  // Initialise humans.
+    spriteNumber = FirstHumanSprite;
+  GameObject::InitialiseAll( DataForLevel->Humans, LevelData::MaxHumans, &spriteNumber );
+  // Use next free sprite number for player.
+  player->SpriteNumber = PlayerSprite;
+  // Do futher initialisation for all enemies.
+  EnemyObject *object;
+  for( UInt8 e = 0; e < LevelData::MaxEnemies; ++e ) {
+    object = (EnemyObject*)DataForLevel->Enemies[ e ];
+    if( object != (EnemyObject*)NULL ) {
+            // Get enemy to chase the player.
+      object->SetChaseObject( player );
+            // Pass array of all enemies to this enemy.
+            object->Enemies = DataForLevel->Enemies;
+            // If enemy is a brain then tell it about the humans to chase.
+            if( object->GetEnemyType() == Brain ) {
+                ((BrainObject*)object)->HumansToChase = DataForLevel->Humans;
+            }
+    }
+  }
+  // Put player in the centre of the arena.
+  player->Xco = PLAYER_START_X;
+  player->Yco = PLAYER_START_Y;
+  // Kill off all player's bullets.
+  player->KillAllBullets();
+  // Kill off all explosions.
+  ExplosionManager::Instance.KillAllExplosions();
+#endif
+}
+
+/**********************************/
+/* DRAW SCORE AND NUMBER OF LIVES */
+/**********************************/
+void LevelNormal::DrawScoreAndLives( void ) {
+#if 0
+  GDExtra::WriteBCDNumber( 16, 0, player->Score, 8 );
+  // Display number of lives but limit this to 20 lives displayed.
+  UInt8 lives = ( player->Lives > 20 ) ? 20 : player->Lives;
+  GD.fill( RAM_PIC + VISIBLE_CHAR_WIDTH - lives, MiniPlayer, lives );
+#endif
+}
+
+/******************/
+/* DRAW THE LEVEL */
+/******************/
+void LevelNormal::DrawLevel( void ) {
+#if 0
+  // Set screen background to black.
+  GD.wr( BG_COLOR, RGB( 0, 0, 0 ) );
+  // Clear the screen to zero characters.
+  GDExtra::ClearScreen( TransparentChar );
+  // Hide all sprties.
+  GDExtra::HideAllSprites();
+  // Display level number.
+  GDExtra::WriteProgString( 0, 0, StringData::LevelString );
+  GDExtra::WriteUInt16( 6, 0, LevelNumber, 10, 2 );
+  // Display score.
+  GDExtra::WriteProgString( 10, 0, StringData::ScoreString );
+  // Update score and lives.
+  DrawScoreAndLives();
+  // Draw border around screen.
+  CharFrame::Draw(
+    ARENA_BORDER_X,
+    ARENA_BORDER_Y,
+    ARENA_BORDER_WIDTH,
+    ARENA_BORDER_HEIGHT
+  );
+#endif
+}
+
+/************************************************/
+/* HANDLE COLLISIONS BETWEEN HUMANS AND ENEMIES */
+/************************************************/
+// Pass index of human in level's humans array in humanIndex.
+// Pass sprite number of sprite that it hit in spriteNumber.
+void LevelNormal::HandleHumanCollision( UInt8 humanIndex, UInt8 spriteNumber ) {
+#if 0
+  // Point to array of enemy object pointers.
+  GameObject **enemies = currentInstance->DataForLevel->Enemies;
+  EnemyObject *enemy;
+  UInt8 enemyIndex, mutantIndex;
+  // Find an enemy with given sprite number.
+  if( GameObject::FindSpriteNumber( enemies, LevelData::MaxEnemies, spriteNumber, &enemyIndex ) ) {
+    // Found enemy. Check if it squashes humans.
+    enemy = (EnemyObject*)enemies[ enemyIndex ];
+        // Get hold of the human that is doomed.
+        GameObject **humans = currentInstance->DataForLevel->Humans;
+        HumanObject *human = (HumanObject*)humans[ humanIndex ];
+        // Human must be walking around. Not rescued or already dead.
+        if( human->CurrentState == HumanObject::WalkingAbout ) {
+            if( enemy->SquashesHumans ) {
+                // Change human to dead state.
+                human->CurrentState = HumanObject::Dead;
+                // Make a noise.
+                SoundManager::Instance.PlaySound( Sounds::HumanDies, 0, 0 );
+            }
+            else if( enemy->GetEnemyType() == Brain ) {
+                // Kill human by inserting a null into humans array.
+                humans[ humanIndex ] = (GameObject*)NULL;
+                // Find a free slot for a new enemy.
+                if( GameObject::FindUnusedObject( enemies, LevelData::MaxEnemies, &mutantIndex ) ) {
+                    // Write a pointer to a mutant with the same index as the human that just died
+                    // into the enemy array.
+                    MutantObject *mutant = currentInstance->DataForLevel->Mutants + humanIndex;
+                    enemies[ mutantIndex ] = mutant;
+                    // Initialise mutant at coordinates of human and chasing the player.
+                    mutant->Start( human, currentInstance->player );
+                    // Make a noise.
+                    // TODO : SoundManager::Instance.PlaySound( Sounds::HumanMutates, 0, 0 );
+                }
+                else {
+                    // Could not find a free slot for a new enemy so just erase the human sprite.
+                    GDExtra::HideSprite( human->SpriteNumber );
+                }
+            }
+        }
+    }
+#endif
+}
+
+/********************************************************/
+/* HANDLE COLLISIONS BETWEEN PLAYER BULLETS AND ENEMIES */
+/********************************************************/
+// Pass index of bullet in player's bullet array in bulletIndex.
+// Pass sprite number of sprite that it hit in spriteNumber.
+void LevelNormal::HandleBulletCollision( UInt8 bulletIndex, UInt8 spriteNumber ) {
+#if 0
+  // Point to array of enemy object pointers.
+  GameObject **enemies = currentInstance->DataForLevel->Enemies;
+  EnemyObject *enemy;
+  UInt8 enemyIndex;
+  // Find an enemy with given sprite number.
+  if( GameObject::FindSpriteNumber( enemies, LevelData::MaxEnemies, spriteNumber, &enemyIndex ) ) {
+    // Found enemy. Check if it is indestructable.
+    enemy = (EnemyObject*)enemies[ enemyIndex ];
+        if( enemy->HitPoints != EnemyObject::Indestructable ) {
+            // Enemy is not indestructable. Decrement hit points and die when it reaches zero.
+            enemy->HitPoints--;
+            if( enemy->HitPoints == 0 ) {
+                // Kill enemy by inserting a NULL into enemies array.
+                enemies[ enemyIndex ] = (GameObject*)NULL;
+                // Hide the enemy sprite.
+                GDExtra::HideSprite( enemy->SpriteNumber );
+                // Add points to player's score.
+                currentInstance->player->AddToScore( enemy->GetPoints() );
+            }
+        }
+        // Tell enemy it has been hit by a bullet.
+        enemy->RegisterHitByBullet();
+        // Kill off the bullet.
+        currentInstance->player->KillBullet( bulletIndex );
+        // Make a noise.
+        SoundManager::Instance.PlaySound( Sounds::Explosion, 0, 0 );
+        // Start explosion animation using coordinates of enemy.
+        ExplosionManager::Instance.StartExplosion( enemy->Xco, enemy->Yco    );
+  }
+#endif
+}
+
+/*********************************************************/
+/* CHECK FOR COLLISIONS BETWEEN PLAYER AND OTHER OBJECTS */
+/*********************************************************/
+// Pass pointer to a flag that will be set true if player is dead in isDead parameter.
+void LevelNormal::CheckPlayerCollisions( bool *isDead ) {
+#if 0
+  UInt8 enemyIndex, humanIndex;
+  // Check if player sprite has hit another sprite.
+  UInt8 hitSpriteNumber = GD.rd( COLLISION + player->SpriteNumber );
+  // If you get 0xFF then no collision found.
+  if( hitSpriteNumber != 0xFF ) {
+    // Check for collision with an enemy.
+    if(
+      GameObject::FindSpriteNumber(
+        DataForLevel->Enemies, LevelData::MaxEnemies, hitSpriteNumber, &enemyIndex
+      )
+    ) {
+      // Hit an enemy. Player is dead.
+      *isDead = true;
+    }
+    // Check for collision with a human that has not already been rescued or killed.
+    else if(
+      GameObject::FindSpriteNumber(
+        DataForLevel->Humans, LevelData::MaxHumans, hitSpriteNumber, &humanIndex
+      )
+    ) {
+      HumanObject *human = (HumanObject*)DataForLevel->Humans[ humanIndex ];
+            if( human->CurrentState == HumanObject::WalkingAbout ) {
+                // Change human state to rescued.
+                human->CurrentState = HumanObject::Rescued;
+                // Give player 50 points (in BCD!).
+                player->AddToScore( 0x50 );
+                // Make a noise.
+                SoundManager::Instance.PlaySound( Sounds::RescueHuman, 0, 0 );
+            }
+    }    
+  }
+#endif
+}
+
+/***********************************************************************************/
+/* WAIT UNTIL SLOT FREE FOR A NEW SOUND, PLAY IT AND WAIT FOR ALL SOUNDS TO FINISH */
+/***********************************************************************************/
+// Pass sound to play in soundToPlay parameter.
+void LevelNormal::PlaySoundAndWait( const UInt8 *soundToPlay ) {
+#if 0
+  // Keep trying to play sound until it works and meanwhile
+  // keep currently playing sounds going.
+  while( ! SoundManager::Instance.PlaySound( soundToPlay, 0, 0 ) ) {
+    // Update sound manager.
+    SoundManager::Instance.Update();
+    // Wait for frame flyback.
+    GD.waitvblank();
+  }
+  // Now wait until all sounds have finished.
+  while( SoundManager::Instance.CountSoundsPlaying() > 0 ) {
+    // Update sound manager.
+    SoundManager::Instance.Update();
+    // Wait for frame flyback.
+    GD.waitvblank();
+  }
+#endif
+}
+
+/*************/
+/* PLAY LOOP */
+/*************/
+// Returns code indicating how level ended.
+// This method should be called from the Play method after the
+// level data has been initialised and the return value returned
+// by the Play method.
+Level::LevelExitCode LevelNormal::PlayLoop( void ) {
+#if 0
+  // Do nothing if level data is NULL or player has not been specified.
+  if( ( DataForLevel != (LevelData*)NULL ) || ( player == (PlayerObject*)NULL ) ) {
+    // Point static pointer to current instance.
+    currentInstance = this;
+    // Do some initialisation first.
+    InitialiseLevel();
+    // Redraw the screen.
+    DrawLevel();
+        // Wait for frame flyback once before entering loop so collision data is recalculated.
+        // At this point there should not be any sprites on the screen so no collisions
+        // should be found.
+        GD.waitvblank();
+    // Repeat until all enemies are dead or player is dead.
+    bool allEnemiesAreDead = false;
+        bool playerIsDead = false;
+    bool gameIsOver = false;
+    bool firstDraw = true;
+    while( ! allEnemiesAreDead && ! gameIsOver ) {
+      // Update sound manager.
+      SoundManager::Instance.Update();
+      // Wait for frame flyback.
+      GD.waitvblank();
+      // Check for collisions between player and other objects.
+      CheckPlayerCollisions( &playerIsDead );
+            // Check for collisions between humans and enemies that squash.
+            GameObject::FindCollisions( DataForLevel->Humans, LevelData::MaxHumans, &LevelNormal::HandleHumanCollision );
+      // Check for collisions between player bullets and enemies.
+      GameObject::FindCollisions( player->GetBullets(), BulletManager::MaxBullets, &LevelNormal::HandleBulletCollision );
+      // Redraw the player's score and number of lives.
+      DrawScoreAndLives();
+      // Draw all the enemies.
+      GameObject::DrawAll( DataForLevel->Enemies, LevelData::MaxEnemies );
+      // Draw all the humans.
+      GameObject::DrawAll( DataForLevel->Humans, LevelData::MaxHumans );
+      // Draw all the explosions.
+      GameObject::DrawAll( ExplosionManager::Instance.GetExplosions(), ExplosionManager::MaxExplosions );
+      // Draw the player.
+      player->Draw();
+      // Draw the player's bullets.
+      GameObject::DrawAll( player->GetBullets(), BulletManager::MaxBullets );
+      // Increment the frame counter.
+      FrameCounter++;
+      // After first redraw play level start sound and wait for it to end.
+      if( firstDraw ) {
+        PlaySoundAndWait( Sounds::StartLevel );
+        firstDraw = false;
+      }
+            // If player was killed then play death march and wait for it to finish.
+            if( playerIsDead ) {
+                // Player got killed.
+                PlaySoundAndWait( Sounds::PlayerDead );
+                // One less life for player.
+                if( player->Lives > 0 ) {
+                    player->Lives--;
+                }
+                // Game is over when player has no more lives.
+                gameIsOver = ( player->Lives == 0 );
+                // If game is not over then re-initialise level using any remaining enemies.
+                if( ! gameIsOver ) {
+                    // Remove all objects that do not survive a level restart (like enemy bullets).
+                    GameObject::RemoveUnretainedObjects( DataForLevel->Enemies, LevelData::MaxEnemies );
+                    InitialiseLevel();
+                    DrawLevel();
+                    GD.waitvblank();
+                    playerIsDead = false;
+                    firstDraw = true;
+                }
+            }
+            else {
+                // Move all the enemies and check if all dead.
+                allEnemiesAreDead = ! GameObject::MoveAll( DataForLevel->Enemies, LevelData::MaxEnemies );
+                // If there are still some enemies alive then check if those that remain are indestructable.
+                // If only indestructable enemies survive then act as if all enemies are dead.
+                // You need to do this or you would never be able to complete a level that had indestructable
+                // enemies on it.
+                if( ! allEnemiesAreDead ) {
+                    allEnemiesAreDead = EnemyObject::AreAllIndestructable(
+                        (const EnemyObject**)DataForLevel->Enemies,
+                        LevelData::MaxEnemies
+                    );
+                }
+                // Move all the humans.
+                GameObject::MoveAll( DataForLevel->Humans, LevelData::MaxHumans );
+                // Move (update) all the explosions.
+                GameObject::MoveAll( ExplosionManager::Instance.GetExplosions(), ExplosionManager::MaxExplosions );
+                // Read the player's controls.
+                player->ReadControls();
+                // Move the player.
+                player->Move();
+                // Move the player's bullets.
+                GameObject::MoveAll( player->GetBullets(), BulletManager::MaxBullets );
+            }
+    }
+        // Player completed level or game is over.
+        return gameIsOver ? GameOver : Completed;
+  }
+#endif
+  // Level data or player were not specified.
+  return Completed;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LevelNormal.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,102 @@
+/*
+ * SOURCE FILE : LevelNormal.h
+ *
+ * Definition of class LevelNormal.
+ * Base class for all "normal" levels.
+ * i.e. Levels that are not special attract modes
+ * but have enemies who are trying to kill you
+ * and so on.
+ *
+ */
+
+#ifndef LevelNormalDefined
+
+  #define LevelNormalDefined
+
+  #include "Level.h"
+#if 0
+  #include "LevelData.h"
+  #include "ExplosionManager.h"
+#endif
+  
+  class LevelNormal : public Level {
+
+  public :
+
+    /***************/
+    /* CONSTRUCTOR */
+    /***************/
+    LevelNormal();
+
+    /**************/
+    /* DESTRUCTOR */
+    /**************/
+    virtual ~LevelNormal();
+
+  protected :
+
+    // Data defining the level.
+    // You should write to this before calling PlayLoop.
+    // LevelData *DataForLevel;
+    
+    /*************/
+    /* PLAY LOOP */
+    /*************/
+    // Returns code indicating how level ended.
+    // This method should be called from the Play method after the
+    // level data has been initialised and the return value returned
+    // by the Play method.
+    virtual LevelExitCode PlayLoop( void );
+    
+  private :
+
+    // Current instance being processed.
+    static LevelNormal *currentInstance;
+
+    /********************/
+    /* INITIALISE LEVEL */
+    /********************/
+    void InitialiseLevel( void );
+
+    /**********************************/
+    /* DRAW SCORE AND NUMBER OF LIVES */
+    /**********************************/
+    void DrawScoreAndLives( void );
+
+    /******************/
+    /* DRAW THE LEVEL */
+    /******************/
+    void DrawLevel( void );
+
+    /************************************************/
+    /* HANDLE COLLISIONS BETWEEN HUMANS AND ENEMIES */
+    /************************************************/
+    // Pass index of human in level's humans array in humanIndex.
+    // Pass sprite number of sprite that it hit in spriteNumber.
+    static void HandleHumanCollision( UInt8 humanIndex, UInt8 spriteNumber );
+
+    /********************************************************/
+    /* HANDLE COLLISIONS BETWEEN PLAYER BULLETS AND ENEMIES */
+    /********************************************************/
+    // Pass index of bullet in player's bullet array in bulletIndex.
+    // Pass sprite number of sprite that it hit in spriteNumber.
+    static void HandleBulletCollision( UInt8 bulletIndex, UInt8 spriteNumber );
+
+    /*********************************************************/
+    /* CHECK FOR COLLISIONS BETWEEN PLAYER AND OTHER OBJECTS */
+    /*********************************************************/
+    // Pass pointer to a flag that will be set true if player is dead in isDead parameter.
+    void CheckPlayerCollisions( bool *isDead );
+
+    /***********************************************************************************/
+    /* WAIT UNTIL SLOT FREE FOR A NEW SOUND, PLAY IT AND WAIT FOR ALL SOUNDS TO FINISH */
+    /***********************************************************************************/
+    // Pass sound to play in soundToPlay parameter.
+    static void PlaySoundAndWait( const UInt8 *soundToPlay );
+
+  };
+
+#endif
+
+/* END of LevelNormal.h */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PlayerName.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,38 @@
+/*
+ * SOURCE FILE : PlayerName.cpp
+ *
+ * Definition of class PlayerName.
+ * Contains the name that appears in a high score table for example.
+ *
+ */
+
+#include "PlayerName.h"
+
+/***************/
+/* CONSTRUCTOR */
+/***************/
+PlayerName::PlayerName() {
+  // Initialise name to all 'X' characters.
+  for( UInt8 i = 0; i < Length; ++i ) {
+    Name[ i ] = 'X';
+  }
+  Name[ Length ] = (char)0;
+}
+
+/**************/
+/* DESTRUCTOR */
+/**************/
+PlayerName::~PlayerName() {
+}
+
+/************************************************************/
+/* COPY ONE NAME TO ANOTHER WITHOUT CREATING A NEW INSTANCE */
+/************************************************************/
+// Pass pointer to name to copy to in dest.
+void PlayerName::CopyTo( PlayerName *dest ) const {
+  for( UInt8 i = 0; i < Length; ++i ) {
+    dest->Name[ i ] = Name[ i ];
+  }
+  dest->Name[ Length ] = (char)0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PlayerName.h	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,50 @@
+/*
+ * SOURCE FILE : PlayerName.h
+ *
+ * Definition of class PlayerName.
+ * Contains the name that appears in a high score table for example.
+ *
+ */
+
+#ifndef PlayerNameDefined
+
+  #define PlayerNameDefined
+
+  #include "Types.h"
+  
+  class PlayerName {
+
+  public :
+
+    enum {
+      Length = 3,      // Number of characters used for name.
+      MinChar = ' ',   // First valid character in a name.
+      MaxChar = 'Z',   // Last valid character in a name.
+    };
+  
+    // Characters that make up the name, plus a zero char at the end.
+    char Name[ Length + 1 ];
+    
+    /***************/
+    /* CONSTRUCTOR */
+    /***************/
+    PlayerName();
+
+    /**************/
+    /* DESTRUCTOR */
+    /**************/
+    virtual ~PlayerName();
+
+    /************************************************************/
+    /* COPY ONE NAME TO ANOTHER WITHOUT CREATING A NEW INSTANCE */
+    /************************************************************/
+    // Pass pointer to name to copy to in dest.
+    void CopyTo( PlayerName *dest ) const;
+    
+  };
+
+  
+#endif
+
+/* END of PlayerName.h */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,21 @@
+/*
+ * SOURCE FILE : main.cpp
+ *
+ * Main program for the RobotRic game. Uses the Gameduino board (for Arduino) to generate graphics and sound.
+ *
+ */
+
+#include "mbed.h"
+#include "GameRobotRic.h"           // RobotRic game object
+
+/**
+  * Main program.
+  * Never returns.
+  */
+int main() {
+    // Create an instance of the game and then play it.
+    // Play method never exits.
+    GameRobotRic game;
+    game.Play();
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Jun 04 20:16:33 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/b3110cd2dd17
\ No newline at end of file