// Required for ALL CodeWarrior projects // #define CWBuild #if defined __MWERKS__ #include <__rts_info_t__.h> #endif #include #include #include #include "main.h" #include "..\2dfw\fw.h" #include "..\2dfw\pad.h" #include "explosn.h" #include "attacker.h" #include "dataman.h" #define PLAYER_LAYER (1) #define SHOT_LAYER (1<<1) #define ENEMY_LAYER (1<<2) #define BOMB_LAYER (1<<3) #define GAME_STAGE_WAIT 0 #define GAME_STAGE_BEGIN 1 #define GAME_STAGE_PLAY 2 #define GAME_STAGE_NEW_WAVE 3 #define GAME_STAGE_NEW_WAVE_WAIT 4 #define GAME_STAGE_NEW_PLAYER_WAIT 5 #define GAME_STAGE_ENTER_INITIALS_BEGIN 6 #define GAME_STAGE_ENTER_INITIALS 7 #define GAME_STAGE_ENTER_INITIALS_END 8 #define MAX_HIGHSCORETABLE 6 typedef struct { int ActorID; int YAnimID; } shots; typedef struct { int ActorID; int YAnimID; } bombs; void checkNewAttacker ( void ); void pickNextAttacker ( int rowNum ); void newWave ( void ); void killWave ( void ); void resetWave ( void ); void newPlayer ( void ); void handlePlayer ( void ); void loadCostumes ( void ); void loadSounds ( void ); short playSound ( short SoundID, short program, short volume ); void stopSound ( short voiceID, short SoundID, short program ); void initHighScores ( void ); void initActors ( void ); void moveEnemyBulk ( void ); void playerShoot ( void ); void checkShotCollisions ( void ); int checkPlayerHit ( void ); void ShowLogo ( void ); void showScore ( void ); void showHighScore ( void ); void showLevel ( void ); void showLives ( void ); void enemyHit ( int ActorID ); void ShowInstructions ( void ); int EnemyCostume [3]; int PlayerCostume; int ShotCostume; int StarsCostume; int TextCostume; int TitleCostume; int BombCostume; int FlagCostume; int CostumePlayerAnim; int CostumeEnemyAnim; int StarsAnim1; int StarsAnim2; typedef struct { int firstActorID; // Actor ID of the leftmost actor in the row int lastActorID; // Actor ID of the rightmost actor in the row int angle; int speed; int selectionCount; // How many times has this row been selected since the int maxpausetime; int pausetime; int maxbombwait; int floatingPoints; int attackingPoints; } enemyrowdetails; enemyrowdetails EnemyRowDetail[4]; // One entry per row of aliens int EnemyActor [4*10+8]; // store ALL the actorIDs of the aliens int attackSide; // What end of a row should the next attacker be picked int attackwait; int PlayerActor; int nextAttackSide; int scoreText; int score; int highscoreText; int highscore; int livesText; int lives; int currentWave; int levelBonus; // Increment at end of each wave. Whne majic number reached bonus life awarded int TitleActor; int highText[10]; int highScores[10]; char highInitials[10][4]; int instructionScreen; int instructionWait; int StarsActor[24]; shots PlayerShotActor[PLAYER_MAX_SHOTS]; int LevelActor[5]; #define MAX_BOMBS 10 bombs EnemyBombActor[MAX_BOMBS]; int PlayerMinX; int PlayerMaxX; int PlayerXPos; int PlayerYPos; int PlayerMovementDirection; int BulkStep = 0; int BulkDirection = 1; int MiniStep = 0; int MiniDirection = 1; int AnimValue = 0; int EnemyAnimBulk; int EnemyAlive = 0; short SoundsVabID; short backSound; main() { #if defined __MWERKS__ // required for ALL CodeWarrior Projects // heap starts after the main program on a 16-byte boundary unsigned long lclHeapStart=(_end & 0xFFFFFFF0L)+0x10; // heap extends to the bottom of the stack. unsigned long lclHeapSize=((_stack_addr-(_stack_size<<10)) & 0xFFFFFFF0L)-lclHeapStart; #endif int finished = 0; int gameStage; int newWaveWait; int newPlayerWait; int highPos; int initialPos; gameStage = GAME_STAGE_WAIT; #if defined __MWERKS__ InitHeap((unsigned long *)lclHeapStart, lclHeapSize); #endif // Initialise our game framework fwDirectInit (); // Tell the framework how many bit to right shift our stage positions in order to // convert them to real pixel positions. fwStageSetPixelShift (STAGE_SHIFT); ShowLogo (); loadCostumes (); loadSounds (); initActors (); initAttackers (); initHighScores (); newPlayer (); score = 0; highscore = 0; lives = 0; instructionScreen = 2; currentWave = 0; while ( finished == 0 ) { // Get the latest state of the pads. fwPadRead(); if ( ( fwPadGetDown ( 0 ) & (PADselect | PADstart ) ) == ( PADselect | PADstart ) ) finished = 1; switch ( gameStage ) { case GAME_STAGE_WAIT: instructionWait--; if ( instructionWait <= 0 ) { instructionScreen++; if ( instructionScreen > 2 ) { instructionScreen = 0; } ShowInstructions (); instructionWait = 240; } if ( fwPadGetDown ( 0 ) & PADstart ) { gameStage = GAME_STAGE_BEGIN; showScore(); killWave(); } moveEnemyBulk (); moveAttackers(); break; case GAME_STAGE_BEGIN: lives = 3; levelBonus=0; currentWave = 0; score = 0; showScore(); showLives(); showLevel(); newPlayer(); gameStage = GAME_STAGE_NEW_WAVE; { int l; for ( l = 0; l < MAX_HIGHSCORETABLE; l ++ ) { fwTextHide ( highText[l]); } } fwActorSetOnStage ( TitleActor, OFF_STAGE ); break; case GAME_STAGE_NEW_WAVE: handlePlayer (); newWaveWait = 120; gameStage = GAME_STAGE_NEW_WAVE_WAIT; stopSound ( backSound, SoundsVabID, 3 ); levelBonus++; if ( levelBonus == 3 ) { lives++; levelBonus=0; playSound ( SoundsVabID, 4, 100 ); showLives(); }; break; case GAME_STAGE_NEW_WAVE_WAIT: handlePlayer (); newWaveWait--; if ( newWaveWait == 0 ) { newWave (); showLevel(); gameStage = GAME_STAGE_PLAY; backSound = playSound ( SoundsVabID, 3, 64 ); } break; case GAME_STAGE_NEW_PLAYER_WAIT: newPlayerWait--; if ( newPlayerWait % 15 == 0 && newPlayerWait > 300) { startExplosion ( fwActorGetXPos ( PlayerActor ), fwActorGetYPos ( PlayerActor ) ); } if ( newPlayerWait == 0 ) { // If this was our last life then its end of game Im afraid if ( lives == 1 ) { if ( score > highscore ) { highscore = score; showHighScore (); } gameStage = GAME_STAGE_WAIT; instructionScreen = 2; instructionWait = 120; ShowInstructions (); { int l; for ( l= 0; l < MAX_HIGHSCORETABLE; l++ ) { fwTextShow ( highText[l]); } } fwActorSetOnStage ( TitleActor, ON_STAGE ); stopSound ( backSound, SoundsVabID, 3 ); // Special case.. if the player got into the high // score table then display it right away // and let the player enter initials if ( score > highScores[9] ) { instructionScreen = 1; gameStage = GAME_STAGE_ENTER_INITIALS_BEGIN; } } else { lives--; showLives(); newPlayer (); gameStage = GAME_STAGE_PLAY; } } moveEnemyBulk (); moveAttackers(); break; case GAME_STAGE_PLAY: handlePlayer (); checkNewAttacker (); moveEnemyBulk (); moveAttackers(); if ( EnemyAlive == 0 ) { gameStage = GAME_STAGE_NEW_WAVE; } break; case GAME_STAGE_ENTER_INITIALS_BEGIN: // Find out what position we have reached for ( highPos = 0; highPos < MAX_HIGHSCORETABLE; highPos++ ) { // And shuffle down the others if necessary if ( score > highScores[highPos] ) { if ( highPos < ( MAX_HIGHSCORETABLE- 1 ) ) { int temp; for ( temp = ( MAX_HIGHSCORETABLE - 2 ); temp >= highPos; temp-- ) { highScores[temp+1] = highScores[temp]; highInitials[temp+1][0] = highInitials[temp][0]; highInitials[temp+1][1] = highInitials[temp][1]; highInitials[temp+1][2] = highInitials[temp][2]; } } highScores[highPos] = score; break; } } gameStage = GAME_STAGE_ENTER_INITIALS; instructionScreen = 1; initialPos = 0; highInitials[highPos][0] = 'A'; highInitials[highPos][1] = '@'; highInitials[highPos][2] = '@'; ShowInstructions (); moveEnemyBulk (); moveAttackers(); break; case GAME_STAGE_ENTER_INITIALS: // Let the player enter initials // left/right to cycle through the chars // and fire to go to next char. // All three chars done will end this stage if ( fwPadGetPressed (0) & PADRdown ) { // Accept current char and move onto next initialPos++; if ( initialPos > 2 ) { gameStage = GAME_STAGE_ENTER_INITIALS_END; } else { highInitials[highPos][initialPos]='A'; ShowInstructions(); } } if ( fwPadGetPressed(0) & PADLleft ) { highInitials[highPos][initialPos]--; if ( highInitials[highPos][initialPos]<'A' ) { highInitials[highPos][initialPos]='Z'; } ShowInstructions(); } if ( fwPadGetPressed(0) & PADLright ) { highInitials[highPos][initialPos]++; if ( highInitials[highPos][initialPos]>'Z' ) { highInitials[highPos][initialPos]='A'; } ShowInstructions(); } moveEnemyBulk (); moveAttackers(); break; case GAME_STAGE_ENTER_INITIALS_END: score = 0; lives = 3; gameStage = GAME_STAGE_WAIT; moveEnemyBulk (); moveAttackers(); break; } checkShotCollisions (); if ( checkPlayerHit () ) { newPlayerWait = 360; gameStage = GAME_STAGE_NEW_PLAYER_WAIT; // reset attack timers for the attackers resetWave (); } showExplosions (); fwDirectRefresh (); } } void initHighScores ( void ) { int highPos; for ( highPos = 0; highPos < MAX_HIGHSCORETABLE; highPos++ ) { highScores[highPos] = 0; highInitials[highPos][0]='Q'; highInitials[highPos][1]='B'; highInitials[highPos][2]='P'; } } void ShowInstructions ( void ) { int textNum; char textBuffer[11]; switch ( instructionScreen ) { case 2: fwTextChange ( highText[0], "@GRAPHICS@@" ); fwTextChange ( highText[1], "PROGRAMMING" ); fwTextChange ( highText[2], "@@@SOUND@@@" ); fwTextChange ( highText[3], "@@@@BY@@@@@" ); fwTextChange ( highText[4], "JOHN WOJCIK" ); fwTextChange ( highText[5], "QUIETBLOKE@" ); break; case 1: for ( textNum = 0; textNum < MAX_HIGHSCORETABLE; textNum++ ) { sprintf ( textBuffer, "%3s@@@%05d", highInitials[textNum], highScores[textNum] ); fwTextChange ( highText[textNum], textBuffer ); } break; case 0: fwTextChange ( highText[0], "PRESS@START" ); fwTextChange ( highText[1], "@TO@@BEGIN@" ); fwTextChange ( highText[2], "@@@@@@@@@@@" ); fwTextChange ( highText[3], "PRESS@START" ); fwTextChange ( highText[4], "AND@@SELECT" ); fwTextChange ( highText[5], "@@TO@QUIT@@" ); break; default: fwTextChange ( highText[0], "@@@@@@@@@@@" ); fwTextChange ( highText[1], "@@@@@@@@@@@" ); fwTextChange ( highText[2], "@@@@@@@@@@@" ); fwTextChange ( highText[3], "@@@@@@@@@@@" ); fwTextChange ( highText[4], "@@@@@@@@@@@" ); fwTextChange ( highText[5], "@@@@@@@@@@@" ); } } void showScore ( void ) { char scoreStr[6]; sprintf ( scoreStr, "%05d", score ); fwTextChange ( scoreText, scoreStr ); } void showHighScore ( void ) { char scoreStr[6]; sprintf ( scoreStr, "%05d", highscore ); fwTextChange ( highscoreText, scoreStr ); } void showLives ( void ) { char livesStr[6]; sprintf ( livesStr, "%02d", lives-1 ); fwTextChange ( livesText, livesStr ); } void showLevel ( void ) { int currentActor; char levelStr[3]; if ( currentWave <= 5 ) { // Up to level 5 simply switch on the right number of flags for ( currentActor = 0; currentActor < 5; currentActor++ ) { if ( currentActor < currentWave ) { // Set it to the flag actor // and display fwActorChangeCostume ( LevelActor[currentActor], FlagCostume ); fwActorSetOnStage ( LevelActor[currentActor], ON_STAGE ); } else { // or hide fwActorSetOnStage ( LevelActor[currentActor], OFF_STAGE ); } } } else { if (currentWave <=12 ) { // we can display 3 flags , a plus and a single digit ( 3-9 ) sprintf ( levelStr, "%01d", currentWave-3 ); fwActorChangeCostume ( LevelActor[0], FlagCostume ); fwActorSetOnStage ( LevelActor[0], ON_STAGE ); fwActorChangeCostume ( LevelActor[1], FlagCostume ); fwActorSetOnStage ( LevelActor[1], ON_STAGE ); fwActorChangeCostume ( LevelActor[2], FlagCostume ); fwActorSetOnStage ( LevelActor[2], ON_STAGE ); fwActorChangeCostume ( LevelActor[3], TextCostume + 15); fwActorSetOnStage ( LevelActor[3], ON_STAGE ); fwActorChangeCostume ( LevelActor[4], TextCostume + levelStr[0]-'0'); fwActorSetOnStage ( LevelActor[4], ON_STAGE ); } else { // we can display 3 flags , a plus and a single digit ( 3-9 ) sprintf ( levelStr, "%02d", currentWave-3 ); fwActorChangeCostume ( LevelActor[0], FlagCostume ); fwActorSetOnStage ( LevelActor[0], ON_STAGE ); fwActorChangeCostume ( LevelActor[1], FlagCostume ); fwActorSetOnStage ( LevelActor[1], ON_STAGE ); fwActorChangeCostume ( LevelActor[2], TextCostume + 15); fwActorSetOnStage ( LevelActor[2], ON_STAGE ); fwActorChangeCostume ( LevelActor[3], TextCostume + levelStr[0]-'0'); fwActorSetOnStage ( LevelActor[3], ON_STAGE ); fwActorChangeCostume ( LevelActor[4], TextCostume + levelStr[0]-'0'); fwActorSetOnStage ( LevelActor[4], ON_STAGE ); } } } void handlePlayer ( void ) { int padd; padd = fwPadGetDown ( 0 ); PlayerMovementDirection = PLAYER_MOVE_STILL; if ( padd & PADLleft ) { if ( PlayerXPos > PlayerMinX ) { PlayerXPos -= PLAYER_MOVE_SPEED; fwActorPos ( PlayerActor, PlayerXPos, PlayerYPos); PlayerMovementDirection = PLAYER_MOVE_LEFT; } } if ( padd & PADLright ) { if ( PlayerXPos < PlayerMaxX ) { PlayerXPos += PLAYER_MOVE_SPEED; fwActorPos ( PlayerActor, PlayerXPos, PlayerYPos); PlayerMovementDirection = PLAYER_MOVE_RIGHT; } } if ( fwPadGetPressed (0) & PADRdown ) { playerShoot (); } } void loadCostumes ( void ) { // EnemyCostume[0] = fwCostumeAdd ( TEXTURE_SHIPSORIGINAL, 2, 3 ); EnemyCostume[0] = fwCostumeAdd ( TEXTURE_SHIPS, 2, 3 ); EnemyCostume[1] = EnemyCostume[0]+2; EnemyCostume[2] = EnemyCostume[1]+2; PlayerCostume = fwCostumeAdd ( TEXTURE_BASE, 2, 1 ); ShotCostume = fwCostumeAdd ( TEXTURE_SHOT, 1, 1 ); StarsCostume = fwCostumeAdd ( TEXTURE_STARS, 2, 1 ); TextCostume = fwCostumeAdd ( TEXTURE_WRITING, 8, 6 ); BombCostume = ShotCostume; TitleCostume = fwCostumeAdd ( TEXTURE_TITLE, 1, 1 ); FlagCostume = fwCostumeAdd ( TEXTURE_FLAG, 1, 1 ); } void loadSounds ( void ) { SoundsVabID = SsVabTransfer ( (u_char *)SOUND_HEADER, (u_char *)SOUND_BODY, -1, 1 ); } short playSound ( short SoundID, short program, short volume ) { short voiceNum; voiceNum = SsUtKeyOn(SoundID, program, 0, 30, 0, volume, volume); return ( voiceNum ); } void stopSound ( short voiceNum, short SoundID, short program ) { SsUtKeyOff ( voiceNum, SoundID, program, 0, 30 ); } void initActors ( void ) { int currentActor; int xpos; int ypos; int currentActorx; int currentActory; int tempText; // Title texts // Main title text // NOTE : I have actually set the @ char to be a space in my tim TitleActor = fwActorAdd ( TitleCostume ); fwActorPos ( TitleActor, ( fwDirectScreenWidth() >> 1 ) << STAGE_SHIFT, 60 << STAGE_SHIFT ); // Top line of text, score, hii score and lives fwTextSetFont ( TextCostume, '0' ); tempText = fwTextAdd ( "SCORE", 8<> 1)-30)<>1) )<>1; ypos = fwActorGetPixelHeight( StarsActor[0] ) << (STAGE_SHIFT)>>1; ypos-= fwActorGetPixelHeight( StarsActor[0] ) << (STAGE_SHIFT); StarsAnim1 = fwAnimateAdd ( ANIMATE_REPEAT, -1, 0,0,(fwActorGetPixelHeight( StarsActor[0] )-1) << (STAGE_SHIFT),1<<(STAGE_SHIFT),2 ); fwAnimateStart ( StarsAnim1 ); fwActorAnimateYPos ( StarsActor[0], StarsAnim1); currentActor = 0; for ( currentActory = 0; currentActory < 3; currentActory++) { xpos = fwActorGetPixelWidth( StarsActor[0] ) << (STAGE_SHIFT)>>1; for ( currentActorx = 0; currentActorx < 4; currentActorx++) { if ( currentActor != 0 ) { StarsActor[currentActor] = fwActorAdd ( StarsCostume ); fwActorAnimateYPos ( StarsActor[currentActor], StarsAnim1); } fwActorPos ( StarsActor[currentActor], xpos, ypos ); xpos+= fwActorGetPixelWidth( StarsActor[0] ) << (STAGE_SHIFT); currentActor++; } ypos+= fwActorGetPixelHeight( StarsActor[0] ) << (STAGE_SHIFT); } // repeat the stars again for the far back stars xpos = fwActorGetPixelWidth( StarsActor[0] ) << (STAGE_SHIFT)>>1; ypos = fwActorGetPixelHeight( StarsActor[0] ) << (STAGE_SHIFT)>>1; ypos-= fwActorGetPixelHeight( StarsActor[0] ) << (STAGE_SHIFT); StarsAnim2 = fwAnimateAdd ( ANIMATE_REPEAT, -1, 0,0,(fwActorGetPixelHeight( StarsActor[0] )-1) << (STAGE_SHIFT),1<<(STAGE_SHIFT),40 ); fwAnimateStart ( StarsAnim2 ); for ( currentActory = 0; currentActory < 3; currentActory++) { xpos = fwActorGetPixelWidth( StarsActor[0] ) << (STAGE_SHIFT)>>1; for ( currentActorx = 0; currentActorx < 4; currentActorx++) { StarsActor[currentActor] = fwActorAdd ( StarsCostume+1 ); fwActorAnimateYPos ( StarsActor[currentActor], StarsAnim2); fwActorPos ( StarsActor[currentActor], xpos, ypos ); xpos+= fwActorGetPixelWidth( StarsActor[0] ) << (STAGE_SHIFT); currentActor++; } ypos+= fwActorGetPixelHeight( StarsActor[0] ) << (STAGE_SHIFT); } // Set up the flag actors used to display current level at bottom left of screen LevelActor[0] = fwActorAdd ( FlagCostume ); xpos = fwActorGetPixelWidth( LevelActor[0] ) << (STAGE_SHIFT)>>1; ypos = ( fwDirectScreenHeight() << STAGE_SHIFT) - ( fwActorGetPixelHeight( LevelActor[0] ) << (STAGE_SHIFT)>>1); fwActorPos ( LevelActor[0], xpos, ypos ); fwActorSetOnStage ( LevelActor[0], OFF_STAGE ); for ( currentActor = 1; currentActor < 5; currentActor++ ) { LevelActor[currentActor] = fwActorAdd ( FlagCostume ); xpos+=fwActorGetPixelWidth( LevelActor[currentActor] ) << STAGE_SHIFT; fwActorPos ( LevelActor[currentActor], xpos, ypos ); fwActorSetOnStage ( LevelActor[currentActor], OFF_STAGE ); } } // Because the emeny bulk moves in strange and mysterious ways // Ive had to write a custom animate routine and simply plug the // final value into the animation. Crude but hey !.. it works for me void moveEnemyBulk ( void ) { int ReverseDirection = 0; if ( MiniDirection == 1 ) { MiniStep+=1; if ( MiniStep > ( ( 1 << STAGE_SHIFT ) ) >> 2 ) { MiniDirection = -1; } } else if ( MiniDirection == -1 ) { MiniStep--; if ( MiniStep < 1 ) { MiniDirection = 0; } } else { BulkStep+=BulkDirection; MiniDirection = 1; if ( BulkStep < 1 || BulkStep > 10 ) { ReverseDirection = 1; } } AnimValue += ( MiniStep * BulkDirection ); fwAnimateSetValue ( EnemyAnimBulk, AnimValue ); if ( ReverseDirection ) { BulkDirection *= -1; } } void playerShoot ( void ) { int CurrentShot; for ( CurrentShot = 0; CurrentShot < PLAYER_MAX_SHOTS; CurrentShot++ ) { if ( fwActorGetOnStage ( PlayerShotActor[CurrentShot].ActorID ) == OFF_STAGE ) { // We have a spare shot.. so lets fire it // First set the position of the shot to match the plane position // The xpos can ba hard coded. fwActorPos ( PlayerShotActor[CurrentShot].ActorID, PlayerXPos, 0 ); // And match the ypos animation to the y pos of the player // fwAnimateSetValue ( PlayerShotActor[CurrentShot].YAnimID, PlayerYPos ); fwAnimateInit ( PlayerShotActor[CurrentShot].YAnimID, ANIMATE_BOUNCE, 2, PlayerYPos, 0, PlayerYPos+1, SHOT_SPEED, 1 ); // fwAnimateSetChangeValue( PlayerShotActor[CurrentShot].YAnimID, (2<> 1 ); // Make the Shot Sound playSound ( SoundsVabID, 0, 127 ); break; } } } void enemyDropBomb ( int xpos, int ypos ) { int CurrentBomb; for ( CurrentBomb = 0; CurrentBomb < MAX_BOMBS; CurrentBomb++ ) { if ( fwActorGetOnStage ( EnemyBombActor[CurrentBomb].ActorID ) == OFF_STAGE ) { // We have a spare shot.. so lets fire it // First set the position of the shot to match the plane position // The xpos can ba hard coded. fwActorPos ( EnemyBombActor[CurrentBomb].ActorID, xpos, ypos ); // And match the ypos animation to the y pos of the player // fwAnimateSetValue ( PlayerShotActor[CurrentShot].YAnimID, PlayerYPos ); fwAnimateInit ( EnemyBombActor[CurrentBomb].YAnimID, ANIMATE_BOUNCE, 2, 0, 0, PlayerYPos, BOMB_SPEED, 1 ); // fwAnimateSetChangeValue( PlayerShotActor[CurrentShot].YAnimID, (2<> STAGE_SHIFT ) ) >> 1) ); fwActorSetLifeSpan ( EnemyBombActor[CurrentBomb].ActorID, ( ( 260 << STAGE_SHIFT ) - ypos ) / BOMB_SPEED ); // Mark the shot as being on stage fwActorSetOnStage ( EnemyBombActor[CurrentBomb].ActorID, ON_STAGE ); break; } } } void checkNewAttacker ( void ) { int currentRow; // Decrement all out counters. // Anyone who hits zero drops. for ( currentRow = 0; currentRow < 4; currentRow++ ) { EnemyRowDetail[currentRow].pausetime--; if ( EnemyRowDetail[currentRow].pausetime == 0 ) { pickNextAttacker ( currentRow ); EnemyRowDetail[currentRow].pausetime = EnemyRowDetail[currentRow].maxpausetime; } } } void pickNextAttacker ( int rowNum ) { int selectedrow = 0; int currentAlien; int foundOne = 0; selectedrow = rowNum; // right .. so we have a row picked.. so now find the alien if ( attackSide == 0 ) { // pick the leftmost alien while ( foundOne == 0 && selectedrow <= 3 ) { currentAlien = EnemyRowDetail[selectedrow].firstActorID; while ( currentAlien <= EnemyRowDetail[selectedrow].lastActorID ) { if ( fwActorGetOnStage ( currentAlien ) == ON_STAGE ) { // Actor is onstage if ( isActorAttacking ( currentAlien ) == 0 ) { // Actor if not currently attacking // So let it drop startAttacker(currentAlien, EnemyRowDetail[selectedrow].angle, EnemyRowDetail[selectedrow].speed, EnemyRowDetail[selectedrow].maxbombwait); foundOne = 1; break; } } currentAlien++; } // We found nothing on our selected row so lets go up a row // and try again selectedrow++; } } else { // pick the rightmost alien while ( foundOne == 0 && selectedrow <= 3 ) { currentAlien = EnemyRowDetail[selectedrow].lastActorID; while ( currentAlien >= EnemyRowDetail[selectedrow].firstActorID ) { if ( fwActorGetOnStage ( currentAlien ) == ON_STAGE ) { // Actor is onstage if ( isActorAttacking ( currentAlien ) == 0 ) { // Actor if not currently attacking // So let it drop startAttacker(currentAlien, 360 - EnemyRowDetail[selectedrow].angle, EnemyRowDetail[selectedrow].speed, EnemyRowDetail[selectedrow].maxbombwait); foundOne = 1; break; } } currentAlien--; } // We found nothing on our selected row so lets go up a row // and try again selectedrow++; } } attackSide= ( attackSide + 1) & 1; } void newWave ( void ) { int currentEnemy; int waveDivider; EnemyAlive=40; for ( currentEnemy = 0; currentEnemy < 40; currentEnemy++ ) { fwActorSetOnStage ( EnemyActor[currentEnemy], ON_STAGE ); } currentWave++; if ( currentWave > 20 ) { waveDivider = 20; } else { waveDivider = (currentWave)+10; } // Set the attack and bomb speeds based on the wave we are on EnemyRowDetail[0].maxpausetime = ( 50 * 24 ) / waveDivider; EnemyRowDetail[0].maxbombwait = ( 30 * 24 ) / waveDivider; EnemyRowDetail[1].maxpausetime = ( 90 * 24 ) / waveDivider; EnemyRowDetail[1].maxbombwait = ( 30 * 24 ) / waveDivider; EnemyRowDetail[2].maxpausetime = ( 180 * 24 ) / waveDivider; EnemyRowDetail[2].maxbombwait = ( 20 * 24 ) / waveDivider; EnemyRowDetail[3].maxpausetime = ( 300 * 24 ) / waveDivider; EnemyRowDetail[3].maxbombwait = ( 15 * 24 ) / waveDivider; resetWave (); } // Simply remove all attackers from the screen void killWave ( void ) { int currentEnemy; EnemyAlive = 0; for ( currentEnemy = 0; currentEnemy < 40; currentEnemy++ ) { fwActorSetOnStage ( EnemyActor[currentEnemy], OFF_STAGE ); } } // reset the counters for each row in this wave void resetWave ( void ) { EnemyRowDetail[0].pausetime = EnemyRowDetail[0].maxpausetime; EnemyRowDetail[1].pausetime = EnemyRowDetail[1].maxpausetime; EnemyRowDetail[2].pausetime = EnemyRowDetail[2].maxpausetime; EnemyRowDetail[3].pausetime = EnemyRowDetail[3].maxpausetime; attackSide = 0; } void newPlayer ( void ) { PlayerXPos = 160 << STAGE_SHIFT; PlayerYPos = ( fwDirectScreenHeight () - fwActorGetPixelHeight ( PlayerActor ) ) << STAGE_SHIFT; fwActorPos ( PlayerActor, PlayerXPos, PlayerYPos ); fwActorSetOnStage ( PlayerActor, ON_STAGE ); } void checkShotCollisions ( void ) { int currentShot; int currentCollision; int hit; for ( currentShot = 0; currentShot < PLAYER_MAX_SHOTS; currentShot++ ) { hit=0; currentCollision = fwActorFirstCollision ( PlayerShotActor[currentShot].ActorID ); while ( currentCollision != -1 ) { // We hit something hit = 1; // Kill the target enemyHit ( currentCollision ); currentCollision = fwActorNextCollision ( PlayerShotActor[currentShot].ActorID, currentCollision ); } // If the shot hit one or more things if ( hit == 1 ) { // Kill the shot fwActorSetOnStage ( PlayerShotActor[currentShot].ActorID, OFF_STAGE ); } } } int checkPlayerHit ( void ) { int currentCollision; int hit= 0; currentCollision = fwActorFirstCollision ( PlayerActor ); while ( currentCollision != -1 ) { hit = 1; // if we hit an alien if ( currentCollision >= EnemyActor[0] && currentCollision <= EnemyActor[39] ) { enemyHit ( currentCollision ); } currentCollision = fwActorNextCollision ( PlayerActor, currentCollision ); } // Finally explode ourselves if ( hit == 1 ) { fwActorSetOnStage ( PlayerActor, OFF_STAGE ); playSound ( SoundsVabID, 1, 127 ); startExplosion ( fwActorGetXPos ( PlayerActor ), fwActorGetYPos ( PlayerActor ) ); } return ( hit ); } void enemyHit ( int ActorID ) { int currentRow; // Kill the target fwActorSetOnStage ( ActorID, OFF_STAGE ); startExplosion ( fwActorGetXPos ( ActorID ), fwActorGetYPos ( ActorID ) ); // And we must of course decrement the counter EnemyAlive--; // Find out how much to increment score by for ( currentRow = 0; currentRow < 4; currentRow++ ) { if ( ActorID >= EnemyRowDetail[currentRow].firstActorID && ActorID <= EnemyRowDetail[currentRow].lastActorID ) { if ( isActorAttacking ( ActorID ) ) { score = score + EnemyRowDetail[currentRow].attackingPoints; } else { score += EnemyRowDetail[currentRow].floatingPoints; } playSound ( SoundsVabID, 1, 127 ); break; } } // Display the new score showScore ( ); } void ShowLogo ( void ) { int ELogoCostume; int ELogoActor; int xpos; int ypos; int pause; int brightness; fwActorReset (); fwAnimateReset (); ELogoCostume = fwCostumeAdd ( TEXTURE_YAROZESCENE_LOGO, 1, 1 ); ELogoActor = fwActorAdd ( ELogoCostume ); ypos = ( fwDirectScreenHeight() >> 1 ) << STAGE_SHIFT; xpos = ( fwDirectScreenWidth() >> 1 ) << STAGE_SHIFT; fwActorPos ( ELogoActor, xpos, ypos ); fwActorSetAngle (ELogoActor, 90 ); fwActorSetOnStage ( ELogoActor, ON_STAGE ); brightness = 255; // fwDirectSetBackGround ( brightness, brightness, brightness ); fwActorSetRGB ( ELogoActor, brightness>>1, brightness>>1, brightness>>1 ); for ( pause = 0; pause < 100; pause++ ) { fwDirectRefresh (); } for ( brightness = 254; brightness > 0; brightness-=2 ) { // fwDirectSetBackGround ( brightness, brightness, brightness ); fwActorSetRGB ( ELogoActor, brightness>>1, brightness>>1, brightness>>1 ); fwDirectRefresh (); } fwActorReset (); fwAnimateReset (); // // ELogoCostume = fwCostumeAdd ( TEXTURE_QBLOGO, 1, 1 ); ELogoActor = fwActorAdd ( ELogoCostume ); ypos = ( fwDirectScreenHeight() >> 1 ) << STAGE_SHIFT; xpos = ( fwDirectScreenWidth() >> 1 ) << STAGE_SHIFT; fwActorPos ( ELogoActor, xpos, ypos ); fwActorSetOnStage ( ELogoActor, ON_STAGE ); brightness = 0; // fwDirectSetBackGround ( brightness, brightness, brightness ); fwActorSetRGB ( ELogoActor, brightness>>1, brightness>>1, brightness>>1 ); for ( brightness = 0; brightness <248; brightness+=4 ) { fwActorSetRGB ( ELogoActor, brightness>>1, brightness>>1, brightness>>1 ); fwDirectRefresh (); } for ( pause = 0; pause < 100; pause++ ) { fwDirectRefresh (); } for ( brightness = 248; brightness > 0; brightness-=4 ) { fwActorSetRGB ( ELogoActor, brightness>>1, brightness>>1, brightness>>1 ); fwDirectRefresh (); } fwActorReset (); fwAnimateReset (); }