// File : DogFight.c // Author : John Wojcik ( QuietBloke ) // Created : September 2000 // Desc : My first game written using my 2D Game framework. // The game is very simple. Two biplanes battle it out in the // Yaroze sky for air supremacy. // // History : // Date Author Description // -------- --------------- ---------------------------------------- // 08/09/00 QuietBloke Got the biplanes up and running. // 09/09/00 QuietBloke Wrote a nice pad handler. Removed it and placed // it into the framwork as a Pad Manager. // 10/09/00 QuietBloke Added shots for each plane. // 11/09/00 QuietBloke Spent ages putting large amounts of comments in // 28/09/00 QuietBloke Added Anti Aircraft fire at top of screen // Changed to interlaced mode // 30/09/00 QuietBloke Added collision detection for planes against enemy bullets. // 01/10/00 QuietBloke Added hangers and floor // 02/10/00 QuietBloke Completed collision detection fro planes and bullets. // Added player explosion upon death // 04/10/00 QuietBloke Added Stages to plane lifecycle. Players start in Hangers, // Take off along the ground till flying speed achieved the // Player can control to fly. // Added wall to seperate the two hangers. // Dying players now falls to ground ( or wall, hanger ) before // exploding. // 05/10/00 QuietBloke Added call to new Framework function to make the bounding // box of the planes a percentage of the actual plane actor size. // 10/10/00 QuietBloke Added Eclipse logo Advert at start of game. // Changed the look of the AAFire animation and randomly rotate // it for each explosion for variety. // 13/10/00 QuietBloke Changed startup screen to display YarozeScene Logo // 15/10/00 QuietBloke Single source file getting unwieldy. Split into header/code and // then split out plane movement code into seperate source files. // Re-wrote plane acceleration logic and wrote initial plane stall logic. // 16/10/00 QuietBloke Added bouncing Dogfight for begining of title/menu screen // 28/10/00 QuietBloke Added transparent smoke clouds for dying plane. // 13/11/00 QuietBloke Added semi-transparent aafire. Also player kills score and end game // when max kills reached ( 3 ). // Required for ALL CodeWarrior projects #include <__rts_info_t__.h> #include #include #include #include "fw.h" #include "pad.h" #include "dogfight.h" #include "PlaneMov.h" #include "TitleScr.h" #include "Inits.h" // Global vars for all actors and thier costumes. int PlaneCostume; // Store the 2 plane costume id's int ShotCostume; // Store the shot costume id int AAFireCostume; // Store the 6 Anti Aircraft fire costume id's int GroundCostume; // Store the Ground Costume id int HangerCostume; // Store the 2 Hanger costume id's int WallCostume; // Store the Wall costume id int DogfightCostume; // Store the Dogfight Text costume id int ELogoCostume; // Store the Eclipse Logo costume id int SmokeCostume; // Store the smoke cloud costume id int ScoreCostume; // Digits 0-9 to show scores int WallActor; // Store the wall actor id int HangerActor[2]; // Store the two hanger actor id's int GroundActor[10]; // Store the ground actor id's ( many as required to fill screen width ) int PlaneActor[2]; // Store the two actor id's int ShotActor[2][MAX_SHOTS]; // Store the shot actor id's. 5 shots per plane. int AAFireActor[12]; // Store the Anti Aircraft fire actor id's. 5 + 2 ( one for each plane ) int XPlaneAnim[2]; // Store the animation id's for the x movement for each plane. int YPlaneAnim[2]; // Store the animation id's for the y movement for each plane. int XShotAnim[2][MAX_SHOTS]; // Store the animation id's for the x movement for each shot. int YShotAnim[2][MAX_SHOTS]; // Store the animation id's for the y movement for each shot. int CostumeAAFireAnim[12]; // Costume animations for each AAFire actor. int PlayerStage[2]; // Current stage of each player. int PlaneAccel[2]; // How fast does a plane accelerate in the direction its pointing. int SmokeActor[2][10]; // puffs of smoke from dying plane int ScaleSmokeAnim[2][10]; // Store the animation ids for the scaled smoke int PlayerKills[2]; // Store how many times each player has made a kill int ScoreActor[2]; // Actor to show the kill score for each player. NOTE : Currently only 1 digit each // All global variables used to customize gameplay int PlaneAcceleration=(1<>5; // Gravity on planes int CheckPlaneCollisions ( int CurrentPlayer ); void CheckShotCollisions ( int CurrentPlayer ); void SetPlayerStage ( int CurrentPlayer, int NewStage ); void fireShot ( int CurrentPlayer, int CurrentShot ); void fireAAFire ( int CurrentAAFire ); void makePlaneSmoke ( int CurrentPlayer ); void ShowLogo ( void ); void ShowKills ( void ); void main ( void ) { int finished = 0; long padd; int CurrentPlayer; int CurrentShot; int CurrentAAFire; int TempSpeed; // 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; InitHeap((unsigned long *)lclHeapStart, lclHeapSize); // 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); // For debug purposes only. FntLoad ( 960,256); FntOpen (16,16,256,200,0,512); // Display the Eclipse Logo ShowLogo (); // Main title screen ShowTitleScreen (); // Once only initialisation of costumes for the game init (); // Initialise everything to start a new game initGame (); while ( finished == 0 ) { // Get the latest state of the pads. fwPadRead(); for ( CurrentPlayer = 0; CurrentPlayer < 2; CurrentPlayer++ ) { // I f a player has the max kills then the game ends if ( PlayerKills[CurrentPlayer] == 3 ) { finished = 1; } // Find out which buttons are up/down padd = fwPadGetDown ( CurrentPlayer ); // If either player hits start then the game is over. if ( padd & PADstart ) { finished = 1; } switch ( PlayerStage[CurrentPlayer] ) { case PLAYER_LANDED: // Do nothing // If player hits fire the we take off // Find out which buttons are up/down if ( padd & PADRup ) { SetPlayerStage ( CurrentPlayer, PLAYER_TAKE_OFF ); } break; case PLAYER_TAKE_OFF: if ( CurrentPlayer == 0 ) fwActorAddVelocity ( PlaneActor[0], 90, 4 ); else fwActorAddVelocity ( PlaneActor[1], 270, 4 ); TempSpeed = ABS ( fwAnimateGetChangeValue( XPlaneAnim[CurrentPlayer] ) ); // if ( ( TempSpeed >= ( PlaneAcceleration*1.5 ) ) || ( TempSpeed <= ( (PlaneAcceleration) * -1.5 ) ) ) if ( TempSpeed >= ( PlaneAcceleration*1.5 ) ) { // Lift the plane up one pixel ( otherwise we will collide with the ground ) fwActorAddVelocity ( PlaneActor[CurrentPlayer] ,0, 1<> PLANE_ACCEL_SHIFT)< PlaneStallSpeed ) { SetPlayerStage ( CurrentPlayer, PLAYER_STALLED ); } // Now see what the player is is trying to do // Turning clockwise ? if ( padd & PADLright ) { fwActorSetAngle ( PlaneActor[CurrentPlayer], fwActorGetAngle ( PlaneActor[CurrentPlayer] ) + PlaneRotation ); } // Turning anticlockwise ? if ( padd & PADLleft ) { fwActorSetAngle ( PlaneActor[CurrentPlayer], fwActorGetAngle ( PlaneActor[CurrentPlayer] ) - PlaneRotation ); } // Has the player decided to fire a shot ? // Here we want to trap whether the button has just been pressed. // The player must release and press the button again in order to fire the next shot. if ( fwPadGetPressed ( CurrentPlayer ) & PADRdown ) { // See if we have a spare shot available for ( CurrentShot = 0; CurrentShot < MaxShots; CurrentShot++ ) { if ( fwActorGetOnStage ( ShotActor [CurrentPlayer][CurrentShot ] ) == OFF_STAGE ) { // We have a spare shot.. so lets fire it fireShot ( CurrentPlayer, CurrentShot ); break; } } } } else { // We've been hit so initialize all the smoke actors now initPlaneSmoke ( CurrentPlayer ); } break; case PLAYER_STALLED: // if we have hit something then its all over // show a pretty explosion and put the plane back in its hanger if ( CheckPlaneCollisions ( CurrentPlayer ) == 0 ) { FreeFallPlane ( CurrentPlayer ); // Now see what the player is is trying to do // Turning clockwise ? if ( padd & PADLright ) { fwActorSetAngle ( PlaneActor[CurrentPlayer], fwActorGetAngle ( PlaneActor[CurrentPlayer] ) + PlaneRotation ); } // Turning anticlockwise ? if ( padd & PADLleft ) { fwActorSetAngle ( PlaneActor[CurrentPlayer], fwActorGetAngle ( PlaneActor[CurrentPlayer] ) - PlaneRotation ); } // If starting engine then allow it if player is pointing down // if ( padd & PADRup ) // { if ( fwActorGetAngle( PlaneActor[CurrentPlayer] ) > 110 && fwActorGetAngle( PlaneActor[CurrentPlayer] ) < 250 ) { SetPlayerStage ( CurrentPlayer, PLAYER_FLYING ); } // } } else { SetPlayerStage ( CurrentPlayer, PLAYER_FALLING ); } break; case PLAYER_FALLING: // if we have hit something then its all over // show a pretty explosion and put the plane back in its hanger if ( CheckPlaneCollisions ( CurrentPlayer ) == 0 ) { FreeFallPlane ( CurrentPlayer ); if ( fwActorGetAngle ( PlaneActor[CurrentPlayer] ) < 180 ) { fwActorSetAngle ( PlaneActor[CurrentPlayer], fwActorGetAngle ( PlaneActor[CurrentPlayer] ) + PlaneRotation ); } else { fwActorSetAngle ( PlaneActor[CurrentPlayer], fwActorGetAngle ( PlaneActor[CurrentPlayer] ) - PlaneRotation ); } makePlaneSmoke ( CurrentPlayer ); } else { // Kick off an AAFire explosion wherever the collision took place fwActorPos ( AAFireActor [TotalAAFire-1-CurrentPlayer], fwAnimateGetValue ( XPlaneAnim[CurrentPlayer] ), fwAnimateGetValue ( YPlaneAnim[CurrentPlayer] ) ); // Set the lifespan fwActorSetLifeSpan ( AAFireActor[TotalAAFire-1-CurrentPlayer], 60 ); // Start the animation fwAnimateStart ( CostumeAAFireAnim[TotalAAFire-1-CurrentPlayer] ); // Mark the AAFire as being on stage fwActorSetOnStage ( AAFireActor[TotalAAFire-1-CurrentPlayer], ON_STAGE ); SetPlayerStage ( CurrentPlayer, PLAYER_LANDED ); // Incremement the other players kill count if ( CurrentPlayer == 0 ) PlayerKills[1]++; else PlayerKills[0]++; ShowKills (); } break; } } // At random intervals // Kick off any Anti Aircraft fire which are currently off stage if ( rand() < 2000 ) { for ( CurrentAAFire = 0; CurrentAAFire < ( TotalAAFire -2 ); CurrentAAFire++ ) { if ( fwActorGetOnStage ( AAFireActor[CurrentAAFire] ) == OFF_STAGE ) { fireAAFire ( CurrentAAFire ); // Stop now.. no point in firing off more than 1 at a time. break; } } } FntPrint ("Player 1 Speed = %d\n", PlaneAccel[0] ); FntPrint ("Player 2 Speed = %d\n", PlaneAccel[1] ); FntFlush ( -1 ); fwDirectRefresh (); } // Just to ram the point home Display the Eclipse Logo again ShowLogo (); } void SetPlayerStage ( int CurrentPlayer, int NewStage ) { switch ( NewStage ) { case PLAYER_LANDED: initPlayer ( CurrentPlayer ); // Player does not collide with anything fwActorCollisionLayers ( PlaneActor[CurrentPlayer], 0 ); break; case PLAYER_TAKE_OFF: // Player can collide with the other player and his/her shots if ( CurrentPlayer == 0 ) fwActorCollisionLayers ( PlaneActor[0], STAGE_LAYER_2 | STAGE_LAYER_7 ); else fwActorCollisionLayers ( PlaneActor[1], STAGE_LAYER_1 | STAGE_LAYER_6 ); break; case PLAYER_FLYING: // Player can collide with the other player and his/her shots + AA Fire + Ground + Wall + Hanger if ( CurrentPlayer == 0 ) fwActorCollisionLayers ( PlaneActor[0], STAGE_LAYER_2 | STAGE_LAYER_3 | STAGE_LAYER_4 | STAGE_LAYER_5 | STAGE_LAYER_7 ); else fwActorCollisionLayers ( PlaneActor[1], STAGE_LAYER_1 | STAGE_LAYER_3 | STAGE_LAYER_4 | STAGE_LAYER_5 | STAGE_LAYER_6 ); break; case PLAYER_FALLING: // Player 0 can collide with ground, wall and hangers fwActorCollisionLayers ( PlaneActor[CurrentPlayer], STAGE_LAYER_4 | STAGE_LAYER_5 ); break; } PlayerStage [CurrentPlayer] = NewStage; } int CheckPlaneCollisions ( int CurrentPlayer ) { int CollidedActor; int CurrentShot; int ReturnValue; ReturnValue = 0; CollidedActor = fwActorFirstCollision ( PlaneActor[CurrentPlayer] ); while ( CollidedActor != -1 ) { ReturnValue = 1; // If the collision was with a bullet then the bullet is dead for ( CurrentShot = 0; CurrentShot < MaxShots; CurrentShot++ ) { if ( ShotActor[0][CurrentShot] == CollidedActor || ShotActor[1][CurrentShot] == CollidedActor ) { fwActorSetOnStage( CollidedActor, OFF_STAGE ); break; } } CollidedActor = fwActorNextCollision ( PlaneActor[CurrentPlayer], CollidedActor ); // The player shall die hahahahahaha SetPlayerStage ( CurrentPlayer, PLAYER_FALLING ); // initPlayer ( CurrentPlayer ); } return ( ReturnValue ); } void CheckShotCollisions ( int CurrentPlayer ) { int CollidedActor; int CurrentShot; int TargetShot; // Now see if our shots have hit anything ( other than the other player ) for ( CurrentShot = 0; CurrentShot < MaxShots; CurrentShot++ ) { CollidedActor = fwActorFirstCollision ( ShotActor[CurrentPlayer][CurrentShot] ); if ( CollidedActor != -1 ) { // We have hit something therefore we must die fwActorSetOnStage ( ShotActor[CurrentPlayer][CurrentShot], OFF_STAGE ); // If we collided with another shot then kill that too for ( TargetShot = 0; TargetShot < MaxShots; TargetShot++ ) { if ( CollidedActor == ShotActor[0][TargetShot] ) { fwActorSetOnStage ( ShotActor[0][TargetShot], OFF_STAGE ); } if ( CollidedActor == ShotActor[1][TargetShot] ) { fwActorSetOnStage ( ShotActor[1][TargetShot], OFF_STAGE ); } } } } } void fireShot ( int CurrentPlayer, int CurrentShot ) { // First set the position of the shot to match the plane position fwAnimateSetValue ( XShotAnim[CurrentPlayer][CurrentShot], fwAnimateGetValue ( XPlaneAnim[CurrentPlayer] ) ); fwAnimateSetValue ( YShotAnim[CurrentPlayer][CurrentShot], fwAnimateGetValue ( YPlaneAnim[CurrentPlayer] ) ); // Set the x and y direction of the shot based on the direction the plane is pointing fwActorSetVelocity ( ShotActor[CurrentPlayer][CurrentShot], fwActorGetAngle( PlaneActor[CurrentPlayer] ), ShotSpeed ); // set the lifespan of the shot fwActorSetLifeSpan ( ShotActor[CurrentPlayer][CurrentShot], ShotLife ); // Mark the shot as being on stage fwActorSetOnStage ( ShotActor[CurrentPlayer][CurrentShot], ON_STAGE ); } void makePlaneSmoke ( int CurrentPlayer ) { int CurrentSmoke; int SmokeXPos; int SmokeYPos; // See if we have a spare shot available for ( CurrentSmoke = 0; CurrentSmoke < 10; CurrentSmoke++ ) { if ( fwActorGetOnStage ( SmokeActor [CurrentPlayer][CurrentSmoke ] ) == OFF_STAGE ) { SmokeXPos = fwAnimateGetValue ( XPlaneAnim[CurrentPlayer] ); SmokeYPos = fwAnimateGetValue ( YPlaneAnim[CurrentPlayer] ); fwActorPos ( SmokeActor [CurrentPlayer][CurrentSmoke], SmokeXPos, SmokeYPos ); // Set the lifespan fwActorSetLifeSpan ( SmokeActor [CurrentPlayer][CurrentSmoke], 80 ); fwActorSetOnStage ( SmokeActor [CurrentPlayer][CurrentSmoke], ON_STAGE ); // Start the animation fwAnimateStart ( ScaleSmokeAnim[CurrentPlayer][CurrentSmoke] ); // The smoke is transparent // fwActorSetTransparency ( SmokeActor[CurrentPlayer][CurrentSmoke], ACTOR_TRANSPARENCY_ON + ACTOR_TRANSPARENCY_ADD_QUARTER ); break; } } } void fireAAFire ( int CurrentAAFire ) { // Place the AAFire at the top of the display // And in a random x position fwActorPos ( AAFireActor [CurrentAAFire], ( rand() * fwDirectScreenWidth() >> 15) << STAGE_SHIFT, fwActorGetPixelHeight ( AAFireActor [CurrentAAFire] ) << (STAGE_SHIFT-1) ); // Set the lifespan fwActorSetLifeSpan ( AAFireActor[CurrentAAFire], 60 ); // Start the animation fwAnimateStart ( CostumeAAFireAnim[CurrentAAFire] ); // Mark the AAFire as being on stage fwActorSetOnStage ( AAFireActor[CurrentAAFire], ON_STAGE ); // To give a bit of variety randomly rotate the actor fwActorSetAngle ( AAFireActor[CurrentAAFire], ( rand () * 360) >> 15 ); } void ShowKills ( void ) { int xpos; int ypos; // Select the actor costume based on the score fwActorSetScale ( ScoreActor[0], 4096 << 2 ); fwActorSetScale ( ScoreActor[1], 4096 << 2 ); // Place the actor on the screen ypos = ( fwDirectScreenHeight() - fwActorGetPixelWidth ( ScoreActor[0] ) >> 1 ) << STAGE_SHIFT; xpos = ( fwDirectScreenWidth() - fwActorGetPixelHeight ( ScoreActor[0] ) >> 1 ) << STAGE_SHIFT; fwActorPos ( ScoreActor[0], xpos, ypos ); fwActorChangeCostume ( ScoreActor[0], ScoreCostume+PlayerKills[0] ); xpos = ( fwDirectScreenWidth() + fwActorGetPixelHeight ( ScoreActor[1] ) >> 1 ) << STAGE_SHIFT; fwActorPos ( ScoreActor[1], xpos, ypos ); fwActorChangeCostume ( ScoreActor[1], ScoreCostume+PlayerKills[1] ); // Set the lifespans fwActorSetLifeSpan ( ScoreActor[0], 60 ); fwActorSetLifeSpan ( ScoreActor[1], 60 ); // and display // Mark the AAFire as being on stage fwActorSetOnStage ( ScoreActor[0], ON_STAGE ); fwActorSetOnStage ( ScoreActor[1], ON_STAGE ); } void ShowLogo ( void ) { int ELogoActor; int xpos; int ypos; int pause; int brightness; fwActorReset (); fwAnimateReset (); ELogoCostume = fwCostumeAdd ( TEXTURE_ELOGO, 1, 1 ); ELogoActor = fwActorAdd ( ELogoCostume ); ypos = ( fwDirectScreenHeight() - fwActorGetPixelWidth ( ELogoActor ) >> 1 ) << STAGE_SHIFT; xpos = ( fwDirectScreenWidth() - fwActorGetPixelHeight ( ELogoActor ) >> 1 ) << STAGE_SHIFT; ypos = ( fwDirectScreenHeight() >> 1 ) << STAGE_SHIFT; xpos = ( fwDirectScreenWidth() >> 1 ) << STAGE_SHIFT; fwActorPos ( ELogoActor, xpos, ypos ); fwActorSetAngle (ELogoActor, 90 ); fwActorSetScale ( ELogoActor, 4096 << 1 ); fwActorSetOnStage ( ELogoActor, ON_STAGE ); brightness = 255; fwDirectSetBackGround ( brightness, brightness, brightness ); fwActorSetRGB ( ELogoActor, brightness>>1, brightness>>1, brightness>>1 ); for ( pause = 0; pause < 255; pause++ ) { fwDirectRefresh (); } for ( brightness = 255; brightness > 0; brightness-- ) { fwDirectSetBackGround ( brightness, brightness, brightness ); fwActorSetRGB ( ELogoActor, brightness>>1, brightness>>1, brightness>>1 ); fwDirectRefresh (); } }