Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: 25LCxxx_SPI CommonTypes Gameduino mbed
LevelNormal.cpp@7:e72691603fd3, 2013-06-08 (annotated)
- Committer:
- RichardE
- Date:
- Sat Jun 08 16:44:54 2013 +0000
- Revision:
- 7:e72691603fd3
- Parent:
- 6:8bbdb70bc11c
- Child:
- 8:82d88f9381f3
Now have grunts wandering around on level 1. They follow the player but since no collision detection logic yet nobody ever gets killed.
Who changed what in which revision?
| User | Revision | Line number | New contents of line | 
|---|---|---|---|
| RichardE | 0:5fa232ee5fdf | 1 | /* | 
| RichardE | 0:5fa232ee5fdf | 2 | * SOURCE FILE : LevelNormal.cpp | 
| RichardE | 0:5fa232ee5fdf | 3 | * | 
| RichardE | 0:5fa232ee5fdf | 4 | * Definition of class LevelNormal. | 
| RichardE | 0:5fa232ee5fdf | 5 | * Base class for all "normal" levels. | 
| RichardE | 0:5fa232ee5fdf | 6 | * i.e. Levels that are not special attract modes | 
| RichardE | 0:5fa232ee5fdf | 7 | * but have enemies who are trying to kill you | 
| RichardE | 0:5fa232ee5fdf | 8 | * and so on. | 
| RichardE | 0:5fa232ee5fdf | 9 | * | 
| RichardE | 0:5fa232ee5fdf | 10 | */ | 
| RichardE | 0:5fa232ee5fdf | 11 | |
| RichardE | 5:0b0651ac7832 | 12 | // Define this for debugging messages. | 
| RichardE | 5:0b0651ac7832 | 13 | #define CHATTY | 
| RichardE | 5:0b0651ac7832 | 14 | |
| RichardE | 5:0b0651ac7832 | 15 | #ifdef CHATTY | 
| RichardE | 5:0b0651ac7832 | 16 | #include "mbed.h" | 
| RichardE | 5:0b0651ac7832 | 17 | extern Serial pc; | 
| RichardE | 5:0b0651ac7832 | 18 | #endif | 
| RichardE | 5:0b0651ac7832 | 19 | |
| RichardE | 0:5fa232ee5fdf | 20 | #include "LevelNormal.h" | 
| RichardE | 5:0b0651ac7832 | 21 | #include "GameObjectLocator.h" | 
| RichardE | 5:0b0651ac7832 | 22 | #include "FrameCounter.h" | 
| RichardE | 5:0b0651ac7832 | 23 | #include "SpriteNumber.h" | 
| RichardE | 5:0b0651ac7832 | 24 | #include "ArenaConst.h" | 
| RichardE | 0:5fa232ee5fdf | 25 | |
| RichardE | 0:5fa232ee5fdf | 26 | // Current instance being processed. | 
| RichardE | 0:5fa232ee5fdf | 27 | LevelNormal *LevelNormal::currentInstance; | 
| RichardE | 0:5fa232ee5fdf | 28 | |
| RichardE | 0:5fa232ee5fdf | 29 | /***************/ | 
| RichardE | 0:5fa232ee5fdf | 30 | /* CONSTRUCTOR */ | 
| RichardE | 0:5fa232ee5fdf | 31 | /***************/ | 
| RichardE | 5:0b0651ac7832 | 32 | LevelNormal::LevelNormal() | 
| RichardE | 5:0b0651ac7832 | 33 | { | 
| RichardE | 0:5fa232ee5fdf | 34 | } | 
| RichardE | 0:5fa232ee5fdf | 35 | |
| RichardE | 0:5fa232ee5fdf | 36 | /**************/ | 
| RichardE | 0:5fa232ee5fdf | 37 | /* DESTRUCTOR */ | 
| RichardE | 0:5fa232ee5fdf | 38 | /**************/ | 
| RichardE | 5:0b0651ac7832 | 39 | LevelNormal::~LevelNormal() | 
| RichardE | 5:0b0651ac7832 | 40 | { | 
| RichardE | 0:5fa232ee5fdf | 41 | } | 
| RichardE | 0:5fa232ee5fdf | 42 | |
| RichardE | 0:5fa232ee5fdf | 43 | /********************/ | 
| RichardE | 0:5fa232ee5fdf | 44 | /* INITIALISE LEVEL */ | 
| RichardE | 0:5fa232ee5fdf | 45 | /********************/ | 
| RichardE | 5:0b0651ac7832 | 46 | // Pass pointer to Gameduino to draw on in gd. | 
| RichardE | 5:0b0651ac7832 | 47 | void LevelNormal::InitialiseLevel( Gameduino *gd ) | 
| RichardE | 5:0b0651ac7832 | 48 | { | 
| RichardE | 0:5fa232ee5fdf | 49 | // Note that if you re-arrange the following code you may need to adjust the | 
| RichardE | 0:5fa232ee5fdf | 50 | // SpriteNumber enumeration in SpriteNumber.h. | 
| RichardE | 5:0b0651ac7832 | 51 | UInt8 spriteNumber = FirstEnemySprite; | 
| RichardE | 5:0b0651ac7832 | 52 | // Initialise enemies. | 
| RichardE | 5:0b0651ac7832 | 53 | GameObject::InitialiseAll( DataForLevel->Enemies, LevelData::MaxEnemies, &spriteNumber ); | 
| RichardE | 5:0b0651ac7832 | 54 | // Initialise humans. | 
| RichardE | 0:5fa232ee5fdf | 55 | spriteNumber = FirstHumanSprite; | 
| RichardE | 5:0b0651ac7832 | 56 | GameObject::InitialiseAll( DataForLevel->Humans, LevelData::MaxHumans, &spriteNumber ); | 
| RichardE | 5:0b0651ac7832 | 57 | // Use next free sprite number for player. | 
| RichardE | 5:0b0651ac7832 | 58 | player->SpriteNumber = PlayerSprite; | 
| RichardE | 5:0b0651ac7832 | 59 | // Do futher initialisation for all enemies. | 
| RichardE | 5:0b0651ac7832 | 60 | EnemyObject *object; | 
| RichardE | 5:0b0651ac7832 | 61 | for( UInt8 e = 0; e < LevelData::MaxEnemies; ++e ) { | 
| RichardE | 5:0b0651ac7832 | 62 | object = (EnemyObject*)DataForLevel->Enemies[ e ]; | 
| RichardE | 5:0b0651ac7832 | 63 | if( object != (EnemyObject*)NULL ) { | 
| RichardE | 0:5fa232ee5fdf | 64 | // Get enemy to chase the player. | 
| RichardE | 5:0b0651ac7832 | 65 | object->SetChaseObject( player ); | 
| RichardE | 0:5fa232ee5fdf | 66 | // Pass array of all enemies to this enemy. | 
| RichardE | 0:5fa232ee5fdf | 67 | object->Enemies = DataForLevel->Enemies; | 
| RichardE | 0:5fa232ee5fdf | 68 | // If enemy is a brain then tell it about the humans to chase. | 
| RichardE | 0:5fa232ee5fdf | 69 | if( object->GetEnemyType() == Brain ) { | 
| RichardE | 0:5fa232ee5fdf | 70 | ((BrainObject*)object)->HumansToChase = DataForLevel->Humans; | 
| RichardE | 0:5fa232ee5fdf | 71 | } | 
| RichardE | 5:0b0651ac7832 | 72 | } | 
| RichardE | 0:5fa232ee5fdf | 73 | } | 
| RichardE | 5:0b0651ac7832 | 74 | // Put player in the centre of the arena. | 
| RichardE | 5:0b0651ac7832 | 75 | player->Xco = PLAYER_START_X; | 
| RichardE | 5:0b0651ac7832 | 76 | player->Yco = PLAYER_START_Y; | 
| RichardE | 5:0b0651ac7832 | 77 | // Kill off all player's bullets. | 
| RichardE | 5:0b0651ac7832 | 78 | player->KillAllBullets( gd ); | 
| RichardE | 5:0b0651ac7832 | 79 | // Kill off all explosions. | 
| RichardE | 5:0b0651ac7832 | 80 | // ExplosionManager::Instance.KillAllExplosions(); | 
| RichardE | 0:5fa232ee5fdf | 81 | } | 
| RichardE | 0:5fa232ee5fdf | 82 | |
| RichardE | 0:5fa232ee5fdf | 83 | /**********************************/ | 
| RichardE | 0:5fa232ee5fdf | 84 | /* DRAW SCORE AND NUMBER OF LIVES */ | 
| RichardE | 0:5fa232ee5fdf | 85 | /**********************************/ | 
| RichardE | 5:0b0651ac7832 | 86 | void LevelNormal::DrawScoreAndLives( void ) | 
| RichardE | 5:0b0651ac7832 | 87 | { | 
| RichardE | 5:0b0651ac7832 | 88 | GDExtra::WriteBCDNumber( gd, 16, 0, player->Score, 8 ); | 
| RichardE | 5:0b0651ac7832 | 89 | // Display number of lives but limit this to 20 lives displayed. | 
| RichardE | 5:0b0651ac7832 | 90 | UInt8 lives = ( player->Lives > 20 ) ? 20 : player->Lives; | 
| RichardE | 5:0b0651ac7832 | 91 | gd->fill( Gameduino::RAM_PIC + VISIBLE_CHAR_WIDTH - lives, MiniPlayer, lives ); | 
| RichardE | 0:5fa232ee5fdf | 92 | } | 
| RichardE | 0:5fa232ee5fdf | 93 | |
| RichardE | 0:5fa232ee5fdf | 94 | /******************/ | 
| RichardE | 0:5fa232ee5fdf | 95 | /* DRAW THE LEVEL */ | 
| RichardE | 0:5fa232ee5fdf | 96 | /******************/ | 
| RichardE | 5:0b0651ac7832 | 97 | void LevelNormal::DrawLevel( void ) | 
| RichardE | 5:0b0651ac7832 | 98 | { | 
| RichardE | 5:0b0651ac7832 | 99 | // Set screen background to black. | 
| RichardE | 5:0b0651ac7832 | 100 | gd->wr( Gameduino::BG_COLOR, Gameduino::RGB( 0, 0, 0 ) ); | 
| RichardE | 5:0b0651ac7832 | 101 | // Clear the screen to zero characters. | 
| RichardE | 5:0b0651ac7832 | 102 | GDExtra::ClearScreen( gd, TransparentChar ); | 
| RichardE | 5:0b0651ac7832 | 103 | // Hide all sprties. | 
| RichardE | 5:0b0651ac7832 | 104 | GDExtra::HideAllSprites( gd ); | 
| RichardE | 5:0b0651ac7832 | 105 | // Display level number. | 
| RichardE | 5:0b0651ac7832 | 106 | GDExtra::WriteProgString( gd, 0, 0, StringData::LevelString ); | 
| RichardE | 5:0b0651ac7832 | 107 | GDExtra::WriteUInt16( gd, 6, 0, LevelNumber, 10, 2 ); | 
| RichardE | 5:0b0651ac7832 | 108 | // Display score. | 
| RichardE | 5:0b0651ac7832 | 109 | GDExtra::WriteProgString( gd, 10, 0, StringData::ScoreString ); | 
| RichardE | 5:0b0651ac7832 | 110 | // Update score and lives. | 
| RichardE | 5:0b0651ac7832 | 111 | DrawScoreAndLives(); | 
| RichardE | 5:0b0651ac7832 | 112 | // Draw border around screen. | 
| RichardE | 5:0b0651ac7832 | 113 | CharFrame::Draw( | 
| RichardE | 5:0b0651ac7832 | 114 | gd, | 
| RichardE | 5:0b0651ac7832 | 115 | ARENA_BORDER_X, | 
| RichardE | 5:0b0651ac7832 | 116 | ARENA_BORDER_Y, | 
| RichardE | 5:0b0651ac7832 | 117 | ARENA_BORDER_WIDTH, | 
| RichardE | 5:0b0651ac7832 | 118 | ARENA_BORDER_HEIGHT | 
| RichardE | 5:0b0651ac7832 | 119 | ); | 
| RichardE | 0:5fa232ee5fdf | 120 | } | 
| RichardE | 0:5fa232ee5fdf | 121 | |
| RichardE | 0:5fa232ee5fdf | 122 | /************************************************/ | 
| RichardE | 0:5fa232ee5fdf | 123 | /* HANDLE COLLISIONS BETWEEN HUMANS AND ENEMIES */ | 
| RichardE | 0:5fa232ee5fdf | 124 | /************************************************/ | 
| RichardE | 0:5fa232ee5fdf | 125 | // Pass index of human in level's humans array in humanIndex. | 
| RichardE | 0:5fa232ee5fdf | 126 | // Pass sprite number of sprite that it hit in spriteNumber. | 
| RichardE | 5:0b0651ac7832 | 127 | void LevelNormal::HandleHumanCollision( UInt8 humanIndex, UInt8 spriteNumber ) | 
| RichardE | 5:0b0651ac7832 | 128 | { | 
| RichardE | 0:5fa232ee5fdf | 129 | #if 0 | 
| RichardE | 5:0b0651ac7832 | 130 | // Point to array of enemy object pointers. | 
| RichardE | 5:0b0651ac7832 | 131 | GameObject **enemies = currentInstance->DataForLevel->Enemies; | 
| RichardE | 5:0b0651ac7832 | 132 | EnemyObject *enemy; | 
| RichardE | 5:0b0651ac7832 | 133 | UInt8 enemyIndex, mutantIndex; | 
| RichardE | 5:0b0651ac7832 | 134 | // Find an enemy with given sprite number. | 
| RichardE | 5:0b0651ac7832 | 135 | if( GameObject::FindSpriteNumber( enemies, LevelData::MaxEnemies, spriteNumber, &enemyIndex ) ) { | 
| RichardE | 5:0b0651ac7832 | 136 | // Found enemy. Check if it squashes humans. | 
| RichardE | 5:0b0651ac7832 | 137 | enemy = (EnemyObject*)enemies[ enemyIndex ]; | 
| RichardE | 0:5fa232ee5fdf | 138 | // Get hold of the human that is doomed. | 
| RichardE | 0:5fa232ee5fdf | 139 | GameObject **humans = currentInstance->DataForLevel->Humans; | 
| RichardE | 0:5fa232ee5fdf | 140 | HumanObject *human = (HumanObject*)humans[ humanIndex ]; | 
| RichardE | 0:5fa232ee5fdf | 141 | // Human must be walking around. Not rescued or already dead. | 
| RichardE | 0:5fa232ee5fdf | 142 | if( human->CurrentState == HumanObject::WalkingAbout ) { | 
| RichardE | 0:5fa232ee5fdf | 143 | if( enemy->SquashesHumans ) { | 
| RichardE | 0:5fa232ee5fdf | 144 | // Change human to dead state. | 
| RichardE | 0:5fa232ee5fdf | 145 | human->CurrentState = HumanObject::Dead; | 
| RichardE | 0:5fa232ee5fdf | 146 | // Make a noise. | 
| RichardE | 0:5fa232ee5fdf | 147 | SoundManager::Instance.PlaySound( Sounds::HumanDies, 0, 0 ); | 
| RichardE | 5:0b0651ac7832 | 148 | } else if( enemy->GetEnemyType() == Brain ) { | 
| RichardE | 0:5fa232ee5fdf | 149 | // Kill human by inserting a null into humans array. | 
| RichardE | 0:5fa232ee5fdf | 150 | humans[ humanIndex ] = (GameObject*)NULL; | 
| RichardE | 0:5fa232ee5fdf | 151 | // Find a free slot for a new enemy. | 
| RichardE | 0:5fa232ee5fdf | 152 | if( GameObject::FindUnusedObject( enemies, LevelData::MaxEnemies, &mutantIndex ) ) { | 
| RichardE | 0:5fa232ee5fdf | 153 | // Write a pointer to a mutant with the same index as the human that just died | 
| RichardE | 0:5fa232ee5fdf | 154 | // into the enemy array. | 
| RichardE | 0:5fa232ee5fdf | 155 | MutantObject *mutant = currentInstance->DataForLevel->Mutants + humanIndex; | 
| RichardE | 0:5fa232ee5fdf | 156 | enemies[ mutantIndex ] = mutant; | 
| RichardE | 0:5fa232ee5fdf | 157 | // Initialise mutant at coordinates of human and chasing the player. | 
| RichardE | 0:5fa232ee5fdf | 158 | mutant->Start( human, currentInstance->player ); | 
| RichardE | 0:5fa232ee5fdf | 159 | // Make a noise. | 
| RichardE | 0:5fa232ee5fdf | 160 | // TODO : SoundManager::Instance.PlaySound( Sounds::HumanMutates, 0, 0 ); | 
| RichardE | 5:0b0651ac7832 | 161 | } else { | 
| RichardE | 0:5fa232ee5fdf | 162 | // Could not find a free slot for a new enemy so just erase the human sprite. | 
| RichardE | 0:5fa232ee5fdf | 163 | GDExtra::HideSprite( human->SpriteNumber ); | 
| RichardE | 0:5fa232ee5fdf | 164 | } | 
| RichardE | 0:5fa232ee5fdf | 165 | } | 
| RichardE | 0:5fa232ee5fdf | 166 | } | 
| RichardE | 0:5fa232ee5fdf | 167 | } | 
| RichardE | 0:5fa232ee5fdf | 168 | #endif | 
| RichardE | 0:5fa232ee5fdf | 169 | } | 
| RichardE | 0:5fa232ee5fdf | 170 | |
| RichardE | 0:5fa232ee5fdf | 171 | /********************************************************/ | 
| RichardE | 0:5fa232ee5fdf | 172 | /* HANDLE COLLISIONS BETWEEN PLAYER BULLETS AND ENEMIES */ | 
| RichardE | 0:5fa232ee5fdf | 173 | /********************************************************/ | 
| RichardE | 0:5fa232ee5fdf | 174 | // Pass index of bullet in player's bullet array in bulletIndex. | 
| RichardE | 0:5fa232ee5fdf | 175 | // Pass sprite number of sprite that it hit in spriteNumber. | 
| RichardE | 5:0b0651ac7832 | 176 | void LevelNormal::HandleBulletCollision( UInt8 bulletIndex, UInt8 spriteNumber ) | 
| RichardE | 5:0b0651ac7832 | 177 | { | 
| RichardE | 0:5fa232ee5fdf | 178 | #if 0 | 
| RichardE | 5:0b0651ac7832 | 179 | // Point to array of enemy object pointers. | 
| RichardE | 5:0b0651ac7832 | 180 | GameObject **enemies = currentInstance->DataForLevel->Enemies; | 
| RichardE | 5:0b0651ac7832 | 181 | EnemyObject *enemy; | 
| RichardE | 5:0b0651ac7832 | 182 | UInt8 enemyIndex; | 
| RichardE | 5:0b0651ac7832 | 183 | // Find an enemy with given sprite number. | 
| RichardE | 5:0b0651ac7832 | 184 | if( GameObject::FindSpriteNumber( enemies, LevelData::MaxEnemies, spriteNumber, &enemyIndex ) ) { | 
| RichardE | 5:0b0651ac7832 | 185 | // Found enemy. Check if it is indestructable. | 
| RichardE | 5:0b0651ac7832 | 186 | enemy = (EnemyObject*)enemies[ enemyIndex ]; | 
| RichardE | 0:5fa232ee5fdf | 187 | if( enemy->HitPoints != EnemyObject::Indestructable ) { | 
| RichardE | 0:5fa232ee5fdf | 188 | // Enemy is not indestructable. Decrement hit points and die when it reaches zero. | 
| RichardE | 0:5fa232ee5fdf | 189 | enemy->HitPoints--; | 
| RichardE | 0:5fa232ee5fdf | 190 | if( enemy->HitPoints == 0 ) { | 
| RichardE | 0:5fa232ee5fdf | 191 | // Kill enemy by inserting a NULL into enemies array. | 
| RichardE | 0:5fa232ee5fdf | 192 | enemies[ enemyIndex ] = (GameObject*)NULL; | 
| RichardE | 0:5fa232ee5fdf | 193 | // Hide the enemy sprite. | 
| RichardE | 0:5fa232ee5fdf | 194 | GDExtra::HideSprite( enemy->SpriteNumber ); | 
| RichardE | 0:5fa232ee5fdf | 195 | // Add points to player's score. | 
| RichardE | 0:5fa232ee5fdf | 196 | currentInstance->player->AddToScore( enemy->GetPoints() ); | 
| RichardE | 0:5fa232ee5fdf | 197 | } | 
| RichardE | 0:5fa232ee5fdf | 198 | } | 
| RichardE | 0:5fa232ee5fdf | 199 | // Tell enemy it has been hit by a bullet. | 
| RichardE | 0:5fa232ee5fdf | 200 | enemy->RegisterHitByBullet(); | 
| RichardE | 0:5fa232ee5fdf | 201 | // Kill off the bullet. | 
| RichardE | 0:5fa232ee5fdf | 202 | currentInstance->player->KillBullet( bulletIndex ); | 
| RichardE | 0:5fa232ee5fdf | 203 | // Make a noise. | 
| RichardE | 0:5fa232ee5fdf | 204 | SoundManager::Instance.PlaySound( Sounds::Explosion, 0, 0 ); | 
| RichardE | 0:5fa232ee5fdf | 205 | // Start explosion animation using coordinates of enemy. | 
| RichardE | 0:5fa232ee5fdf | 206 | ExplosionManager::Instance.StartExplosion( enemy->Xco, enemy->Yco ); | 
| RichardE | 5:0b0651ac7832 | 207 | } | 
| RichardE | 0:5fa232ee5fdf | 208 | #endif | 
| RichardE | 0:5fa232ee5fdf | 209 | } | 
| RichardE | 0:5fa232ee5fdf | 210 | |
| RichardE | 0:5fa232ee5fdf | 211 | /*********************************************************/ | 
| RichardE | 0:5fa232ee5fdf | 212 | /* CHECK FOR COLLISIONS BETWEEN PLAYER AND OTHER OBJECTS */ | 
| RichardE | 0:5fa232ee5fdf | 213 | /*********************************************************/ | 
| RichardE | 0:5fa232ee5fdf | 214 | // Pass pointer to a flag that will be set true if player is dead in isDead parameter. | 
| RichardE | 5:0b0651ac7832 | 215 | void LevelNormal::CheckPlayerCollisions( bool *isDead ) | 
| RichardE | 5:0b0651ac7832 | 216 | { | 
| RichardE | 0:5fa232ee5fdf | 217 | #if 0 | 
| RichardE | 5:0b0651ac7832 | 218 | UInt8 enemyIndex, humanIndex; | 
| RichardE | 5:0b0651ac7832 | 219 | // Check if player sprite has hit another sprite. | 
| RichardE | 5:0b0651ac7832 | 220 | UInt8 hitSpriteNumber = GD.rd( COLLISION + player->SpriteNumber ); | 
| RichardE | 5:0b0651ac7832 | 221 | // If you get 0xFF then no collision found. | 
| RichardE | 5:0b0651ac7832 | 222 | if( hitSpriteNumber != 0xFF ) { | 
| RichardE | 5:0b0651ac7832 | 223 | // Check for collision with an enemy. | 
| RichardE | 5:0b0651ac7832 | 224 | if( | 
| RichardE | 5:0b0651ac7832 | 225 | GameObject::FindSpriteNumber( | 
| RichardE | 5:0b0651ac7832 | 226 | DataForLevel->Enemies, LevelData::MaxEnemies, hitSpriteNumber, &enemyIndex | 
| RichardE | 5:0b0651ac7832 | 227 | ) | 
| RichardE | 5:0b0651ac7832 | 228 | ) { | 
| RichardE | 5:0b0651ac7832 | 229 | // Hit an enemy. Player is dead. | 
| RichardE | 5:0b0651ac7832 | 230 | *isDead = true; | 
| RichardE | 5:0b0651ac7832 | 231 | } | 
| RichardE | 5:0b0651ac7832 | 232 | // Check for collision with a human that has not already been rescued or killed. | 
| RichardE | 5:0b0651ac7832 | 233 | else if( | 
| RichardE | 5:0b0651ac7832 | 234 | GameObject::FindSpriteNumber( | 
| RichardE | 5:0b0651ac7832 | 235 | DataForLevel->Humans, LevelData::MaxHumans, hitSpriteNumber, &humanIndex | 
| RichardE | 5:0b0651ac7832 | 236 | ) | 
| RichardE | 5:0b0651ac7832 | 237 | ) { | 
| RichardE | 5:0b0651ac7832 | 238 | HumanObject *human = (HumanObject*)DataForLevel->Humans[ humanIndex ]; | 
| RichardE | 0:5fa232ee5fdf | 239 | if( human->CurrentState == HumanObject::WalkingAbout ) { | 
| RichardE | 0:5fa232ee5fdf | 240 | // Change human state to rescued. | 
| RichardE | 0:5fa232ee5fdf | 241 | human->CurrentState = HumanObject::Rescued; | 
| RichardE | 0:5fa232ee5fdf | 242 | // Give player 50 points (in BCD!). | 
| RichardE | 0:5fa232ee5fdf | 243 | player->AddToScore( 0x50 ); | 
| RichardE | 0:5fa232ee5fdf | 244 | // Make a noise. | 
| RichardE | 0:5fa232ee5fdf | 245 | SoundManager::Instance.PlaySound( Sounds::RescueHuman, 0, 0 ); | 
| RichardE | 0:5fa232ee5fdf | 246 | } | 
| RichardE | 5:0b0651ac7832 | 247 | } | 
| RichardE | 5:0b0651ac7832 | 248 | } | 
| RichardE | 0:5fa232ee5fdf | 249 | #endif | 
| RichardE | 0:5fa232ee5fdf | 250 | } | 
| RichardE | 0:5fa232ee5fdf | 251 | |
| RichardE | 0:5fa232ee5fdf | 252 | /***********************************************************************************/ | 
| RichardE | 0:5fa232ee5fdf | 253 | /* WAIT UNTIL SLOT FREE FOR A NEW SOUND, PLAY IT AND WAIT FOR ALL SOUNDS TO FINISH */ | 
| RichardE | 0:5fa232ee5fdf | 254 | /***********************************************************************************/ | 
| RichardE | 0:5fa232ee5fdf | 255 | // Pass sound to play in soundToPlay parameter. | 
| RichardE | 5:0b0651ac7832 | 256 | void LevelNormal::PlaySoundAndWait( const UInt8 *soundToPlay ) | 
| RichardE | 5:0b0651ac7832 | 257 | { | 
| RichardE | 0:5fa232ee5fdf | 258 | #if 0 | 
| RichardE | 5:0b0651ac7832 | 259 | // Keep trying to play sound until it works and meanwhile | 
| RichardE | 5:0b0651ac7832 | 260 | // keep currently playing sounds going. | 
| RichardE | 5:0b0651ac7832 | 261 | while( ! SoundManager::Instance.PlaySound( soundToPlay, 0, 0 ) ) { | 
| RichardE | 5:0b0651ac7832 | 262 | // Update sound manager. | 
| RichardE | 5:0b0651ac7832 | 263 | SoundManager::Instance.Update(); | 
| RichardE | 5:0b0651ac7832 | 264 | // Wait for frame flyback. | 
| RichardE | 5:0b0651ac7832 | 265 | GD.waitvblank(); | 
| RichardE | 5:0b0651ac7832 | 266 | } | 
| RichardE | 5:0b0651ac7832 | 267 | // Now wait until all sounds have finished. | 
| RichardE | 5:0b0651ac7832 | 268 | while( SoundManager::Instance.CountSoundsPlaying() > 0 ) { | 
| RichardE | 5:0b0651ac7832 | 269 | // Update sound manager. | 
| RichardE | 5:0b0651ac7832 | 270 | SoundManager::Instance.Update(); | 
| RichardE | 5:0b0651ac7832 | 271 | // Wait for frame flyback. | 
| RichardE | 5:0b0651ac7832 | 272 | GD.waitvblank(); | 
| RichardE | 5:0b0651ac7832 | 273 | } | 
| RichardE | 0:5fa232ee5fdf | 274 | #endif | 
| RichardE | 0:5fa232ee5fdf | 275 | } | 
| RichardE | 0:5fa232ee5fdf | 276 | |
| RichardE | 0:5fa232ee5fdf | 277 | /*************/ | 
| RichardE | 0:5fa232ee5fdf | 278 | /* PLAY LOOP */ | 
| RichardE | 0:5fa232ee5fdf | 279 | /*************/ | 
| RichardE | 0:5fa232ee5fdf | 280 | // Returns code indicating how level ended. | 
| RichardE | 0:5fa232ee5fdf | 281 | // This method should be called from the Play method after the | 
| RichardE | 0:5fa232ee5fdf | 282 | // level data has been initialised and the return value returned | 
| RichardE | 0:5fa232ee5fdf | 283 | // by the Play method. | 
| RichardE | 5:0b0651ac7832 | 284 | Level::LevelExitCode LevelNormal::PlayLoop( void ) | 
| RichardE | 5:0b0651ac7832 | 285 | { | 
| RichardE | 5:0b0651ac7832 | 286 | // Do nothing if Gameduino has not been specified, level data is NULL or player has not been specified. | 
| RichardE | 5:0b0651ac7832 | 287 | if( ( gd != (Gameduino*)NULL ) || ( DataForLevel != (LevelData*)NULL ) || ( player == (PlayerObject*)NULL ) ) { | 
| RichardE | 5:0b0651ac7832 | 288 | // Point static pointer to current instance. | 
| RichardE | 5:0b0651ac7832 | 289 | currentInstance = this; | 
| RichardE | 5:0b0651ac7832 | 290 | // Do some initialisation first. | 
| RichardE | 5:0b0651ac7832 | 291 | InitialiseLevel( gd ); | 
| RichardE | 5:0b0651ac7832 | 292 | // Redraw the screen. | 
| RichardE | 5:0b0651ac7832 | 293 | DrawLevel(); | 
| RichardE | 5:0b0651ac7832 | 294 | // Wait for frame flyback once before entering loop so collision data is recalculated. | 
| RichardE | 5:0b0651ac7832 | 295 | // At this point there should not be any sprites on the screen so no collisions | 
| RichardE | 5:0b0651ac7832 | 296 | // should be found. | 
| RichardE | 5:0b0651ac7832 | 297 | gd->waitvblank(); | 
| RichardE | 5:0b0651ac7832 | 298 | // Repeat until all enemies are dead or player is dead. | 
| RichardE | 5:0b0651ac7832 | 299 | bool allEnemiesAreDead = false; | 
| RichardE | 5:0b0651ac7832 | 300 | bool playerIsDead = false; | 
| RichardE | 5:0b0651ac7832 | 301 | bool gameIsOver = false; | 
| RichardE | 5:0b0651ac7832 | 302 | bool firstDraw = true; | 
| RichardE | 5:0b0651ac7832 | 303 | while( ! allEnemiesAreDead && ! gameIsOver ) { | 
| RichardE | 5:0b0651ac7832 | 304 | // Update sound manager. | 
| RichardE | 5:0b0651ac7832 | 305 | // SoundManager::Instance.Update(); | 
| RichardE | 5:0b0651ac7832 | 306 | // Wait for frame flyback. | 
| RichardE | 5:0b0651ac7832 | 307 | gd->waitvblank(); | 
| RichardE | 5:0b0651ac7832 | 308 | // Check for collisions between player and other objects. | 
| RichardE | 5:0b0651ac7832 | 309 | CheckPlayerCollisions( &playerIsDead ); | 
| RichardE | 5:0b0651ac7832 | 310 | #if 0 | 
| RichardE | 5:0b0651ac7832 | 311 | // Check for collisions between humans and enemies that squash. | 
| RichardE | 5:0b0651ac7832 | 312 | GameObject::FindCollisions( DataForLevel->Humans, LevelData::MaxHumans, &LevelNormal::HandleHumanCollision ); | 
| RichardE | 5:0b0651ac7832 | 313 | // Check for collisions between player bullets and enemies. | 
| RichardE | 5:0b0651ac7832 | 314 | GameObject::FindCollisions( player->GetBullets(), BulletManager::MaxBullets, &LevelNormal::HandleBulletCollision ); | 
| RichardE | 5:0b0651ac7832 | 315 | #endif | 
| RichardE | 5:0b0651ac7832 | 316 | // Redraw the player's score and number of lives. | 
| RichardE | 5:0b0651ac7832 | 317 | DrawScoreAndLives(); | 
| RichardE | 7:e72691603fd3 | 318 | // Draw all the enemies. | 
| RichardE | 7:e72691603fd3 | 319 | GameObject::DrawAll( gd, DataForLevel->Enemies, LevelData::MaxEnemies ); | 
| RichardE | 1:dfd5eaaf96a3 | 320 | #if 0 | 
| RichardE | 5:0b0651ac7832 | 321 | // Draw all the humans. | 
| RichardE | 5:0b0651ac7832 | 322 | GameObject::DrawAll( DataForLevel->Humans, LevelData::MaxHumans ); | 
| RichardE | 5:0b0651ac7832 | 323 | // Draw all the explosions. | 
| RichardE | 5:0b0651ac7832 | 324 | GameObject::DrawAll( ExplosionManager::Instance.GetExplosions(), ExplosionManager::MaxExplosions ); | 
| RichardE | 5:0b0651ac7832 | 325 | #endif | 
| RichardE | 5:0b0651ac7832 | 326 | // Draw the player. | 
| RichardE | 5:0b0651ac7832 | 327 | player->Draw( gd ); | 
| RichardE | 5:0b0651ac7832 | 328 | // Draw the player's bullets. | 
| RichardE | 6:8bbdb70bc11c | 329 | GameObject::DrawAll( gd, player->GetBullets(), BulletManager::MaxBullets ); | 
| RichardE | 5:0b0651ac7832 | 330 | // Increment the frame counter. | 
| RichardE | 5:0b0651ac7832 | 331 | FrameCounter++; | 
| RichardE | 5:0b0651ac7832 | 332 | // After first redraw play level start sound and wait for it to end. | 
| RichardE | 5:0b0651ac7832 | 333 | if( firstDraw ) { | 
| RichardE | 5:0b0651ac7832 | 334 | // PlaySoundAndWait( Sounds::StartLevel ); | 
| RichardE | 5:0b0651ac7832 | 335 | firstDraw = false; | 
| RichardE | 1:dfd5eaaf96a3 | 336 | } | 
| RichardE | 5:0b0651ac7832 | 337 | // If player was killed then play death march and wait for it to finish. | 
| RichardE | 5:0b0651ac7832 | 338 | if( playerIsDead ) { | 
| RichardE | 5:0b0651ac7832 | 339 | #ifdef CHATTY | 
| RichardE | 5:0b0651ac7832 | 340 | pc.puts( "Player got killed.\r\n" ); | 
| RichardE | 5:0b0651ac7832 | 341 | #endif | 
| RichardE | 5:0b0651ac7832 | 342 | // Player got killed. | 
| RichardE | 5:0b0651ac7832 | 343 | // PlaySoundAndWait( Sounds::PlayerDead ); | 
| RichardE | 5:0b0651ac7832 | 344 | // One less life for player. | 
| RichardE | 5:0b0651ac7832 | 345 | if( player->Lives > 0 ) { | 
| RichardE | 5:0b0651ac7832 | 346 | player->Lives--; | 
| RichardE | 5:0b0651ac7832 | 347 | } | 
| RichardE | 5:0b0651ac7832 | 348 | // Game is over when player has no more lives. | 
| RichardE | 5:0b0651ac7832 | 349 | gameIsOver = ( player->Lives == 0 ); | 
| RichardE | 5:0b0651ac7832 | 350 | // If game is not over then re-initialise level using any remaining enemies. | 
| RichardE | 5:0b0651ac7832 | 351 | if( ! gameIsOver ) { | 
| RichardE | 5:0b0651ac7832 | 352 | #ifdef CHATTY | 
| RichardE | 5:0b0651ac7832 | 353 | pc.puts( "Game is over.\r\n" ); | 
| RichardE | 5:0b0651ac7832 | 354 | #endif | 
| RichardE | 5:0b0651ac7832 | 355 | // Remove all objects that do not survive a level restart (like enemy bullets). | 
| RichardE | 5:0b0651ac7832 | 356 | GameObject::RemoveUnretainedObjects( DataForLevel->Enemies, LevelData::MaxEnemies ); | 
| RichardE | 5:0b0651ac7832 | 357 | InitialiseLevel( gd ); | 
| RichardE | 5:0b0651ac7832 | 358 | DrawLevel(); | 
| RichardE | 5:0b0651ac7832 | 359 | gd->waitvblank(); | 
| RichardE | 5:0b0651ac7832 | 360 | playerIsDead = false; | 
| RichardE | 5:0b0651ac7832 | 361 | firstDraw = true; | 
| RichardE | 5:0b0651ac7832 | 362 | } | 
| RichardE | 5:0b0651ac7832 | 363 | } | 
| RichardE | 5:0b0651ac7832 | 364 | else { | 
| RichardE | 5:0b0651ac7832 | 365 | // Move all the enemies and check if all dead. | 
| RichardE | 5:0b0651ac7832 | 366 | allEnemiesAreDead = ! GameObject::MoveAll( DataForLevel->Enemies, LevelData::MaxEnemies ); | 
| RichardE | 5:0b0651ac7832 | 367 | // If there are still some enemies alive then check if those that remain are indestructable. | 
| RichardE | 5:0b0651ac7832 | 368 | // If only indestructable enemies survive then act as if all enemies are dead. | 
| RichardE | 5:0b0651ac7832 | 369 | // You need to do this or you would never be able to complete a level that had indestructable | 
| RichardE | 5:0b0651ac7832 | 370 | // enemies on it. | 
| RichardE | 5:0b0651ac7832 | 371 | if( ! allEnemiesAreDead ) { | 
| RichardE | 5:0b0651ac7832 | 372 | allEnemiesAreDead = EnemyObject::AreAllIndestructable( | 
| RichardE | 6:8bbdb70bc11c | 373 | (const EnemyObject**)DataForLevel->Enemies, | 
| RichardE | 6:8bbdb70bc11c | 374 | LevelData::MaxEnemies | 
| RichardE | 6:8bbdb70bc11c | 375 | ); | 
| RichardE | 5:0b0651ac7832 | 376 | } | 
| RichardE | 7:e72691603fd3 | 377 | #if 0 | 
| RichardE | 5:0b0651ac7832 | 378 | // Move all the humans. | 
| RichardE | 5:0b0651ac7832 | 379 | GameObject::MoveAll( DataForLevel->Humans, LevelData::MaxHumans ); | 
| RichardE | 5:0b0651ac7832 | 380 | // Move (update) all the explosions. | 
| RichardE | 5:0b0651ac7832 | 381 | GameObject::MoveAll( ExplosionManager::Instance.GetExplosions(), ExplosionManager::MaxExplosions ); | 
| RichardE | 5:0b0651ac7832 | 382 | #endif | 
| RichardE | 5:0b0651ac7832 | 383 | // Read the player's controls. | 
| RichardE | 5:0b0651ac7832 | 384 | player->ReadControls(); | 
| RichardE | 5:0b0651ac7832 | 385 | // Move the player. | 
| RichardE | 5:0b0651ac7832 | 386 | player->Move(); | 
| RichardE | 5:0b0651ac7832 | 387 | // Move the player's bullets. | 
| RichardE | 5:0b0651ac7832 | 388 | GameObject::MoveAll( player->GetBullets(), BulletManager::MaxBullets ); | 
| RichardE | 0:5fa232ee5fdf | 389 | } | 
| RichardE | 1:dfd5eaaf96a3 | 390 | } | 
| RichardE | 5:0b0651ac7832 | 391 | // Player completed level or game is over. | 
| RichardE | 5:0b0651ac7832 | 392 | return gameIsOver ? GameOver : Completed; | 
| RichardE | 0:5fa232ee5fdf | 393 | } | 
| RichardE | 5:0b0651ac7832 | 394 | else { | 
| RichardE | 5:0b0651ac7832 | 395 | // Level data or player were not specified. | 
| RichardE | 5:0b0651ac7832 | 396 | return Completed; | 
| RichardE | 5:0b0651ac7832 | 397 | } | 
| RichardE | 0:5fa232ee5fdf | 398 | } | 
| RichardE | 0:5fa232ee5fdf | 399 |