1. // Beginning Game Programming, Second Edition
  2. // DynamicScroll program
  3.  
  4. // for File I/O
  5. //#include <iostream>
  6. //#include <fstream>
  7.  
  8. #include "game.h"
  9.  
  10. /* THESE WILL BE THE IN-GAME OPTIONS */
  11. // GAME DIFFICULTY - "limiter" = max # of badies to spawn on ya at once
  12. int DIFF_LEVEL = 5; // AVG
  13. // SCREEN_WIDTH
  14. // SCREEN_HEIGHT    < 2000 :D
  15. // FULLSCREEN   0/1
  16. // MAX   10
  17. // AVG    6
  18. // NOVICE 3
  19. // EASY    2
  20.  
  21. // counters for score
  22. int MAX_SYTEM =0;
  23. int MAX_PLANET =0;
  24.  
  25.  
  26. int ScrollX=0, ScrollY=0;           //current scroll position
  27. int SpeedX, SpeedY;                 //scroll speed
  28. LPDIRECT3DSURFACE9 scrollbuffer;    //scroll buffer
  29. LPDIRECT3DSURFACE9 space_tiles,surface_tiles[NUM_MAPS_PLANET],system_tiles[NUM_MAPS_SYSTEM];            //source image(s) containing tiles
  30. bool gamestart = true;
  31.  
  32. /* music class */
  33. CWMp3* mp3 = CreateCWMp3();
  34.  
  35.  
  36. long start;                         //timing variable
  37.  
  38. // keep track of which state the game is in
  39. GAME_STATE gameView = SPACE;
  40.  
  41. // TILE MAP Data
  42. int MAPDATA[MAPWIDTH][MAPHEIGHT];
  43. int SYSTEM_MAPDATA[MAPWIDTH][MAPHEIGHT];
  44.  
  45. // track players progress -- and mobs, etc --
  46. bool clearedArea[NUM_MAPS_SYSTEM][NUM_MAPS_PLANET];
  47.  
  48. struct debrisType
  49. {
  50.     bool space[DEBRIS_AMT_SPACE];
  51.     bool system[DEBRIS_AMT_SYSTEM];
  52.     bool surface[DEBRIS_AMT_PLANET];
  53. } hitDebris;
  54.  
  55. struct planetType
  56. {
  57.     bool space[IMMOBILE_AMT_SPACE];
  58.     bool system[IMMOBILE_AMT_SYSTEM];
  59.     bool surface[IMMOBILE_AMT_PLANET];
  60. } hitPlanet[NUM_MAPS_PLANET];
  61.  
  62. float COLL_RADIUS = 0.40; // 80% of mass
  63.  
  64. // FLAG if player is at a dock-able object (planet,sun,etc)
  65. // will be -1 if not
  66. int DOCKED_AT = -1;
  67.  
  68. struct dType
  69. {
  70.     int planet;
  71.     int system;
  72.     int space;
  73. };
  74. dType docked = {-1,-1};
  75. dType CURR_MAP = {0,0,0};
  76.  
  77. // SPRITE handler
  78. LPD3DXSPRITE sprite_handler;
  79. float scalex=1.0f,scaley=1.0f; // used for sprite scaling
  80. float ScaleX=1.0f,ScaleY=1.0f; // used for sprite scaling
  81.  
  82. // static objects for the guns/ammo
  83. CGuns       *Guns[MAX_GUNS];
  84. CProjectile *Ammo[MAX_AMMO];
  85. int Alt_Weapon = 3; // missiles, 4 is torpedo
  86.  
  87. // FOR AI guns and such
  88. CGuns       *Guns_AI[MAX_GUNS_AI];
  89. CProjectile *Ammo_AI[MAX_GUNS_AI];
  90.  
  91. // max # of projectiles to track
  92. int cntBullets=0; // projectiles in motion
  93. int bulletsDrawn=0;
  94. int rCode=0;
  95. int enemyBullets=0;
  96. int bulletsHit=0;
  97.  
  98. // enemy
  99. const int NUM_DRONE_SHIPS=3;
  100. const int NUM_ENEMIES=10;
  101. CShip *enemy[NUM_ENEMIES];
  102. CShip *boss; // only one at a time
  103. CSprite *beeks;
  104. int deaths=0; // number of times boss has died , starts with frame #0 (grey)
  105. const int lives = 8; // 8 colors/frames
  106.  
  107. // Players ship
  108. CShip   *player;
  109. CSprite *shield;
  110.  
  111. // keep track of enter/exit locations
  112. // pt is xy location, number is object collides with last, dir is facing
  113. struct LAST_LOC
  114. {
  115.     POINT pt;       // xy location
  116.     int number;     // object # collided with
  117.     DIRS direction; // direction you were facing
  118.     POINT scroll;   // scrollx and scrolly at entrance xy
  119. };
  120.  
  121. struct LAST_COLL
  122. {
  123.     int space;  // numbers reflect # of last object collided with in that view
  124.     int system;
  125.     int surface;
  126. };
  127. LAST_COLL lastColl = {0,0,0};
  128. LAST_COLL currColl = {0,0,0};
  129. LAST_COLL lastPlanetColl = {0,0,0};
  130. LAST_COLL currPlanetColl = {0,0,0};
  131.  
  132. // used to save previous locations and entrance locations
  133. LAST_LOC enterPLANET,enterSYSTEM,enterSPACE;
  134.  
  135. struct lastType
  136. {
  137.     LAST_LOC space;
  138.     LAST_LOC system;
  139.     LAST_LOC planet;
  140. } prev;
  141.  
  142. // health bars
  143. LPDIRECT3DSURFACE9 color_bars;
  144. LPDIRECT3DSURFACE9 sun;
  145. LPD3DXFONT dxfont;
  146.  
  147. CSprite *yellowBmp,*redBmp;
  148.  
  149. // random space debris
  150. // Debris class to handle the moving debris
  151. CDebris *debris_space[DEBRIS_AMT_SPACE];
  152. CDebris *debris_system[DEBRIS_AMT_SYSTEM];
  153. CDebris *debris_planet[DEBRIS_AMT_PLANET];
  154.  
  155. CPlanet *immobile_space[IMMOBILE_AMT_SPACE];
  156. CPlanet *immobile_system[NUM_MAPS_SYSTEM][IMMOBILE_AMT_SYSTEM];
  157. CPlanet *immobile_planet[NUM_MAPS_PLANET][IMMOBILE_AMT_PLANET];
  158.  
  159. // collision stuff
  160. double vPx;
  161. double vPy;
  162. double vJx;
  163. double vJy;
  164. //  ---
  165.  
  166. const int MAX_EXPLOSIONS = 30;
  167. CSprite *explosion[MAX_EXPLOSIONS];
  168. bool activeEXP[MAX_EXPLOSIONS];
  169.  
  170. const int RIGHT = 1;
  171. const int LEFT  = 0;
  172.  
  173. // timer to delay key presses
  174. bool KEY_PRESSED=false;
  175.  
  176. //-------------------------------------------------------//
  177. //-----------------   GAME INIT -------------------------//
  178. //initializes the game
  179. int Game_Init(HWND hwnd)
  180. {
  181.     HRESULT result;
  182.  
  183.     Init_DirectInput(hwnd);
  184.     Init_Keyboard(hwnd);
  185.  
  186.  
  187.     //create sprite handler object
  188.     result = D3DXCreateSprite(d3ddev, &sprite_handler);
  189.     if (result != D3D_OK)
  190.      return 0;
  191.  
  192.     // set all explosions to false
  193.     for (int i=0; i < MAX_EXPLOSIONS; i++)
  194.         activeEXP[i] = false;
  195.  
  196.     // set all map data to (1) ... SPACE/PLANET (for now)
  197.     for (int row=0; row < MAPHEIGHT;row++)
  198.         for (int column=0; column < MAPWIDTH; column++)
  199.             MAPDATA[column][row] = 1; // all will use sprite #1
  200.  
  201.    
  202.     // system map data
  203.     int cnt = 0;
  204.     for (int row=0; row < MAPHEIGHT;row++)
  205.         for (int column=0; column < MAPWIDTH; column++)
  206.             SYSTEM_MAPDATA[column][row] = cnt++; // so it draws the bmp using tiles
  207.  
  208.  
  209.     // load the font
  210.     D3DXCreateFont( d3ddev, 14, 0, FW_NORMAL, 1, false, DEFAULT_CHARSET,
  211.                     OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
  212.                     "Arial Black", &dxfont);
  213.  
  214.     // setup the guns and ammo for the ships
  215.     Init_Guns();
  216.  
  217.     //load the tile images
  218.    
  219.     space_tiles = LoadSurface(TEXT("./Media/Images/space_00.png"), D3DCOLOR_XRGB(0,0,0));
  220.     assert(space_tiles);
  221.  
  222.     //load the tile images 
  223.     for (int p=0; p < NUM_MAPS_PLANET; p++)
  224.     {
  225.         char myText[100];
  226.         sprintf(myText,"./Media/Images/planet_0%d.png",p);
  227.  
  228.         surface_tiles[p] = LoadSurface((LPCSTR) myText, D3DCOLOR_XRGB(0,0,0));
  229.         assert(surface_tiles[p]);
  230.     }
  231.  
  232.     //load the tile images
  233.     for (int s=0; s < NUM_MAPS_SYSTEM; s++)
  234.     {
  235.         char myText[100];
  236.         sprintf(myText,"./Media/Images/system_0%d.png",s);
  237.  
  238.         system_tiles[s] = LoadSurface((LPCSTR) myText, D3DCOLOR_XRGB(0,0,0));
  239.         assert(system_tiles[s]);
  240.     }
  241.  
  242.     //create the scroll buffer surface in memory, slightly bigger
  243.     //than the screen
  244.     result = d3ddev->CreateOffscreenPlainSurface(
  245.         SCROLLBUFFERWIDTH, SCROLLBUFFERHEIGHT,
  246.         D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT,
  247.         &scrollbuffer,
  248.         NULL);
  249.  
  250.     // test bitmap
  251.     // will draw under objects that are collided with ... as a test
  252.     yellowBmp = new CSprite(0,0,120,100,TEXT("./Media/Images/test1.bmp")); 
  253.     assert(yellowBmp);
  254.  
  255.     redBmp = new CSprite(0,0,120,100,TEXT("./Media/Images/test2.png"));
  256.     assert(redBmp);
  257.  
  258.     //player
  259.     // now using GAME WORLD coordinates
  260.     // starting ship  Max Speed 8, Solar Energy 20, Recharge Delay 50, BLASTERS, shields, armor, hull (hit points)
  261.     player = new CShip(16,16,128,128,TEXT("./Media/Images/ship.png"),0,8,20,25,Guns[0],0,3,2,1);
  262.     player->setupAnim(4,SOUTH,4); // sprites per anim, initially heading, sprites per row on sheet 
  263.     player->setSTATE(ACTIVE);  
  264.     player->setBorder(0,0,GAMEWORLDWIDTH - 64,GAMEWORLDHEIGHT - 64); // set border to game window
  265.     assert(player);
  266.  
  267.     shield = new CSprite(50,50,128,128,TEXT("./Media/Images/shield.png"));
  268.     shield->setupAnim(4,EAST,4);
  269.     shield->setSTATE(ACTIVE);
  270.     assert(shield);
  271.  
  272.     // spawn/create the Enemy SHIPs & BOSS
  273.     createDrones();
  274.  
  275.     // randomly initializes the debris
  276.     createDebris();
  277.  
  278.     // load the static objects (planets)
  279.     loadMaps();
  280.  
  281.  
  282.  
  283.     // SCORE
  284.     // SYSTEMS CLEARED
  285.     int cntPl=0,cntSys=0, temp=0;
  286.     for (int s=0; s < NUM_MAPS_SYSTEM; s++)
  287.     {
  288.         temp=cntPl;
  289.         for (int p=0; p < NUM_MAPS_SYSTEM; p++)
  290.             if (clearedArea[s][p] == false)
  291.                 cntPl++;
  292.  
  293.         if (temp != cntPl)
  294.         {
  295.             cntSys++;
  296.             temp = cntPl;
  297.         }
  298.     }              
  299.  
  300.     MAX_SYTEM  =cntSys;
  301.     MAX_PLANET =cntPl; // <- this is THE SCORE (max)
  302.  
  303.     // Status bars for players
  304.     color_bars = LoadSurface(TEXT("./Media/Images/bars.bmp"), D3DCOLOR_XRGB(255,0,255));
  305.     assert(color_bars);
  306.  
  307.     // setup the enter/exit objects
  308.     // when entering a planet view, start at the bottom of map - looking north
  309.     enterPLANET.pt.x = 1;//(GAMEWORLDWIDTH-(player->getWidth())/2);
  310.     enterPLANET.pt.y = 1;//GAMEWORLDHEIGHT - player->getHeight();
  311.     enterPLANET.direction = SE;//NORTH;
  312.     enterPLANET.scroll.x = 0;//getScrollX(enterPLANET.pt.x);
  313.     enterPLANET.scroll.y = 0;//getScrollY(enterPLANET.pt.y);
  314.  
  315.     enterSYSTEM.pt.x = 1;//(GAMEWORLDWIDTH-(player->getWidth())/2);
  316.     enterSYSTEM.pt.y = 1;//GAMEWORLDHEIGHT - player->getHeight();
  317.     enterSYSTEM.direction = SE;//NORTH;
  318.     enterSYSTEM.scroll.x = 0;//getScrollX(enterSYSTEM.pt.x);
  319.     enterSYSTEM.scroll.y = 0;//getScrollY(enterSYSTEM.pt.y);
  320.  
  321.     enterSPACE.pt.x = 150;//(GAMEWORLDWIDTH-(player->getWidth())/2);
  322.     enterSPACE.pt.y = 150;//GAMEWORLDHEIGHT - player->getHeight();
  323.     enterSPACE.direction = SE;//NORTH;
  324.     enterSPACE.scroll.x = 0;//getScrollX(enterSPACE.pt.x);
  325.     enterSPACE.scroll.y = 0;//getScrollY(enterSPACE.pt.y);
  326.  
  327.     start = GetTickCount();
  328.  
  329.     mp3->OpenFile(".\\Media\\Sound\\Music\\Plunder_the_Galaxy.mp3",800, 0, 0);
  330.     mp3->Play();
  331.  
  332.     return 1;
  333. }
  334.  
  335.  
  336. // -------------------------------------------------- //
  337. // ------------ GAME RUN ---------------------------- //
  338.  
  339. //the main game loop
  340. void Game_Run(HWND hwnd)
  341. {
  342.     //make sure the Direct3D device is valid
  343.     if (d3ddev == NULL)
  344.         return;
  345.  
  346.     //poll DirectInput devices
  347.     Poll_Keyboard();
  348.  
  349.     //check for escape key (to exit program)
  350.     if (Key_Down(DIK_ESCAPE))
  351.         PostMessage(hwnd, WM_DESTROY, 0, 0);
  352.  
  353.     if (gamestart)
  354.     {
  355.         mp3->Stop();
  356.         gamestart = false;
  357.     }
  358.  
  359.     int temp=0;
  360.  
  361.     //keep the game running at a steady frame rate
  362.     if (GetTickCount() - start >= 30)
  363.     {
  364.         //reset timing
  365.         start = GetTickCount();
  366.  
  367.         // check for player pressing a key
  368.         Check_Keys();
  369.  
  370.         // set player ship scale based on view level
  371.         switch(gameView)
  372.         {
  373.         case SPACE:
  374.             {
  375.                 scalex=0.5f;
  376.                 scaley=0.5f;
  377.             };
  378.             break;
  379.         case SYSTEM:
  380.             {
  381.                 scalex=0.75f;
  382.                 scaley=0.75f;
  383.             };
  384.             break;
  385.         case PLANET:
  386.             {
  387.                 scalex=1.0f;
  388.                 scaley=1.0f;
  389.             };
  390.             break;
  391.         }
  392.  
  393.     // RECOVER
  394.         // regen solar energy & shields & guns
  395.         player->recharge();
  396.  
  397.         // recharge power on enemy ships, so they can continue shooting at you
  398.         for (int i=0; i < NUM_ENEMIES; i++)
  399.             if ((enemy[i]->getSTATE() != DEAD) && (enemy[i]->getSTATE() != INACTIVE))
  400.                 enemy[i]->recharge();
  401.  
  402.         if ( (boss->getSTATE() != DEAD) && (boss->getSTATE() != INACTIVE) )
  403.             boss->recharge();
  404.  
  405.     // MOVE
  406.        //move the sprite
  407.         player->doMove();
  408.  
  409.         // Bullet movement
  410.         moveBullets();
  411.  
  412.         // process Enemy Actions (FSM)
  413.         // and MOVE enemy ships
  414.         EnemyAI();
  415.         BossAI();
  416.  
  417.         // move Debris in current Game View
  418.         moveDebris();
  419.  
  420.     // CHECK MOVES
  421.         // Player - check if left screen or not
  422.         // make sure ship doesnt leave game coordinates
  423.         if (player->checkBounds(0,0,GAMEWORLDWIDTH,GAMEWORLDHEIGHT))
  424.             player->setSpeed(0);// border collision occured ... now what? player ship is stopped
  425.        
  426.         //update the scrolling view
  427.         UpdateScrollPosition();
  428.  
  429.     //COLLISIONS
  430.         // AI bullets vs Player
  431.         bullet_AI_Collision(player);
  432.  
  433.         // player bullets vs AI
  434.         for (int i=0;i < NUM_ENEMIES; i++)
  435.             if ((enemy[i]->getSTATE() != DEAD) && (enemy[i]->getSTATE() != INACTIVE))
  436.                 bulletCollision(enemy[i]);
  437.  
  438.         // player bullets vs Boss
  439.         if ( (boss->getSTATE() != DEAD) && (boss->getSTATE() != INACTIVE) )
  440.             bulletCollision(boss);
  441.  
  442.         // check for player vs. debris collision ... and determine the results
  443.         checkDebris();
  444.  
  445.         // if player collides with a planet - enter planet mode
  446.         temp = planetCollision(player); // object # collided with (what about 0?!)
  447.  
  448.         // track current and last object collided with     
  449.         if (gameView == SPACE) 
  450.         {
  451.             lastPlanetColl.space   = currPlanetColl.space; // resets to (0) if no collision
  452.             currPlanetColl.space   = temp; // resets to (0) if no collision
  453.         }
  454.         if (gameView == SYSTEM)
  455.         {
  456.             lastPlanetColl.system = currPlanetColl.system;
  457.             currPlanetColl.system  = temp;
  458.         }
  459.         if (gameView == PLANET)
  460.         {
  461.             lastPlanetColl.surface = currPlanetColl.surface;
  462.             currPlanetColl.surface = temp;
  463.         }      
  464.  
  465.         // Will hold the current object player is docked at
  466.         // DOCKED_AT = temp;
  467.         DOCKED_AT = -1;
  468.  
  469.         // OK- if you are docked at a planet -- you can hit the + key to "zoom in"
  470.         // check to make sure its a valid DOCK target
  471.         switch(gameView)
  472.         {
  473.             case SPACE:
  474.                 {
  475.                     // DOCKED_AT only holds the [i] last collision w/ object
  476.                     // lets get the frame # from the given sprite                  
  477.                     // find the resulting frame # which represents which type of system it will be                 
  478.  
  479.                     // make sure its a valid #
  480.                     if (( temp < IMMOBILE_AMT_SPACE) && (temp >= 0))
  481.                     {
  482.                         // this should tell us the map # associated, (-1) if none
  483.                         if (immobile_space[temp]->getMap() > -1)
  484.                             DOCKED_AT = immobile_space[temp]->getMap();                    
  485.                     }
  486.                 };
  487.                 break;
  488.             case SYSTEM:
  489.                 {
  490.                     // make sure its a valid #
  491.                     if (( temp < IMMOBILE_AMT_SYSTEM) && (temp >= 0))
  492.                     {
  493.                         if (immobile_system[docked.system][temp]->getMap() > -1)
  494.                             DOCKED_AT = immobile_system[docked.system][temp]->getMap();
  495.                     }
  496.                 };
  497.                 break;
  498.             case PLANET:
  499.                 {
  500.                 };
  501.                 break;
  502.         };
  503.        
  504.  
  505.         // check for debris leaving the screen
  506.         respawnDebris();
  507.  
  508.     // ANIMATE
  509.         // change shield color
  510.         shield->setFrame(shield->getLastFrame() - player->getShields());
  511.  
  512.         //animate player sprite
  513. //      player->nextFrame(); // all ships animate on doMove() - this includes enemies and player
  514.  
  515.         // animate explosions
  516.         animExp();
  517.  
  518.         // bullets?
  519.        
  520.  
  521.         //start rendering
  522.         if (d3ddev->BeginScene())
  523.         {          
  524.  
  525.             //erase the entire background
  526.             d3ddev->ColorFill(backbuffer, NULL, D3DCOLOR_XRGB(0,0,0));
  527.  
  528.             //start sprite handler
  529.             sprite_handler->Begin(D3DXSPRITE_ALPHABLEND);
  530.  
  531.             //draw tiles onto the scroll buffer
  532.             switch (gameView)
  533.             {
  534.                 case SPACE: DrawBG(space_tiles); break;
  535.                 case SYSTEM:
  536.                     {
  537.                         int c = docked.system;
  538.                         if ((c > NUM_MAPS_SYSTEM) || (c < 0))
  539.                             c = 0;
  540.                         DrawBG(system_tiles[c]);
  541.                     }; break;
  542.                 case PLANET:
  543.                     {
  544.                         int c = docked.planet;
  545.                         if ((c > NUM_MAPS_PLANET) || (c < 0))
  546.                             c = 0;
  547.                         DrawBG(surface_tiles[c]);
  548.                     }; break;
  549.             }
  550.  
  551.             // SCORE
  552.             // SYSTEMS CLEARED
  553.             int cntPl=0,cntSys=0, temp=0;
  554.             for (int s=0; s < NUM_MAPS_SYSTEM; s++)
  555.             {
  556.                 temp=cntPl;
  557.                 for (int p=0; p < NUM_MAPS_SYSTEM; p++)
  558.                     if (clearedArea[s][p] == false)
  559.                         cntPl++;
  560.  
  561.                 if (temp != cntPl)
  562.                 {
  563.                     cntSys++;
  564.                     temp = cntPl;
  565.                 }
  566.             }              
  567.  
  568.             // SCORE BOARD
  569.             drawText("Shots",  50, 0);
  570.             drawText("Enemy"  ,150, 0);
  571.             drawText("Hits"   ,250, 0);        
  572.             drawNumbers(cntBullets,   50,30);
  573.             drawNumbers(enemyBullets,150,30);
  574.             drawNumbers(bulletsHit,  250,30);
  575.  
  576.             drawText("Unsafe  ", 650,15);
  577.             drawText("Max  ",    800,40);
  578.             drawText("Systems ", 750,0);             
  579.             drawText("Planets ", 850,0);           
  580.             drawNumbers(cntSys,750,28);        
  581.             drawNumbers(cntPl, 850,28);
  582.             drawNumbers(MAX_SYTEM, 750,50);                      
  583.             drawNumbers(MAX_PLANET,850,50);
  584.  
  585. //          drawText("X axis", 0,700);           
  586. //          drawText("Y axis",50,700);         
  587. //          drawNumbers(player->getX(),0,740);         
  588. //          drawNumbers(player->getY(),50,740);        
  589.  
  590. //          drawText("Boss Stage",150,700);        
  591. //          drawNumbers(deaths,150,740);           
  592. //          drawNumbers(boss->getFrame(),200,740);
  593.  
  594.             // draw the STATIC objects (not moving; planets and such)
  595.             drawPlanets();
  596.  
  597.             //draw the space debris sprites (clouds, asteroids, etc)
  598.             drawDebris();
  599.  
  600.             // this should draw all the player's bullets that are active
  601.             drawBullets();
  602.  
  603.             // draw the health bars for enemy / player ships
  604.             drawBars();
  605.  
  606.             //draw shield under the player sprite          
  607.             DrawSprite( player->getX()-ScrollX,player->getY()-ScrollY,
  608.                         shield->getWidth(),shield->getHeight(),
  609.                         scalex, scaley, player->getAngle(),
  610.                         D3DCOLOR_XRGB(255,255,255),
  611.                         shield->getImage(),
  612.                         &shield->getRect(),
  613.                         d3ddev, true);
  614.  
  615.             //draw the player sprite
  616.             DrawSprite( player->getX()-ScrollX,player->getY()-ScrollY,
  617.                         player->getWidth(),player->getHeight(),
  618.                         scalex, scaley, player->getAngle(),
  619.                         D3DCOLOR_XRGB(255,255,255),
  620.                         player->getImage(),
  621.                         &player->getRect(),
  622.                         d3ddev, true);
  623.  
  624.            
  625.             for (int i=0;i < NUM_ENEMIES; i++)
  626.                 if ((enemy[i]->getSTATE() != DEAD) && (enemy[i]->getSTATE() != INACTIVE))
  627.                     if (enemy[i]->getHP() > 0)// check for ZOMBIES :P
  628.                     {
  629.                         DrawSprite( enemy[i]->getX()-ScrollX,enemy[i]->getY()-ScrollY,
  630.                                     enemy[i]->getWidth(),enemy[i]->getHeight(),
  631.                                     scalex, scaley, enemy[i]->getAngle(),
  632.                                     D3DCOLOR_XRGB(255,255,255),
  633.                                     enemy[i]->getImage(),
  634.                                     &enemy[i]->getRect(),
  635.                                     d3ddev, true);             
  636.                     }
  637.                     else
  638.                         enemy[i]->setSTATE(DEAD);  
  639.  
  640.             if ((boss->getSTATE() != DEAD) && (boss->getSTATE() != INACTIVE))
  641.                 if (boss->getHP() > 0)// check for ZOMBIES :P
  642.                 {
  643.                     DrawSprite( boss->getX()-ScrollX,boss->getY()-ScrollY,
  644.                                 boss->getWidth(),boss->getHeight(),
  645.                                 scalex, scaley, boss->getAngle(),
  646.                                 D3DCOLOR_XRGB(255,255,255),
  647.                                 boss->getImage(),
  648.                                 &boss->getRect(),
  649.                                 d3ddev, true); 
  650.  
  651.                     // Draw Beeks over-top
  652.                     DrawSprite( boss->getX()-ScrollX,boss->getY()-ScrollY,
  653.                                 beeks->getWidth(),beeks->getHeight(),
  654.                                 scalex, scaley, boss->getAngle(),
  655.                                 D3DCOLOR_XRGB(255,255,255),
  656.                                 beeks->getImage(),
  657.                                 &beeks->getRect(),
  658.                                 d3ddev, true);             
  659.                 }
  660.                 else
  661.                     boss->setSTATE(DEAD);  
  662.  
  663.             // draw the Explosions (if any)
  664.             drawExp();
  665.  
  666.  
  667. // DEBUG --
  668.             /*
  669.             //info on the enemy sprites
  670.             for (int i=0;i < NUM_ENEMIES; i++)
  671.             {
  672.  
  673.                 int x = (i*50)+60;
  674.                 int y = SCREEN_HEIGHT - 30;
  675.                 switch( enemy[i]->getSTATE() )
  676.                 {
  677.                     case FLEEING  : drawText(TEXT("Flee"),x,y); break;
  678.                     case ACTIVE   : drawText(TEXT("Actv"),x,y); break;
  679.                     case SEARCHING: drawText(TEXT("Srch"),x,y); break;
  680.                     case ATTACKING: drawText(TEXT("Attk"),x,y); break;                 
  681.                     case DEAD     : drawText(TEXT("Dead"),x,y); break;
  682.                     case DYING    : drawText(TEXT("Dyng"),x,y); break;
  683.                     case INACTIVE : drawText(TEXT("Inact"),x,y); break;
  684.                 };
  685.                 // what is the guns range
  686.                 int gunRange = Ammo[enemy[i]->getAmmo()]->getRange() * scalex;
  687.  
  688.                 y -= 25;if(i==0) drawText("Rng",0,y);       drawNumbers(gunRange,x,y);
  689.                 y -= 25;if(i==0) drawText("Pwr",0,y);       drawNumbers(enemy[i]->getSolar(),x,y);
  690.                 y -= 25;if(i==0) drawText("Dly",0,y);       drawNumbers(enemy[i]->getGunDelay(),x,y);
  691.                 y -= 25;if(i==0) drawText("Rld",0,y);       drawNumbers(enemy[i]->weapon->getReload(),x,y);
  692.                 y -= 25;if(i==0) drawText("nrg",0,y);       drawNumbers(enemy[i]->weapon->getEnergy(),x,y);
  693.                 y -= 25;if(i==0) drawText("HP",0,y);        drawNumbers(enemy[i]->getHP(),x,y);
  694.                 y -= 25;if(i==0) drawText("Max",0,y);       drawNumbers(enemy[i]->getMaxHP(),x,y);
  695.             }
  696.             */
  697. // -- DEBUG
  698.  
  699.             //stop drawing
  700.             sprite_handler->End();
  701.    
  702.             //stop rendering
  703.             d3ddev->EndScene();
  704.         }
  705.     }
  706.  
  707.     //display the back buffer on the screen
  708.     d3ddev->Present(NULL, NULL, NULL, NULL);
  709. }
  710.  
  711. // -------------------------------------- //
  712. // ---------- GAME END ------------------ //
  713. //frees memory and cleans up before the game ends
  714. void Game_End(HWND hwnd)
  715. {
  716.     Kill_Keyboard();
  717.     Kill_Mouse();
  718.     dinput->Release();
  719.  
  720.     if (sprite_handler != NULL)
  721.         sprite_handler->Release();
  722. }
  723.  
  724. // -------------------------------------- //
  725. // ------------ Functions --------------- //
  726.  
  727.  
  728. void drawText(LPCSTR outText, int screenX, int screenY)
  729. {
  730.     RECT textbox;
  731.     textbox.left   = screenX;
  732.     textbox.top    = screenY;
  733.     textbox.right  = screenX + (strlen((LPCSTR) &outText)*32);
  734.     textbox.bottom = screenY + 32; // 90x30 box ok?
  735.  
  736.     dxfont->DrawTextA(  NULL,
  737.                         (LPCSTR)outText,
  738.                         strlen((LPCSTR) outText),
  739.                         &textbox,
  740.                         DT_RIGHT,
  741.                         D3DCOLOR_ARGB(255, 120, 255, 120)
  742.                         );
  743. };
  744.  
  745. // used for debug purposes, writing numbers to screen
  746. // draw numbers to screen
  747. void drawNumbers(int number, int screenX, int screenY)
  748. {
  749.     static char outText[10];
  750.     _itoa_s(number, outText, 10);
  751.  
  752.     RECT textbox;
  753.     textbox.left   = screenX;
  754.     textbox.top    = screenY;
  755.     textbox.right  = screenX + 90;
  756.     textbox.bottom = screenY + 30; // 90x30 box ok?
  757.  
  758.     dxfont->DrawTextA(  NULL,
  759.                         (LPCSTR)&outText,
  760.                         strlen((LPCSTR) &outText),
  761.                         &textbox,
  762.                         DT_RIGHT,
  763.                         D3DCOLOR_ARGB(255, 120, 255, 120)
  764.                         );
  765. };
  766.  
  767.  
  768. // function to scale, rotate and draw a sprite - all in one!!
  769. // draws sprite in the position (x,y) with scaling factor (sx,sy),
  770. // with rotation of angle-degrees and with trasparency of "alpha" (0xFF = fully opaque).
  771. // You can also specify a subrect to draw (rc).
  772. void DrawSprite(float x, float y, int width, int height, float sx, float sy, float angle, unsigned char alpha, LPDIRECT3DTEXTURE9 sprite, RECT *rc, IDirect3DDevice9* pd3dDevice, bool FixAngle)
  773. {
  774.     D3DSURFACE_DESC desc;
  775.     sprite->GetLevelDesc(0, &desc);
  776.  
  777.     // angles are messed up now, got to add 90 before drawing
  778.     int tAngle = angle;
  779.     if (FixAngle)
  780.     {
  781.         tAngle += 90;
  782.         if (tAngle < 0)
  783.             tAngle = 360 + tAngle;
  784.         if (tAngle >= 360)
  785.             tAngle = tAngle - 360;
  786.     }
  787.  
  788.     const int halfWidth = width/2; //desc.Width >> 1;
  789.     const int halfHeight = height/2; //desc.Height >> 1;
  790.  
  791.     D3DXMATRIX rotate, trasl, scale, result;
  792.  
  793.     D3DXMatrixIdentity(&result);
  794.     D3DXMatrixTranslation(&trasl, -halfWidth, -halfHeight, 0);
  795.     D3DXMatrixMultiply(&result, &result, &trasl);
  796.     D3DXMatrixScaling(&scale, sx, sy, 1.0f);
  797.     D3DXMatrixMultiply(&result, &result, &scale);
  798.     D3DXMatrixRotationZ(&rotate, D3DXToRadian(tAngle));
  799.     D3DXMatrixMultiply(&result, &result, &rotate);
  800.     D3DXMatrixTranslation(&trasl, +halfWidth, +halfHeight, 0);
  801.     D3DXMatrixMultiply(&result, &result, &trasl);
  802.     D3DXMatrixTranslation(&trasl, x, y, 0);
  803.     D3DXMatrixMultiply(&result, &result, &trasl);
  804.  
  805.     sprite_handler->SetTransform(&result);
  806.     sprite_handler->Draw(sprite, rc, NULL, NULL, (0xFFFFFF) | (alpha << 24));
  807. }
  808.  
  809. // checks to see if player is trying to move with keys
  810. void Check_Keys()
  811. {
  812.     if (KEY_DOWN(VK_DOWN))
  813.     {
  814.         if (KEY_PRESSED)
  815.             return;
  816.         // slowing down
  817.         player->addSpeed(-2);
  818.         KEY_PRESSED=true;      
  819.     }
  820.     else if (KEY_DOWN(VK_UP))
  821.     {
  822.         if (KEY_PRESSED)
  823.             return;
  824.         // increment current speed
  825.         player->addSpeed(1);
  826.         KEY_PRESSED=true;
  827.         player->useSolar(1); // burst uses some energy
  828.     }
  829.     else if (KEY_DOWN(VK_RIGHT))   
  830.     {
  831.         if (KEY_PRESSED)
  832.             return;
  833.  
  834.         player->turn(RIGHT);
  835.  
  836.         KEY_PRESSED=true;
  837.     }  
  838.     else if (KEY_DOWN(VK_LEFT))
  839.     {
  840.         if (KEY_PRESSED)
  841.             return;
  842.  
  843.         player->turn(LEFT); // left
  844.  
  845.         KEY_PRESSED=true;
  846.     }
  847.     else if (KEY_DOWN(VK_ADD) || KEY_DOWN(VK_OEM_PLUS))
  848.     { // zoom in
  849.         if (KEY_PRESSED == true)
  850.             return;
  851.  
  852.         switch (gameView)
  853.         {
  854.         case SPACE:
  855.             { // space -> system
  856.                 if (DOCKED_AT > -1)            
  857.                 {
  858.                     // check if any enemies in this system
  859.                     // if all planets cleared, then its safe
  860.                     bool systemSafe=true;
  861.                     int pcnt=0;
  862.                     for (int p=0; p < NUM_MAPS_PLANET; p++)
  863.                         if ( clearedArea[DOCKED_AT][p] == false)
  864.                         {
  865.                             pcnt++;
  866.                             systemSafe=false;
  867.                         }
  868.                     // respawn aliens (1 per planet)
  869.                     // pcnt = planets w enemies
  870.                     // can have up to 10 planets
  871.                     // max of 10 enemies
  872.                     if (! systemSafe)
  873.                         respawnDrones(pcnt);
  874.                     else
  875.                         {
  876.                             boss->setSTATE(INACTIVE);
  877.                             deaths=0;
  878.                         }
  879.  
  880.                     // keep track of what system # you are entering
  881.                     docked.system = DOCKED_AT;
  882.                     CURR_MAP.system = DOCKED_AT;
  883.  
  884.                     // save current location
  885.                     prev.space.direction = player->getFacing();
  886.                     prev.space.pt.x = player->getX();
  887.                     prev.space.pt.y = player->getY();
  888.  
  889.                     // enter system
  890.                     gameView=SYSTEM;
  891.                    
  892.                     // set speed,location,etc ...
  893.                     SpeedX=0;
  894.                     SpeedY=0;
  895.  
  896.                     player->setSpeed(0);           
  897.                     player->setPT(enterSYSTEM.pt);
  898.                     player->setFacing(enterSYSTEM.direction);
  899.                     ScrollX = enterSYSTEM.scroll.x;
  900.                     ScrollY = enterSYSTEM.scroll.y;
  901.  
  902.                     mp3->OpenFile(".\\Media\\Sound\\teleport_activate.mp3",800, 0, 0);
  903.                     mp3->Play();
  904.                 }
  905.            
  906.             };
  907.             break;
  908.         case SYSTEM:
  909.             { // SYSTEM -> PLANET
  910.                 if (DOCKED_AT > -1)
  911.                 {
  912.                     // check if any enemies in this system
  913.                     // if all planets cleared, then its safe
  914.                     if ( clearedArea[CURR_MAP.system][DOCKED_AT] == false)
  915.                         {
  916.                             // planet NOT Safe
  917.                             // max of 10 enemies
  918.                             respawnDrones(8);
  919.                             deaths=0;
  920.                             respawnBoss();
  921.                         }
  922.                     else
  923.                         {
  924.                             boss->setSTATE(INACTIVE);
  925.                             deaths=0;
  926.                         }
  927.  
  928.                     // keep track of what system # you are entering
  929.                     docked.planet = DOCKED_AT;
  930.                     CURR_MAP.planet = DOCKED_AT;
  931.  
  932.                     // save current location
  933.                     prev.system.direction = player->getFacing();
  934.                     prev.system.pt.x = player->getX();
  935.                     prev.system.pt.y = player->getY();
  936.  
  937.                     // enter planet
  938.                     gameView=PLANET;                       
  939.                     SpeedX=0;
  940.                     SpeedY=0;
  941.                     player->setSpeed(0);
  942.  
  943.                     // move to starting location
  944.                     player->setPT(enterPLANET.pt);
  945.                     player->setFacing(enterPLANET.direction);
  946.                     ScrollX = enterPLANET.scroll.x; // map scroll values for given xy starting location
  947.                     ScrollY = enterPLANET.scroll.y;
  948.  
  949.                     mp3->OpenFile(".\\Media\\Sound\\teleport_activate.mp3",800, 0, 0);
  950.                     mp3->Play();
  951.                 }
  952.             };  break;
  953.          case PLANET: break; // do nothing, its already PLANET
  954.         }
  955.         KEY_PRESSED=true;
  956.     }
  957.     else if (KEY_DOWN(VK_SUBTRACT) || KEY_DOWN(VK_OEM_MINUS) || (player->getSTATE() == DEAD) )
  958.     {
  959.         if (KEY_PRESSED == true)
  960.             return;
  961.  
  962.         // --- NOTE --- //
  963.         // the "Escape" button :D
  964.         // the "-" key  ///
  965.         // heals u back up
  966.  
  967.     //  LOC_HULL,
  968.     //  LOC_ARMOR,
  969.     //  LOC_SHIELD
  970.         switch (gameView)
  971.         {
  972.             case SPACE:
  973.                 {
  974.                     // this is the "panic" button
  975.                     // so if you FLY off the map or some crazy thing --
  976.                     // hit "-" and .. teleports u back                 
  977.                     POINT dest = { 105, 105 }; // GAMEWORLDWIDTH HEIGHT
  978.                     player->setPT(dest);
  979.                     ScrollX=0;ScrollY=0;
  980.  
  981.                     player->setupShip(player->getMax(LOC_SHIELD),player->getMax(LOC_ARMOR),player->getMax(LOC_HULL));
  982.                     player->setSTATE(ACTIVE);
  983.                     player->useSolar(20);
  984.  
  985.                     mp3->Stop();
  986.                     mp3->OpenFile(".\\Media\\Sound\\teleport_activate.mp3",800, 0, 0);
  987.                     mp3->Play();
  988.                 }; break;
  989.  
  990.             case SYSTEM:
  991.                 {   // SYSTEM -> SPACE view                
  992.                     gameView=SPACE;
  993.  
  994.                     // un-spawn the drones
  995.                     respawnDrones(0); // sets them all to inactive
  996.                     boss->setSTATE(INACTIVE);
  997.                     deaths=0; // reset boss
  998.  
  999.                     // move to starting location
  1000.                     player->setPT(prev.space.pt);
  1001.                     player->setFacing(prev.space.direction);
  1002.                     ScrollX = getScrollX(prev.space.pt.x);
  1003.                     ScrollY = getScrollY(prev.space.pt.y);
  1004.                     SpeedX= 0;
  1005.                     SpeedY=0;
  1006.                     player->setSpeed(0);
  1007.                     KEY_PRESSED=true;
  1008.  
  1009.                     player->setupShip(player->getMax(LOC_SHIELD),player->getMax(LOC_ARMOR),player->getMax(LOC_HULL));
  1010.                     player->setSTATE(ACTIVE);
  1011.  
  1012.                     mp3->Stop();
  1013.                     mp3->OpenFile(".\\Media\\Sound\\teleport_activate.mp3",800, 0, 0);
  1014.                     mp3->Play();
  1015.  
  1016.                 };break;
  1017.             case PLANET:
  1018.                 {   // PLANET -> SYSTEM view
  1019.                     gameView=SYSTEM;  
  1020.  
  1021.                     // check if any enemies in this system
  1022.                     // if all planets cleared, then its safe
  1023.                     int pcnt=0; // number of unsafe planets
  1024.                     for (int p=0; p < NUM_MAPS_PLANET; p++)
  1025.                         if ( clearedArea[DOCKED_AT][p] == false)
  1026.                             pcnt++;
  1027.                     if (pcnt > DIFF_LEVEL)
  1028.                         pcnt = DIFF_LEVEL;
  1029.  
  1030.                     // respawn aliens (1 per planet)
  1031.                     respawnDrones(pcnt); // NONE if all planets safe
  1032.                     boss->setSTATE(INACTIVE);
  1033.                     deaths=0; // reset boss
  1034.  
  1035.                     player->setupShip(player->getMax(LOC_SHIELD),player->getMax(LOC_ARMOR),player->getMax(LOC_HULL));
  1036.                     player->setSTATE(ACTIVE);
  1037.  
  1038.                     // move to starting location
  1039.                     player->setPT(prev.system.pt);
  1040.                     player->setFacing(prev.system.direction);
  1041.                     ScrollX = getScrollX(prev.system.pt.x);
  1042.                     ScrollY = getScrollY(prev.system.pt.y);
  1043.                     SpeedX= 0;
  1044.                     SpeedY=0;
  1045.                     player->setSpeed(0);
  1046.                     KEY_PRESSED=true;
  1047.  
  1048.                     mp3->Stop();
  1049.                     mp3->OpenFile(".\\Media\\Sound\\teleport_activate.mp3",800, 0, 0);
  1050.                     mp3->Play();
  1051.                 };break;
  1052.         }
  1053.     }
  1054.     else if (KEY_DOWN(VK_SPACE) || KEY_DOWN(VK_LBUTTON))
  1055.     {
  1056.         if (KEY_PRESSED == true)
  1057.             return;
  1058.  
  1059.         // fire the weapon
  1060.         if ( player->canFire() )
  1061.         {          
  1062.             LPCSTR filename;
  1063.             // ok got enough power to fire the gun
  1064.             switch(player->getGun())
  1065.             {          
  1066.                 case  4: filename=".\\Media\\Sound\\plasma.mp3";  break;// torpedo
  1067.                 case  3: filename=".\\Media\\Sound\\missile.mp3"; break;// missile
  1068.                 case  2: filename=".\\Media\\Sound\\cannon.mp3";  break;// cannon
  1069.                 case  1: filename=".\\Media\\Sound\\Laser.mp3";   break;// laser
  1070.                 default: filename=".\\Media\\Sound\\blaster.mp3"; break;// blaster
  1071.             }  
  1072.             mp3->Stop();
  1073.             mp3->OpenFile(filename,800, 0, 0);
  1074.             mp3->Play();
  1075.  
  1076.             // start bullets out front at a safe distance
  1077.             rCode = Ammo[player->getAmmo()]->spawnBullet(player->getAnchor(),player->getFacing());
  1078.             if (rCode > -1)
  1079.                 cntBullets++;
  1080.         }
  1081.         else
  1082.         {
  1083.             // SOUND
  1084.             // make a sound that tells player it couldnt fire because you are out of power!!!
  1085.         }  
  1086.  
  1087.         KEY_PRESSED=true;
  1088.     }
  1089.     else if ( KEY_DOWN(VK_RBUTTON) || KEY_DOWN(VK_LCONTROL) || KEY_DOWN(VK_RCONTROL) )
  1090.     {
  1091.         if (KEY_PRESSED == true)
  1092.             return;
  1093.  
  1094.         int current = player->getGun(); //
  1095.        
  1096.         // left/right control
  1097.         // fires missile(s)
  1098.         if ( player->isLoaded() )
  1099.         {
  1100.             LPCSTR filename;
  1101.             // ok got enough power to fire the gun
  1102.             switch(Alt_Weapon)
  1103.             {
  1104.                 case  4: filename=".\\Media\\Sound\\plasma.mp3";  break;// torpedo
  1105.                 default: filename=".\\Media\\Sound\\missile.mp3"; break;// blaster
  1106.             }  
  1107.             mp3->Stop();
  1108.             mp3->OpenFile(filename,800, 0, 0);
  1109.             mp3->Play();
  1110.  
  1111.  
  1112.             // start bullets out front at a safe distance
  1113.             POINT destPT = player->getAnchor();//, player->getWidth(),player->getHeight(),player->getFacing());
  1114.             rCode= Ammo[Alt_Weapon]->spawnBullet(destPT,player->getFacing()); // missiles=3, torpedoes=4
  1115.             if (rCode > -1)
  1116.                 cntBullets++;
  1117.  
  1118.             KEY_PRESSED=true;
  1119.         }
  1120.     }
  1121.     else if (KEY_DOWN('1')) // 1 key
  1122.     {
  1123.         if (KEY_PRESSED == true)
  1124.             return;
  1125.  
  1126.         mp3->Stop();
  1127.         mp3->OpenFile(".\\Media\\Sound\\gun_change01.mp3",400, 0, 0);
  1128.         mp3->Play();
  1129.            
  1130.         player->setGun(Guns[0],0);
  1131.         KEY_PRESSED=true;
  1132.     }
  1133.     else if (KEY_DOWN('2')) // 2 key
  1134.     {
  1135.         if (KEY_PRESSED == true)
  1136.             return;
  1137.  
  1138.         mp3->Stop();
  1139.         mp3->OpenFile(".\\Media\\Sound\\gun_change02.mp3",400, 0, 0);
  1140.         mp3->Play();
  1141.         player->setGun(Guns[1],1);
  1142.         KEY_PRESSED=true;
  1143.     }
  1144.     else if (KEY_DOWN('3')) // 3 key
  1145.     {
  1146.         if (KEY_PRESSED == true)
  1147.             return;
  1148.         mp3->OpenFile(".\\Media\\Sound\\gun_change03.mp3",800, 0, 0);
  1149.         mp3->Play();
  1150.         player->setGun(Guns[2],2);
  1151.         KEY_PRESSED=true;
  1152.     }
  1153.     else if (KEY_DOWN('4')) // 4 key
  1154.     {
  1155.         if (KEY_PRESSED == true)
  1156.             return;
  1157.         mp3->OpenFile(".\\Media\\Sound\\gun_change04.mp3",800, 0, 0);
  1158.         mp3->Play();
  1159.         Alt_Weapon = 3;
  1160.         KEY_PRESSED=true;
  1161.     }
  1162.     else if (KEY_DOWN('5')) // 5 key
  1163.     {
  1164.         if (KEY_PRESSED == true)
  1165.             return;
  1166.         mp3->OpenFile(".\\Media\\Sound\\gun_change04.mp3",800, 0, 0);
  1167.         mp3->Play();
  1168.         Alt_Weapon = 4;
  1169.         KEY_PRESSED=true;
  1170.     }
  1171.     else
  1172.         KEY_PRESSED=false;
  1173.         // if none of the are pressed, we can press keys again
  1174. }
  1175.  
  1176. bool canScroll(DIRS direction,int speed)
  1177. {
  1178.     //ScrollX and ScrollY
  1179.     int testX=ScrollX;
  1180.     int testY=ScrollY;
  1181.  
  1182.     switch(direction)
  1183.     {
  1184.         case NORTH:  testY-=speed;      break;
  1185.         case SOUTH:  testY+=speed;      break;
  1186.         case EAST:   testX+=speed;      break;
  1187.         case WEST:   testX-=speed;      break;
  1188.         case NE:     testX+=speed;testY-=speed; break;
  1189.         case NW:     testX-=speed;testY-=speed; break;
  1190.         case SE:     testX+=speed;testY+=speed; break;
  1191.         case SW:     testX-=speed;testY+=speed; break;
  1192.     }
  1193.  
  1194.     return ( min_max(testX,0,GAMEWORLDWIDTH - SCREEN_WIDTH) && min_max(testY,0,GAMEWORLDHEIGHT - SCREEN_HEIGHT) );
  1195. }
  1196.  
  1197. //This function updates the scrolling position and speed
  1198. void UpdateScrollPosition()
  1199. {
  1200.     bool doScrollLeft  =  ((player->getX() - ScrollX) <= (SCREEN_WIDTH  * 0.25) && ((player->getFacing() == WEST)  || (player->getFacing() == NW) || (player->getFacing() == SW)) ); // WEST   
  1201.     bool doScrollRight =  ((player->getX() - ScrollX) >= (SCREEN_WIDTH  * 0.75) && ((player->getFacing() == EAST)  || (player->getFacing() == NE) || (player->getFacing() == SE)) ); // EAST
  1202.     bool doScrollUp    =  ((player->getY() - ScrollY) <= (SCREEN_HEIGHT * 0.25) && ((player->getFacing() == NORTH) || (player->getFacing() == NW) || (player->getFacing() == NE)) );   // NORTH
  1203.     bool doScrollDown  =  ((player->getY() - ScrollY) >= (SCREEN_HEIGHT * 0.75) && ((player->getFacing() == SOUTH) || (player->getFacing() == SE) || (player->getFacing() == SW)) );   // SOUTH
  1204.  
  1205.     if ((doScrollLeft || doScrollRight || doScrollUp || doScrollDown) == false)
  1206.         return;
  1207.  
  1208.     // exit if cant scroll
  1209.     if (! canScroll(player->getFacing(),player->getSpeed()) )
  1210.         return;
  1211.  
  1212. //  POINT   tPT = { ScrollX, ScrollY };
  1213. //  POINT newPT = calcXY(player->getAngle(),player->getSpeed(),tPT);
  1214.  
  1215. //  SpeedX = newPT.x - ScrollX; // east (10-8 -> +2 pix) west (6,8=-2)
  1216. //  SpeedY = newPT.y - ScrollY; // north (6-8 = -2) south (8-6) = +2
  1217.  
  1218.     SpeedX = 0; SpeedY=0;
  1219.     switch(player->getFacing())
  1220.     {       // based on direction we are heading, scroll the background - if possible
  1221.             case NORTH: SpeedY -= player->getSpeed(); break;
  1222.             case SOUTH: SpeedY += player->getSpeed(); break;
  1223.             case EAST:  SpeedX += player->getSpeed(); break;
  1224.             case WEST:  SpeedX -= player->getSpeed(); break;
  1225.             case NE:    SpeedX += player->getSpeed();
  1226.                         SpeedY -= player->getSpeed(); break;
  1227.             case NW:    SpeedX -= player->getSpeed();
  1228.                         SpeedY -= player->getSpeed(); break;
  1229.             case SE:    SpeedX += player->getSpeed();
  1230.                         SpeedY += player->getSpeed(); break;
  1231.             case SW:    SpeedX -= player->getSpeed();
  1232.                         SpeedY += player->getSpeed(); break;
  1233.     }
  1234.  
  1235.     // N/S movement
  1236.     if ((ScrollY + SpeedY) < 0)
  1237.     {
  1238.         ScrollY = 0;
  1239.         SpeedY  = 0;
  1240.     }
  1241.     else if ((ScrollY + SpeedY) > (GAMEWORLDHEIGHT - SCREEN_HEIGHT))
  1242.     {
  1243.         ScrollY = GAMEWORLDHEIGHT - SCREEN_HEIGHT;
  1244.         SpeedY = 0;
  1245.     }
  1246.     else
  1247.         ScrollY += SpeedY;      // OK to scroll Y
  1248.  
  1249.     // E/W movement
  1250.     if ((ScrollX + SpeedX) < 0)
  1251.     {
  1252.         ScrollX = 0;
  1253.         SpeedX  = 0;
  1254.     }
  1255.     else if ( (ScrollX + SpeedX) > (GAMEWORLDWIDTH - SCREEN_WIDTH))
  1256.     {
  1257.         ScrollX = GAMEWORLDWIDTH - SCREEN_WIDTH;
  1258.         SpeedX = 0;
  1259.     }
  1260.     else
  1261.         ScrollX += SpeedX;
  1262.  
  1263.     // now see what direction we are facing
  1264.     if ( (SpeedX < 0) && (SpeedY < 0) ) // NW
  1265.         player->setFacing(NW);
  1266.     if ((SpeedX > 0) && (SpeedY < 0)) // NE
  1267.         player->setFacing(NE);
  1268.     if ((SpeedX < 0) && (SpeedY > 0)) // SW
  1269.         player->setFacing(SW);
  1270.     if ((SpeedX > 0) && (SpeedY > 0)) // SE
  1271.         player->setFacing(SE);
  1272.     if ((SpeedX == 0) && (SpeedY > 0)) // SOUTH
  1273.         player->setFacing(SOUTH);
  1274.     if ((SpeedX == 0) && (SpeedY < 0)) // NORTH
  1275.         player->setFacing(NORTH);
  1276.     if ((SpeedX > 0) && (SpeedY == 0)) // EAST
  1277.         player->setFacing(EAST);
  1278.     if ((SpeedX < 0) && (SpeedY == 0)) // WEST
  1279.         player->setFacing(WEST);
  1280.  
  1281. }
  1282.  
  1283. //This function does the real work of drawing a single tile from the
  1284. //source image onto the tile scroll buffer. Parameters provide much
  1285. //flexibility.
  1286. void DrawTile(  //LPDIRECT3DSURFACE9 *source,   // source surface image
  1287.                 int tilenum,                // tile #
  1288.                 int width,                  // tile width
  1289.                 int height,                 // tile height
  1290.                 int columns,                // columns of tiles
  1291.                 LPDIRECT3DSURFACE9 dest,    // destination surface
  1292.                 int destx,                  // destination x
  1293.                 int desty)                  // destination y
  1294. {    
  1295.     //create a RECT to describe the source image
  1296.     RECT r1;
  1297.     r1.left = (tilenum % columns) * width;
  1298.     r1.top = (tilenum / columns) * height;
  1299.     r1.right = r1.left + width;
  1300.     r1.bottom = r1.top + height;
  1301.    
  1302.     //set destination rect
  1303.     RECT r2 = {destx,desty,destx+width,desty+height};
  1304.  
  1305.     //draw the tile
  1306.     switch (gameView)
  1307.     {
  1308.         case SPACE: d3ddev->StretchRect(space_tiles,  &r1, dest, &r2, D3DTEXF_NONE); break;
  1309.         case SYSTEM:d3ddev->StretchRect(system_tiles[0], &r1, dest, &r2, D3DTEXF_NONE); break;
  1310.         case PLANET:d3ddev->StretchRect(surface_tiles[0],&r1, dest, &r2, D3DTEXF_NONE); break;
  1311.     }
  1312. }
  1313.  
  1314. //This function fills the tilebuffer with tiles representing
  1315. //the current scroll display based on scrollx/scrolly.
  1316. void DrawTiles()
  1317. {
  1318.     switch (gameView)
  1319.     {
  1320.         case SPACE: DrawBG(space_tiles); break;
  1321.         case SYSTEM:DrawBG(system_tiles[0]); break;
  1322.         case PLANET:DrawBG(surface_tiles[0]); break;
  1323.     }
  1324.     return;
  1325. /*
  1326.     int tilex, tiley;
  1327.     int columns, rows;
  1328.     int x, y;
  1329.     int tilenum;
  1330.  
  1331.     //calculate starting tile position
  1332.     tilex = ScrollX / TILEWIDTH;
  1333.     tiley = ScrollY / TILEHEIGHT;
  1334.    
  1335.     //calculate the number of columns and rows
  1336.     columns = WINDOWWIDTH / TILEWIDTH;
  1337.     rows = WINDOWHEIGHT / TILEHEIGHT;
  1338.    
  1339.     //draw tiles onto the scroll buffer surface
  1340.     for (y=0; y<=rows; y++)
  1341.     {
  1342.         for (x=0; x<=columns; x++)
  1343.         {
  1344.             // default
  1345.             tilenum = MAPDATA[tilex + x][tiley + y];
  1346.            
  1347.             //retrieve the tile number from this position            
  1348.             if (gameView == SYSTEM)
  1349.                 tilenum = SYSTEM_MAPDATA[tilex + x][tiley + y];
  1350.  
  1351.             DrawTile(tilenum,TILEWIDTH,TILEHEIGHT,16,scrollbuffer, x*TILEWIDTH,y*TILEHEIGHT);
  1352.         }
  1353.     }
  1354. */
  1355. }
  1356.  
  1357. //This function draws the portion of the scroll buffer onto the back buffer
  1358. //according to the current "partial tile" scroll position.
  1359. void DrawScrollWindow()
  1360. {
  1361.     //calculate the partial sub-tile lines to draw using modulus
  1362.     int partialx = ScrollX % TILEWIDTH;
  1363.     int partialy = ScrollY % TILEHEIGHT;
  1364.    
  1365.     //set dimensions of the source image as a rectangle
  1366.     RECT r1 = {partialx,partialy,partialx+WINDOWWIDTH,partialy+WINDOWHEIGHT};
  1367.        
  1368.     //set the destination rectangle
  1369.     //This line draws the virtual scroll buffer to the screen exactly as is,
  1370.     //without scaling the image to fit the screen. If your screen does not
  1371.     //divide evenly with the tiles, then you may want to scale the scroll
  1372.     //buffer to fill the entire screen. It's better to use a resolution that
  1373.     //divides evenly with your tile size.
  1374.  
  1375.     //use this line for scaled display
  1376.     //RECT r2 = {0, 0, WINDOWWIDTH-1, WINDOWHEIGHT-1};  
  1377.    
  1378.     //use this line for non-scaled display
  1379.     RECT r2 = {0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1};
  1380.  
  1381.     //draw the "partial tile" scroll window onto the back buffer
  1382.     d3ddev->StretchRect(scrollbuffer, &r1, backbuffer, &r2, D3DTEXF_NONE);
  1383. }
  1384.  
  1385. // draw bar at location; using current, max # and color
  1386. void drawBar(int x, int y,int curr,int max, int color)
  1387. {
  1388. //      BARS
  1389. //      grey        0
  1390. //      blue        1
  1391. //      green       2
  1392. //      orange      3
  1393. //      blue        4
  1394. //      red         5
  1395. //      yellow      6
  1396.  
  1397.     int width  = 64;
  1398.     int height = 6;
  1399.  
  1400.     // 0 is grey bar
  1401.     // source
  1402.     RECT r1;
  1403.     r1.left   = 0;
  1404.     r1.right  = width;
  1405.     r1.top    = 0;
  1406.     r1.bottom = height;
  1407.  
  1408.     // dest
  1409.     RECT r2;
  1410.     r2.left = x;
  1411.     r2.top  = y;
  1412.     r2.right = x + (width*scalex);
  1413.     r2.bottom = y + (height*scaley);
  1414.  
  1415.     d3ddev->StretchRect(color_bars, &r1, backbuffer, &r2, D3DTEXF_NONE);
  1416.  
  1417.     // draw bar % percentage
  1418.     // change width to match %
  1419.     r1.left = (width * color);
  1420.     r1.right = r1.left + width;
  1421.     if (curr < max)
  1422.     {
  1423.         // only draw a portion of the rect if not equal
  1424.         r1.right = r1.left + (width * curr / max);
  1425.         r2.right = r2.left + (width * scalex * curr / max);
  1426.     }
  1427.     d3ddev->StretchRect(color_bars, &r1, backbuffer, &r2, D3DTEXF_NONE);
  1428. }
  1429.  
  1430. // returns t/f is given # is with the range
  1431. bool min_max(int num, int min,int max)
  1432. {
  1433.     return ((num <= max) && (num >= min));
  1434. }
  1435.  
  1436.  
  1437. void drawPlanets()
  1438. {
  1439.     CPlanet *planet;
  1440.  
  1441.     // check for debris leaving the screen
  1442.     switch(gameView)
  1443.     {
  1444.         case SPACE:
  1445.             {
  1446.                 for (int i=0; i < IMMOBILE_AMT_SPACE; i++)
  1447.                 {
  1448.                     planet = immobile_space[i];
  1449.                     POINT dest = planet->getPT();
  1450.                     dest.x -= ScrollX; // since they use game world coords
  1451.                     dest.y -= ScrollY; // subtract the offset values to get screen coord
  1452.  
  1453.  
  1454.                     // draw the sprite if it would appear on screen
  1455.                     if ( (((dest.x + planet->getWidth()) > 0) || (dest.y + planet->getHeight() >= 0)) && (( dest.x < SCREEN_WIDTH) || (dest.y  < SCREEN_HEIGHT)) )
  1456.                     {
  1457.                         if  ( (hitPlanet[0].space[i] == true) && (planet->getMap() > -1) )                         
  1458.                         {
  1459.                             DrawSprite( dest.x, dest.y,
  1460.                                         yellowBmp->getWidth(),yellowBmp->getHeight(),
  1461.                                         ScaleX, ScaleY,
  1462.                                         planet->getAngle(),
  1463.                                         D3DCOLOR_XRGB(255,255,255),
  1464.                                         yellowBmp->getImage(),
  1465.                                         NULL, //&yellowBmp->getRect(),
  1466.                                         d3ddev, false);
  1467. //                          drawNumbers(i,dest.x,dest.y-10);
  1468. //                          drawNumbers(planet->getFrame(),dest.x+50,dest.y-10);
  1469.                         }
  1470.  
  1471.                         DrawSprite( dest.x, dest.y,
  1472.                                     planet->getWidth(),planet->getHeight(),
  1473.                                     ScaleX, ScaleY,
  1474.                                     planet->getAngle(),
  1475.                                     D3DCOLOR_XRGB(255,255,255),
  1476.                                     planet->getImage(),
  1477.                                     &planet->getRect(),
  1478.                                     d3ddev, false);
  1479.                     }
  1480.                 }
  1481.             };break;
  1482.         case SYSTEM:
  1483.             {
  1484.                 for (int i=0; i < IMMOBILE_AMT_SYSTEM; i++)
  1485.                 {
  1486.                     planet = immobile_system[docked.system][i];
  1487.  
  1488.                     POINT dest = planet->getPT();
  1489.                     dest.x -= ScrollX; // since they use game world coords
  1490.                     dest.y -= ScrollY; // subtract the offset values to get screen coord
  1491.  
  1492.                     // draw the sprite if it would appear on screen
  1493.                     if ( (((dest.x + planet->getWidth()) > 0) || (dest.y + planet->getHeight() >= 0)) && (( dest.x < SCREEN_WIDTH) || (dest.y  < SCREEN_HEIGHT)) )
  1494.                     {
  1495.                         if ((hitPlanet[docked.system].system[i] == true) && (planet->getMap() > -1))
  1496.                         {
  1497.                             DrawSprite( dest.x, dest.y,
  1498.                                         yellowBmp->getWidth(),yellowBmp->getHeight(),
  1499.                                         ScaleX, ScaleY,
  1500.                                         planet->getAngle(),
  1501.                                         D3DCOLOR_XRGB(255,255,255),
  1502.                                         yellowBmp->getImage(),
  1503.                                         NULL, //&yellowBmp->getRect(),
  1504.                                         d3ddev,false);
  1505. //                          drawNumbers(i,dest.x,dest.y-10);
  1506. //                          drawNumbers(planet->getFrame(),dest.x+50,dest.y-10);
  1507.                         }
  1508.  
  1509.                         DrawSprite( dest.x, dest.y,
  1510.                                     planet->getWidth(),planet->getHeight(),
  1511.                                     ScaleX, ScaleY,
  1512.                                     planet->getAngle(),
  1513.                                     D3DCOLOR_XRGB(255,255,255),
  1514.                                     planet->getImage(),
  1515.                                     &planet->getRect(),
  1516.                                     d3ddev,false);
  1517.                     }
  1518.                 }
  1519.             };break;
  1520.         case PLANET:
  1521.             {
  1522.                 for (int i=0; i < IMMOBILE_AMT_PLANET; i++)
  1523.                 {
  1524.                     planet = immobile_planet[docked.planet][i];
  1525.  
  1526.                     POINT dest = planet->getPT();
  1527.                     dest.x -= ScrollX; // since they use game world coords
  1528.                     dest.y -= ScrollY; // subtract the offset values to get screen coord
  1529.  
  1530.                     // draw the sprite if it would appear on screen
  1531.                     if ( (((dest.x + planet->getWidth()) > 0) || (dest.y + planet->getHeight() >= 0)) && (( dest.x < SCREEN_WIDTH) || (dest.y  < SCREEN_HEIGHT)) )
  1532.                     {
  1533.                         if ((hitPlanet[docked.planet].surface[i] == true) && (planet->getMap() > -1))
  1534.                         {
  1535.                             DrawSprite( dest.x, dest.y,
  1536.                                         yellowBmp->getWidth(),yellowBmp->getHeight(),
  1537.                                         ScaleX, ScaleY,
  1538.                                         planet->getAngle(),
  1539.                                         D3DCOLOR_XRGB(255,255,255),
  1540.                                         yellowBmp->getImage(),
  1541.                                         NULL, //&yellowBmp->getRect(),
  1542.                                         d3ddev, false);
  1543. //                          drawNumbers(i,dest.x,dest.y-10);
  1544. //                          drawNumbers(planet->getFrame(),dest.x+50,dest.y-10);
  1545.                         }
  1546.  
  1547.                         DrawSprite( dest.x, dest.y,
  1548.                                     planet->getWidth(),planet->getHeight(),
  1549.                                     ScaleX, ScaleY, planet->getAngle(),
  1550.                                     D3DCOLOR_XRGB(255,255,255),
  1551.                                     planet->getImage(),
  1552.                                     &planet->getRect(),
  1553.                                     d3ddev, false);
  1554.                     }
  1555.                 };
  1556.             };break;
  1557.     } // end case ...
  1558. };
  1559. //draw the debris sprites
  1560. void drawDebris()
  1561. {
  1562.     CDebris *debris;
  1563.  
  1564.     // check for debris leaving the screen
  1565.     switch(gameView)
  1566.     {
  1567.         case SPACE:
  1568.             {
  1569.                 for (int i=0; i < DEBRIS_AMT_SPACE; i++)
  1570.                 {
  1571.                     debris = debris_space[i];  
  1572.                     POINT dest = {debris->getX(),debris->getY()};
  1573.                     dest.x -= ScrollX; // since they use game world coords
  1574.                     dest.y -= ScrollY; // subtract the offset values to get screen coord
  1575.  
  1576.                     // draw the sprite if it would appear on screen
  1577.                     if ( (((dest.x + debris->getWidth()) > 0) || (dest.y + debris->getHeight() >= 0)) && (( dest.x < SCREEN_WIDTH) || (dest.y  < SCREEN_HEIGHT)) )
  1578.                     {
  1579.                         if (hitDebris.space[i] == true)
  1580.                         {
  1581.                             DrawSprite( dest.x, dest.y,
  1582.                                         redBmp->getWidth(),redBmp->getHeight(),
  1583.                                         scalex, scaley,
  1584.                                         debris->getAngle(),
  1585.                                         D3DCOLOR_XRGB(255,255,255),
  1586.                                         redBmp->getImage(),
  1587.                                         NULL,  //&debris->getRect(),
  1588.                                         d3ddev,false);
  1589. //                          drawNumbers(i,dest.x,dest.y-10);
  1590. //                          drawNumbers(debris->getFrame(),dest.x+50,dest.y-10);
  1591.                         }
  1592.  
  1593.                         DrawSprite( dest.x, dest.y,
  1594.                                     debris->getWidth(),debris->getHeight(),
  1595.                                     scalex, scaley,
  1596.                                     debris->getAngle(),
  1597.                                     D3DCOLOR_XRGB(255,255,255),
  1598.                                     debris->getImage(),
  1599.                                     &debris->getRect(),
  1600.                                     d3ddev,false);
  1601.                     }
  1602.                 }
  1603.             };break;
  1604.         case SYSTEM:
  1605.             {
  1606.                 for (int i=0; i < DEBRIS_AMT_SYSTEM; i++)
  1607.                 {
  1608.                     debris = debris_system[i]; 
  1609.  
  1610.                     POINT dest = {debris->getX(),debris->getY()};
  1611.                     dest.x -= ScrollX; // since they use game world coords
  1612.                     dest.y -= ScrollY; // subtract the offset values to get screen coord
  1613.  
  1614.                     // draw the sprite if it would appear on screen
  1615.                     if ( (((dest.x + debris->getWidth()) > 0) || (dest.y + debris->getHeight() >= 0)) && (( dest.x < SCREEN_WIDTH) || (dest.y  < SCREEN_HEIGHT)) )
  1616.                     {
  1617.                         if (hitDebris.system[i] == true)
  1618.                         {
  1619.                             DrawSprite( dest.x, dest.y,
  1620.                                         redBmp->getWidth(),redBmp->getHeight(),
  1621.                                         scalex, scaley,
  1622.                                         debris->getAngle(),
  1623.                                         D3DCOLOR_XRGB(255,255,255),
  1624.                                         redBmp->getImage(),
  1625.                                         NULL,  //&debris->getRect(),
  1626.                                         d3ddev,false);
  1627. //                          drawNumbers(i,dest.x,dest.y-10);
  1628. //                          drawNumbers(debris->getFrame(),dest.x+50,dest.y-10);
  1629.                         }
  1630.  
  1631.                         DrawSprite( dest.x, dest.y,
  1632.                                     debris->getWidth(),debris->getHeight(),
  1633.                                     scalex, scaley,
  1634.                                     debris->getAngle(),
  1635.                                     D3DCOLOR_XRGB(255,255,255),
  1636.                                     debris->getImage(),
  1637.                                     &debris->getRect(),
  1638.                                     d3ddev,false);
  1639.                     }
  1640.                 }
  1641.             };break;
  1642.         case PLANET:
  1643.             {
  1644.                 for (int i=0; i < DEBRIS_AMT_PLANET; i++)
  1645.                 {
  1646.                     debris = debris_planet[i]; 
  1647.  
  1648.                     POINT dest = {debris->getX(),debris->getY()};
  1649.                     dest.x -= ScrollX; // since they use game world coords
  1650.                     dest.y -= ScrollY; // subtract the offset values to get screen coord
  1651.  
  1652.                     // draw the sprite if it would appear on screen
  1653.                     if ( (((dest.x + debris->getWidth()) > 0) || (dest.y + debris->getHeight() >= 0)) && (( dest.x < SCREEN_WIDTH) || (dest.y  < SCREEN_HEIGHT)) )
  1654.                     {
  1655.                         if (hitDebris.surface[i] == true)
  1656.                         {
  1657.                             DrawSprite( dest.x, dest.y,
  1658.                                         redBmp->getWidth(),redBmp->getHeight(),
  1659.                                         scalex, scaley,
  1660.                                         debris->getAngle(),
  1661.                                         D3DCOLOR_XRGB(255,255,255),
  1662.                                         yellowBmp->getImage(),
  1663.                                         NULL,  //&debris->getRect(),
  1664.                                         d3ddev,false);
  1665. //                          drawNumbers(i,dest.x,dest.y-10);
  1666. //                          drawNumbers(debris->getFrame(),dest.x+50,dest.y-10);
  1667.                         }
  1668.  
  1669.                         DrawSprite( dest.x, dest.y,
  1670.                                     debris->getWidth(),debris->getHeight(),
  1671.                                     scalex, scaley, debris->getAngle(),
  1672.                                     D3DCOLOR_XRGB(255,255,255),
  1673.                                     debris->getImage(),
  1674.                                     &debris->getRect(),
  1675.                                     d3ddev,false);
  1676.                     }
  1677.                 };
  1678.             };break;
  1679.     } // end case ...
  1680. }
  1681.  
  1682.  
  1683. // determine which direction to turn to face target
  1684. DIRS getDirection(POINT sourcePT, POINT targetPT)
  1685. {
  1686.     int a = 0; // centered horizontally
  1687.     // left to right
  1688.     if (sourcePT.x < targetPT.x) // left
  1689.         a = -1;
  1690.     if (sourcePT.x > targetPT.x) // right
  1691.         a = 1;
  1692.  
  1693.     int b = 0; // centered vertically
  1694.     // top to bottom
  1695.     if (sourcePT.y < targetPT.y) // above
  1696.         b = -1;
  1697.     if (sourcePT.y > targetPT.y) // below
  1698.         b = 1;
  1699.  
  1700.     switch(a)
  1701.     {
  1702.         case -1:
  1703.             {
  1704.                 if (b == -1)
  1705.                     { return NW; }
  1706.                 else if (b == 1)
  1707.                     { return SW; }
  1708.                 else
  1709.                     return WEST;
  1710.             }; break;
  1711.         case 1:
  1712.             {
  1713.                 if (b == -1)
  1714.                     { return NE; }
  1715.                 else if (b == 1)
  1716.                     { return SE; }
  1717.                 else
  1718.                     return EAST;
  1719.             }; break;
  1720.         case 0:
  1721.             {
  1722.                 if (b == -1)
  1723.                     { return NORTH; }
  1724.                 else
  1725.                     { return SOUTH; }
  1726.             };break;
  1727.     }
  1728.  
  1729.     return EAST; // default catch all
  1730. }
  1731.  
  1732. // returns distance in pixels
  1733. float findDistance(POINT pt1,POINT pt2)
  1734. {
  1735.     float distance;
  1736.     float   dx = pt1.x - pt2.x;
  1737.     float   dy = pt1.y - pt2.y;
  1738.     distance = sqrt(dx*dx + dy*dy);
  1739.     return distance;
  1740. }
  1741.  
  1742. // test for collisions
  1743. int SpriteCollision(CSprite *sprite1, CSprite *sprite2)
  1744. {
  1745.     RECT rect1;
  1746.     rect1.left   = sprite1->getX() + 1;
  1747.     rect1.top    = sprite1->getY() + 1;
  1748.     rect1.right  = sprite1->getX() + sprite1->getWidth()  -2;
  1749.     rect1.bottom = sprite1->getY() + sprite1->getHeight() -2;
  1750.  
  1751.     RECT rect2;
  1752.     rect2.left   = sprite2->getX() + 1;
  1753.     rect2.top    = sprite2->getY() + 1;
  1754.     rect2.right  = sprite2->getX() + sprite2->getWidth()  -2;
  1755.     rect2.bottom = sprite2->getY() + sprite2->getHeight() -2;
  1756.  
  1757.     RECT dest;
  1758.     return IntersectRect(&dest, &rect1, &rect2);
  1759. }
  1760.  
  1761. // test for collisions
  1762. bool rectCollision(RECT r1, RECT r2)
  1763. {
  1764.  
  1765. return ( r1.left   < r2.right  &&
  1766.          r1.top    < r2.bottom &&
  1767.          r1.right  > r2.left   &&        
  1768.          r1.bottom > r2.top    );
  1769. }
  1770.  
  1771. bool circleCollision(POINT a,int radius1, POINT b, int radius2)
  1772. {
  1773.     int dx = b.x - a.x;
  1774.     int dy = b.y - a.y;
  1775.     int radii = radius1 + radius2;
  1776.     //return ( ((b.x - a.x)^2 + (b.y - a.y)^2) < (radius1 + radius2) );
  1777.     return ( (dx*dx)+(dy*dy) < (radii * radii) );
  1778. };
  1779.  
  1780. int planetCollision(CSprite *target)
  1781. {
  1782. //  RECT r1,r2;
  1783.  
  1784.     CPlanet *planet;
  1785.  
  1786.     int i;
  1787.  
  1788.     // see if player has collided with any debris
  1789.     switch(gameView)
  1790.     {
  1791.         case SPACE:
  1792.         {
  1793.             for (i=0; i < IMMOBILE_AMT_SPACE; i++)
  1794.             {
  1795.                 planet = immobile_space[i];
  1796.  
  1797.                 POINT targetPT = target->getAnchor();
  1798.                 POINT planetPT = planet->getAnchor();
  1799.  
  1800.                 int temp = target->getHeight();
  1801.                 if (target->getWidth() < target->getHeight())
  1802.                     temp = target->getWidth();
  1803.                 int radiusT = temp * COLL_RADIUS * scalex; // should cover most of the sprite in its radius ... 96/2=48-4=44
  1804.  
  1805.                 temp = planet->getHeight();
  1806.                 if (planet->getWidth() < planet->getHeight())
  1807.                     temp = planet->getWidth();             
  1808.                 int radiusD = temp * COLL_RADIUS; // should cover most of the sprite in its radius ... 120/2=60-
  1809.  
  1810.                 // use circle collision
  1811.                 if (circleCollision(targetPT,radiusT,planetPT,radiusD))
  1812.                 {
  1813.                     hitPlanet[0].space[i] = true;
  1814.                     return i;  
  1815.                 }
  1816.                 else
  1817.                     hitPlanet[0].space[i] = false;                 
  1818.             }
  1819.         }; break;
  1820.         case SYSTEM:
  1821.         {
  1822.             for (i=0; i < IMMOBILE_AMT_SYSTEM; i++)
  1823.             {
  1824.                 planet = immobile_system[docked.system][i];
  1825.  
  1826.                 POINT targetPT = target->getAnchor();
  1827.                 POINT planetPT = planet->getAnchor();
  1828.  
  1829.                 int temp = target->getHeight();
  1830.                 if (target->getWidth() < target->getHeight())
  1831.                     temp = target->getWidth();
  1832.                 int radiusT = temp * COLL_RADIUS * scalex; // should cover most of the sprite in its radius ... 96/2=48-4=44
  1833.  
  1834.                 temp = planet->getHeight();
  1835.                 if (planet->getWidth() < planet->getHeight())
  1836.                     temp = planet->getWidth();             
  1837.                 int radiusD = temp * COLL_RADIUS; // should cover most of the sprite in its radius ... 120/2=60-
  1838.  
  1839.                 // use circle collision
  1840.                 if (circleCollision(targetPT,radiusT,planetPT,radiusD))
  1841.                 {
  1842.                     hitPlanet[docked.system].system[i] = true;
  1843.                     return i;  
  1844.                 }
  1845.                 else
  1846.                     hitPlanet[docked.system].system[i] = false;
  1847.             }
  1848.         }; break;
  1849.         case PLANET:
  1850.         {
  1851.             for (i=0; i < IMMOBILE_AMT_PLANET; i++)
  1852.             {
  1853.                 planet = immobile_planet[docked.planet][i];
  1854.  
  1855.                 POINT targetPT = target->getAnchor();
  1856.                 POINT planetPT = planet->getAnchor();
  1857.  
  1858.                 int temp = target->getHeight();
  1859.                 if (target->getWidth() < target->getHeight())
  1860.                     temp = target->getWidth();
  1861.                 int radiusT = temp * COLL_RADIUS * scalex; // should cover most of the sprite in its radius ... 96/2=48-4=44
  1862.  
  1863.                 temp = planet->getHeight();
  1864.                 if (planet->getWidth() < planet->getHeight())
  1865.                     temp = planet->getWidth();             
  1866.                 int radiusD = temp * COLL_RADIUS; // should cover most of the sprite in its radius ... 120/2=60-
  1867.  
  1868.                 // use circle collision
  1869.                 if (circleCollision(targetPT,radiusT,planetPT,radiusD))
  1870.                 {
  1871.                     hitPlanet[docked.planet].surface[i] = true;
  1872.                     return i;  
  1873.                 }
  1874.                 else
  1875.                     hitPlanet[docked.planet].surface[i] = false;
  1876.             }
  1877.         };break;
  1878.     }
  1879.  
  1880.     // if no collisions (return -1)
  1881.     return -1;
  1882. } // end planet collision testing
  1883.  
  1884. int debrisCollision( CSprite *target)
  1885. {
  1886. //  RECT r1,r2;
  1887.  
  1888.     CDebris *debris;
  1889.  
  1890.     int i;
  1891.     // see if player has collided with any debris
  1892.     switch(gameView)
  1893.     {
  1894.         case SPACE:
  1895.         {          
  1896.             for (i=0; i < DEBRIS_AMT_SPACE; i++)
  1897.             {
  1898.                 debris = debris_space[i];
  1899.  
  1900.                 POINT targetPT = target->getAnchor();
  1901.                 POINT debrisPT = debris->getAnchor();
  1902.  
  1903.                 int temp = target->getHeight();
  1904.                 if (target->getWidth() < target->getHeight())
  1905.                     temp = target->getWidth();
  1906.                 int radiusT = temp * COLL_RADIUS * scalex; // should cover most of the sprite in its radius ... 96/2=48-4=44
  1907.  
  1908.                 temp = debris->getHeight();
  1909.                 if (debris->getWidth() < debris->getHeight())
  1910.                     temp = debris->getWidth();             
  1911.                 int radiusD = temp * COLL_RADIUS; // should cover most of the sprite in its radius ... 120/2=60-
  1912.  
  1913.                 // use circle collision
  1914.                 if (circleCollision(targetPT,radiusT,debrisPT,radiusD))
  1915.                 {
  1916.                     hitDebris.space[i] = true;
  1917.                     return i;  
  1918.                 }
  1919.                 else
  1920.                     hitDebris.space[i] = false;
  1921.             }
  1922.         }; break;
  1923.         case SYSTEM:
  1924.         {
  1925.             for (i=0; i < DEBRIS_AMT_SYSTEM; i++)
  1926.             {
  1927.                 debris = debris_system[i];
  1928.  
  1929.                 POINT targetPT = target->getAnchor();
  1930.                 POINT debrisPT = debris->getAnchor();
  1931.  
  1932.                 int temp = target->getHeight();
  1933.                 if (target->getWidth() < target->getHeight())
  1934.                     temp = target->getWidth();
  1935.                 int radiusT = temp * COLL_RADIUS * scalex; // should cover most of the sprite in its radius ... 96/2=48-4=44
  1936.  
  1937.                 temp = debris->getHeight();
  1938.                 if (debris->getWidth() < debris->getHeight())
  1939.                     temp = debris->getWidth();             
  1940.                 int radiusD = temp * COLL_RADIUS; // should cover most of the sprite in its radius ... 120/2=60-
  1941.  
  1942.                 // use circle collision
  1943.                 if (circleCollision(targetPT,radiusT,debrisPT,radiusD))
  1944.                 {
  1945.                     hitDebris.system[i] = true;
  1946.                     return i;  
  1947.                 }
  1948.                 else
  1949.                     hitDebris.system[i] = false;
  1950.             }
  1951.         }; break;
  1952.         case PLANET:
  1953.         {
  1954.             for (i=0; i < DEBRIS_AMT_PLANET; i++)
  1955.             {
  1956.                 debris = debris_planet[i];
  1957.  
  1958.                 POINT targetPT = target->getAnchor();
  1959.                 POINT debrisPT = debris->getAnchor();
  1960.  
  1961.                 int temp = target->getHeight();
  1962.                 if (target->getWidth() < target->getHeight())
  1963.                     temp = target->getWidth();
  1964.                 int radiusT = temp * COLL_RADIUS * scalex; // should cover most of the sprite in its radius ... 96/2=48-4=44
  1965.  
  1966.                 temp = debris->getHeight();
  1967.                 if (debris->getWidth() < debris->getHeight())
  1968.                     temp = debris->getWidth();             
  1969.                 int radiusD = temp * COLL_RADIUS; // should cover most of the sprite in its radius ... 120/2=60-
  1970.  
  1971.                 // use circle collision
  1972.                 if (circleCollision(targetPT,radiusT,debrisPT,radiusD))
  1973.                 {
  1974.                     hitDebris.surface[i] = true;
  1975.                     return i;  
  1976.                 }
  1977.                 else
  1978.                     hitDebris.surface[i] = false;
  1979.             }
  1980.         };break;
  1981.     }
  1982.  
  1983.     // if no collisions
  1984.     return -1;
  1985. } // end debris collision testing
  1986.  
  1987.  
  1988. // checks if debris has left screen and respawns it randomly
  1989. // only used for the space view
  1990. void respawnDebris()
  1991. {
  1992.     // it checks for objects leaving the game map
  1993.     // and respawns them with new image
  1994.     // heading etc ... from one of the 4 map borders
  1995.     for (int i=0; i < DEBRIS_AMT_SPACE; i++)
  1996.         debris_space[i]->checkExit();
  1997.     for (int i=0; i < DEBRIS_AMT_SYSTEM; i++)
  1998.         debris_system[i]->checkExit();
  1999.     for (int i=0; i < DEBRIS_AMT_PLANET; i++)
  2000.         debris_planet[i]->checkExit();
  2001. }
  2002.  
  2003.  
  2004. // calculates new velocity and heading
  2005. void collision2Ds(double m1, double m2,
  2006.                  double x1, double y1, double x2, double y2) //,
  2007. //                 double& vx1, double& vy1, double& vx2, double& vy2)
  2008. {
  2009. // globals
  2010. //double vPx; vx1
  2011. //double vPy; vy1
  2012. //double vJx; vx2
  2013. //double vJy; vy2
  2014.  
  2015.        double  m21,dvx2,a,x21,y21,vx21,vy21,fy21,sign;
  2016.  
  2017.        m21=m2/m1;
  2018.        x21=x2-x1;
  2019.        y21=y2-y1;
  2020.        vx21=vJx-vPx;
  2021.        vy21=vJy-vPy;
  2022.  
  2023. //     *** return old velocities if balls are not approaching ***
  2024.        if ( (vx21*x21 + vy21*y21) >= 0) return;
  2025.  
  2026.        fy21=1.0E-12*fabs(y21);                            
  2027.        if ( fabs(x21)<fy21 ) {  
  2028.                    if (x21<0) { sign=-1; } else { sign=1;}  
  2029.                    x21=fy21*sign;
  2030.         }
  2031.  
  2032. //     ***  update velocities ***
  2033.        a=y21/x21;
  2034.        dvx2= -2*(vx21 +a*vy21)/((1+a*a)*(1+m21)) ;
  2035.        vJx=vJx+dvx2;
  2036.        vJy=vJy+a*dvx2;
  2037.        vPx=vPx-m21*dvx2;
  2038.        vPy=vPy-a*m21*dvx2;
  2039. }
  2040.  
  2041. // translates a given x location to get ScrollX value
  2042. int getScrollX(int x)
  2043. {
  2044.     int temp = 0;
  2045.     if (x < (SCREEN_WIDTH*0.75))
  2046.         return 0;
  2047.  
  2048.     temp = x - (SCREEN_WIDTH /2); // 1000 - 480 = 520 scrollx
  2049.     if ( temp > (GAMEWORLDWIDTH - SCREEN_WIDTH))
  2050.         temp = GAMEWORLDWIDTH - SCREEN_WIDTH;
  2051.  
  2052.     return temp;
  2053. };
  2054.  
  2055. // translates a given y location to get ScrollY value
  2056. int getScrollY(int y)
  2057. {
  2058.     int temp = 0;
  2059.     if (y < (SCREEN_HEIGHT*0.75))
  2060.         return 0;
  2061.  
  2062.     temp = y - (SCREEN_HEIGHT /2); // 1000 - 480 = 520 scrollx
  2063.     if ( temp > (GAMEWORLDHEIGHT - SCREEN_HEIGHT))
  2064.         temp = GAMEWORLDHEIGHT - SCREEN_HEIGHT;
  2065.  
  2066.     return temp;
  2067. };
  2068.  
  2069. void loadMaps()
  2070. {
  2071.     int cnt=0;
  2072.     char buffer[256];
  2073.     char line[255];
  2074.     char filename[100];
  2075.     LPCSTR Filename;
  2076.  
  2077.     // setup cleared - by default all areas are cleared, until maps are loaded
  2078.     for (int s=0;s < NUM_MAPS_SYSTEM; s++)
  2079.         for (int p=0;p<NUM_MAPS_PLANET;p++)
  2080.             clearedArea[s][p] = true;
  2081.  
  2082. // ------------------------------------------------------------------------
  2083.     for (int map=0; map < NUM_MAPS_PLANET; map++)
  2084.     {
  2085.         sprintf(filename,"./Media/static_surface_0%d.txt",map);
  2086.  
  2087.         // load map data
  2088.         ifstream mapFile(filename);
  2089.  
  2090.         // read in data from map file
  2091.         assert(! mapFile.fail());
  2092.  
  2093.         // BITMAP SOURCE
  2094.         Filename = TEXT("./Media/Images/static_surface.png");
  2095.  
  2096.         cnt=0;
  2097.         while ((! mapFile.eof()) && (cnt < IMMOBILE_AMT_PLANET))
  2098.         {
  2099.             // read in the map data    
  2100.             mapFile.getline(line, sizeof(buffer), ','); // X
  2101.             int x = atoi(line);        
  2102.             mapFile.getline(line, sizeof(buffer), ','); // Y
  2103.             int y = atoi(line);        
  2104.             mapFile.getline(line, sizeof(buffer), ','); // FRAME #
  2105.             int frame = atoi(line);    
  2106.             mapFile.getline(line, sizeof(buffer), ','); // ANGLE
  2107.             int rotation = atoi(line);     
  2108.             mapFile.getline(line, sizeof(buffer), '\n'); // grab the end of line
  2109.             int Map = atoi(line);                   // rotation speed (if any)
  2110.  
  2111.             immobile_planet[map][cnt] = new CPlanet(x,y,120,110,Filename,IMMOBILE_AMT_PLANET);     
  2112.             immobile_planet[map][cnt]->setFrame(frame-1);
  2113.             immobile_planet[map][cnt]->setFacing(NORTH);
  2114.             immobile_planet[map][cnt]->setMap(Map);
  2115.             immobile_planet[map][cnt]->setAngle(rotation);
  2116.  
  2117.             hitPlanet[map].surface[cnt] = false;           
  2118.  
  2119.             assert(immobile_planet[map][cnt]);     
  2120.  
  2121.             cnt++;
  2122.         }
  2123.         mapFile.close();
  2124.     }
  2125. // ------------------------------------------------------------------------
  2126.     ifstream spaceFile(TEXT("./Media/static_space_00.txt"));
  2127.     assert(! spaceFile.fail());
  2128.  
  2129.     Filename = TEXT("./Media/Images/static_space.png");
  2130.  
  2131.     cnt=0;
  2132.     while ((! spaceFile.eof()) && (cnt < IMMOBILE_AMT_SPACE))
  2133.     {
  2134.         // read in the map data    
  2135.         spaceFile.getline(line, sizeof(buffer), ','); // X
  2136.         int x = atoi(line);        
  2137.         spaceFile.getline(line, sizeof(buffer), ','); // Y
  2138.         int y = atoi(line);        
  2139.         spaceFile.getline(line, sizeof(buffer), ','); // FRAME #
  2140.         int frame = atoi(line);    
  2141.         spaceFile.getline(line, sizeof(buffer), ','); // ANGLE
  2142.         int rotation = atoi(line);     
  2143.         spaceFile.getline(line, sizeof(buffer), '\n'); // grab the end of line
  2144.         int map = atoi(line);                   // rotation speed (if any)
  2145.  
  2146.         immobile_space[cnt] = new CPlanet(x,y,120,110,Filename,IMMOBILE_SPRITES_SPACE);    
  2147.         immobile_space[cnt]->setFrame(frame-1);
  2148.         immobile_space[cnt]->setAngle(rotation);
  2149.         immobile_space[cnt]->setMap(map);
  2150.         hitPlanet[0].space[cnt] = false;
  2151.         assert(immobile_space[cnt]);
  2152.  
  2153.         cnt++;
  2154.     }
  2155.     spaceFile.close();
  2156. // ------------------------------------------------------------------------
  2157.     for (int map=0; map < NUM_MAPS_SYSTEM; map++)
  2158.     {
  2159.         sprintf(filename,"./Media/static_system_0%d.txt",map);
  2160.  
  2161.         ifstream sysFile(filename);
  2162.         // read in data from map file
  2163.         assert(! sysFile.fail());
  2164.  
  2165.         // BITMAP SOURCE
  2166.         Filename = TEXT("./Media/Images/static_system.png");
  2167.  
  2168.         cnt=0;
  2169.         while ((! sysFile.eof()) && (cnt < IMMOBILE_AMT_SYSTEM))
  2170.         {
  2171.             // read in the map data    
  2172.             sysFile.getline(line, sizeof(buffer), ','); // X
  2173.             int x = atoi(line);        
  2174.             sysFile.getline(line, sizeof(buffer), ','); // Y
  2175.             int y = atoi(line);        
  2176.             sysFile.getline(line, sizeof(buffer), ','); // FRAME #
  2177.             int frame = atoi(line);    
  2178.             sysFile.getline(line, sizeof(buffer), ','); // ANGLE
  2179.             int rotation = atoi(line);     
  2180.             sysFile.getline(line, sizeof(buffer), '\n'); // grab the end of line
  2181.             int Map = atoi(line);                   // rotation speed (if any)
  2182.  
  2183.             // Map > -1 , cnt = Planet # // indicate enemy occupied areas
  2184.             if (Map > -1)
  2185.                 clearedArea[map][cnt] = false; // there will be enemies there now
  2186.  
  2187.             immobile_system[map][cnt] = new CPlanet(x,y,120,110,Filename,IMMOBILE_AMT_SYSTEM);     
  2188.             immobile_system[map][cnt]->setFrame(frame-1); // 0 is the first frame!
  2189.             immobile_system[map][cnt]->setAngle(rotation);     
  2190.             immobile_system[map][cnt]->setMap(Map);
  2191.  
  2192.             assert(immobile_system[map][cnt]);
  2193.  
  2194.             hitPlanet[map].system[cnt] = false;
  2195.             cnt++;
  2196.         }
  2197.         sysFile.close();
  2198.     }
  2199. };
  2200.  
  2201. void moveBullets()
  2202. {
  2203.     for (int a=0; a < MAX_AMMO; a++)
  2204.         Ammo[a]->doMoves(scalex); // only moves the active ones
  2205.     for (int a=0; a < MAX_GUNS_AI; a++)
  2206.         Ammo_AI[a]->doMoves(scalex); // only moves the active ones
  2207. };
  2208.  
  2209. // draw the active bullet sprites
  2210. void drawBullets()
  2211. {
  2212.     int cnt = 0;
  2213.  
  2214.     // PC bullets
  2215.     for (int a=0; a < MAX_AMMO; a++)
  2216.         for (int i=0; i < MAX_BULLETS; i++)
  2217.             if (Ammo[a]->Bullets[i].isActive == true)
  2218.             {   //draw the bullet sprite
  2219.                 cnt++; // keep track of number of bullets drawn
  2220.                 DrawSprite( Ammo[a]->Bullets[i].currPT.x-ScrollX,
  2221.                             Ammo[a]->Bullets[i].currPT.y-ScrollY,
  2222.                             Ammo[a]->getWidth(), Ammo[a]->getHeight(),
  2223.                             scalex, scaley,
  2224.                             Ammo[a]->Bullets[i].angle,
  2225.                             D3DCOLOR_XRGB(255,255,255),
  2226.                             Ammo[a]->getImage(),
  2227.                             & Ammo[a]->getRect(),
  2228.                             d3ddev, true);
  2229.             }
  2230.     // AI Bullets
  2231.     for (int a=0; a < MAX_GUNS_AI; a++)
  2232.         for (int i=0; i < MAX_BULLETS; i++)
  2233.             if (Ammo_AI[a]->Bullets[i].isActive == true)
  2234.             {   //draw the bullet sprite
  2235.                 cnt++; // keep track of number of bullets drawn
  2236.                 DrawSprite( Ammo_AI[a]->Bullets[i].currPT.x-ScrollX,
  2237.                             Ammo_AI[a]->Bullets[i].currPT.y-ScrollY,
  2238.                             Ammo_AI[a]->getWidth(), Ammo_AI[a]->getHeight(),
  2239.                             scalex, scaley,
  2240.                             Ammo_AI[a]->Bullets[i].angle,
  2241.                             D3DCOLOR_XRGB(255,255,255),
  2242.                             Ammo_AI[a]->getImage(),
  2243.                             & Ammo_AI[a]->getRect(),
  2244.                             d3ddev, true);
  2245.  
  2246.             }
  2247.     bulletsDrawn = cnt;
  2248. };
  2249.  
  2250. // draw the active bullet sprites
  2251. void bulletCollision(CShip *target)
  2252. {
  2253.     int cnt = 0;
  2254.     bool hit = false;
  2255.     int hitCnt = 0;
  2256.  
  2257.     for (int a=0; a < MAX_AMMO; a++)
  2258.         for (int i=0; i < MAX_BULLETS; i++)
  2259.             if (Ammo[a]->Bullets[i].isActive == true)
  2260.                 {
  2261.                     POINT  pt1 = Ammo[a]->Bullets[i].currPT;
  2262.                     int halfW = Ammo[a]->getWidth()  / 2;
  2263.                     int halfH = Ammo[a]->getHeight() / 2;
  2264.  
  2265.                     POINT center;
  2266.                     center.x = pt1.x + halfW;
  2267.                     center.y = pt1.y + halfH;
  2268.                     int radius1 = halfW;
  2269.  
  2270.                     // players location
  2271.                     POINT pt2 = target->getAnchor();
  2272.                     int radius2 = target->getWidth() * 0.4f;               
  2273.  
  2274.                     if ( circleCollision(center,radius1,pt2,radius2) )
  2275.                     {
  2276.                         // this bullet has collided
  2277.                         hitCnt++;
  2278.                         Ammo[a]->Bullets[i].isActive = false;
  2279.  
  2280.                         DAMAGE dType = Ammo[a]->getDmgType();
  2281.                         int dmg      = Ammo[a]->getDmg();
  2282.  
  2283.                         if (target->applyDmg(dType,dmg))
  2284.                         {
  2285.                             // spawn new explosion
  2286.                             newExp(target->getAnchor());
  2287.  
  2288.                             // target is DEAD !!!
  2289.                             target->setSTATE(DEAD);                    
  2290.  
  2291.                             // BOOM SOUND
  2292.                         }
  2293.                     }
  2294.                 }
  2295.     bulletsHit += hitCnt;
  2296. };
  2297.  
  2298. // checks AI bullets for collision - most likely only with player sprite
  2299. void bullet_AI_Collision(CShip *target)
  2300. {
  2301.     int cnt = 0;
  2302.     bool hit = false;
  2303.     int hitCnt = 0;
  2304.  
  2305.     for (int a=0; a < MAX_GUNS_AI; a++)
  2306.         for (int i=0; i < MAX_BULLETS; i++)
  2307.             if (Ammo_AI[a]->Bullets[i].isActive == true)
  2308.                 {
  2309.                     POINT  pt1 = Ammo_AI[a]->Bullets[i].currPT;
  2310.                     int halfW = Ammo_AI[a]->getWidth()  / 2;
  2311.                     int halfH = Ammo_AI[a]->getHeight() / 2;
  2312.  
  2313.                     POINT center;
  2314.                     center.x = pt1.x + halfW;
  2315.                     center.y = pt1.y + halfH;
  2316.                     int radius1 = halfW;
  2317.  
  2318.                     // players location
  2319.                     POINT pt2 = target->getAnchor();
  2320.                     int radius2 = target->getWidth() * 0.4f;               
  2321.  
  2322.                     if ( circleCollision(center,radius1,pt2,radius2) )
  2323.                     {
  2324.                         // this bullet has collided
  2325.                         hitCnt++;
  2326.                         Ammo_AI[a]->Bullets[i].isActive = false;
  2327.  
  2328.                         DAMAGE dType = Ammo_AI[a]->getDmgType();
  2329.                         int dmg      = Ammo_AI[a]->getDmg();
  2330.  
  2331.                         if (target->applyDmg(dType,dmg))
  2332.                         {
  2333.                             // spawn new explosion
  2334.                             newExp(target->getAnchor());
  2335.  
  2336.                             // target is DEAD !!!
  2337.                             target->setSTATE(DEAD);                    
  2338.  
  2339.                             // BOOM SOUND
  2340.                         }
  2341.                     }
  2342.                 }
  2343.     bulletsHit += hitCnt;
  2344. };
  2345.  
  2346. void Init_Guns()
  2347. {
  2348.     // [5]
  2349.     Ammo[0] = new CProjectile(1,ENERGY,  14,RANGE_MED,  TEXT("./Media/Images/proj_blaster.png") ,30,30); // 24
  2350.     Ammo[1] = new CProjectile(2,ENERGY,  18,RANGE_LONG, TEXT("./Media/Images/proj_laser.bmp")   ,32,32); // 25
  2351.     Ammo[2] = new CProjectile(3,KINETIC, 12,RANGE_SHORT,TEXT("./Media/Images/cannon.png")       ,44,44); // 35
  2352.     Ammo[3] = new CProjectile(2,EXPLODE, 12,RANGE_LONG ,TEXT("./Media/Images/missile.png")      ,32,32); // 25
  2353.     Ammo[4] = new CProjectile(4,ENERGY,  10,RANGE_SHORT,TEXT("./Media/Images/proj_torpedo.bmp") ,32,32); // 25
  2354.     Ammo[3]->setupAnim(4,NORTH,4); // animated rocket frames
  2355.  
  2356.     for (int i=0;i < MAX_AMMO; i++)
  2357.         assert(Ammo[i]); // make sure all load successfully
  2358.  
  2359.     //                     reload cycl energy per shot
  2360.     Guns[0] = new CGuns(0, DELAY_SHORT, 1,TEXT("Blaster"));      // blaster
  2361.     Guns[1] = new CGuns(1, DELAY_SHORT, 2,TEXT("Laser"));        // laser
  2362.     Guns[2] = new CGuns(2, DELAY_MED,   3,TEXT("Cannon"));       // cannon
  2363.     Guns[3] = new CGuns(3, DELAY_LONG,  5,TEXT("Missile"));      // missile
  2364.     Guns[4] = new CGuns(4, DELAY_LONG,  5,TEXT("Torpedo"));      // photon torpedo
  2365.     for (int i=0;i < MAX_GUNS; i++)
  2366.         assert(Guns[i]); // make sure all load successfully
  2367.  
  2368.     //const int MAX_AI_GUNS;
  2369.     Ammo_AI[0] = new CProjectile(1,KINETIC,  9,RANGE_SHORT,TEXT("./Media/Images/mantabullet.png")  ,32,32); // 25
  2370.     Ammo_AI[1] = new CProjectile(2,KINETIC, 12,RANGE_LONG ,TEXT("./Media/Images/mantabullet.png")  ,32,32); // 25
  2371.     Guns_AI[0] = new CGuns(1, DELAY_MED, 2,TEXT("manta bullet")); // AI blasters
  2372.     Guns_AI[1] = new CGuns(2, DELAY_MED, 2,TEXT("boss bullet"));  // AI blasters x 3
  2373.     for (int i=0;i < MAX_GUNS_AI; i++)
  2374.     {
  2375.         assert(Guns_AI[i]); // make sure all load successfully
  2376.         assert(Ammo_AI[i]); // make sure all load successfully
  2377.     }
  2378.  
  2379. }
  2380.  
  2381. // performs basic FSM and then moves enemy ship
  2382. void EnemyAI()
  2383. {
  2384.     int GUN_RANGE, distance;
  2385.     DIRS chaseDIR, fleeDIR;
  2386.  
  2387.     // Enemy AI //
  2388.     for (int i=0; i < NUM_ENEMIES; i++)
  2389.         if (enemy[i]->getSTATE() != INACTIVE) // ignore the enemy if its INACTIVE
  2390.         {
  2391.             GUN_RANGE = Ammo[ enemy[i]->getAmmo() ]->getRange() * scalex; // 75% range in SYSTEM, 50% range in SPACE
  2392.  
  2393.             distance  = findDistance(enemy[i]->getAnchor(),player->getAnchor());
  2394.             chaseDIR  = getDirection(player->getAnchor()  ,enemy[i]->getAnchor()); // used to CHASE
  2395.             fleeDIR   = getDirection(enemy[i]->getAnchor(),player->getAnchor());   // used to FLEE
  2396.  
  2397.             // always move away if super close
  2398.             if (distance <= TOO_CLOSE)
  2399.             {
  2400.                 enemy[i]->setSpeed(0);
  2401.                 if (distance <= (TOO_CLOSE/2))
  2402.                 {
  2403.                     enemy[i]->setSTATE(FLEEING); // way too close, get away
  2404.                     enemy[i]->addSpeed(2);
  2405.                 }
  2406.             }
  2407.  
  2408.             switch ( enemy[i]->getSTATE() )
  2409.             {
  2410.             case FLEEING:
  2411.                 {
  2412.                     // flee until at a safe distance away
  2413.                     if (distance > (2*TOO_CLOSE))
  2414.                     { // no longer need to flee
  2415.                         enemy[i]->setSTATE(ACTIVE);
  2416.                     }
  2417.                     else
  2418.                     {   // FLEE                    
  2419.                         enemy[i]->addSpeed(1); // move towards MAX speed (caps at max)
  2420.  
  2421.                         // face player
  2422.                         enemy[i]->setFacing(fleeDIR);
  2423.  
  2424.                         if ((rand() % 100) < 10) // 10% chance for random 45 degree turns
  2425.                             enemy[i]->turn(rand() % 2);
  2426.                     }
  2427.  
  2428.                 }; break;
  2429.             case ACTIVE:        // Moving around normally
  2430.                 {
  2431.                     if ((rand() % 100) < 10) // 10% chance for random 45 degree turns
  2432.                         enemy[i]->turn(rand() % 2);
  2433.  
  2434.                     // random +/- speed
  2435.                     enemy[i]->addSpeed(1);
  2436.                     // caps at MAX speed, so no harm in this
  2437.  
  2438.                     // change state if target visible
  2439.                     if (distance <= SIGHT_RANGE)
  2440.                         enemy[i]->setSTATE(SEARCHING); // sees player on radar
  2441.  
  2442.                     if (distance <= GUN_RANGE)
  2443.                         enemy[i]->setSTATE(ATTACKING);
  2444.                 }; break;
  2445.             case SEARCHING:
  2446.                 {   // HEAD towards player - AI "Sees" the player on radar
  2447.                     enemy[i]->addSpeed(1); // move towards MAX speed (caps at max)
  2448.  
  2449.                     // face player
  2450.                     enemy[i]->setFacing(chaseDIR);                 
  2451.  
  2452.                     // change state if target visible
  2453.                     if (distance > SIGHT_RANGE)
  2454.                         enemy[i]->setSTATE(ACTIVE); // sees player on radar
  2455.                     if (distance <= GUN_RANGE)
  2456.                         enemy[i]->setSTATE(ATTACKING);
  2457.                 }; break;
  2458.             case ATTACKING:     // Attacking player
  2459.                 {
  2460.                     // make sure the target is still in range
  2461.                     if (distance > GUN_RANGE)
  2462.                     {
  2463.                         // unable to fire ... move first
  2464.                         enemy[i]->setSTATE(ACTIVE);
  2465.  
  2466.                         // this should make him head towards player
  2467.                         enemy[i]->setFacing(chaseDIR);
  2468.                         enemy[i]->addSpeed(2);
  2469.                     }
  2470.                     else
  2471.                     {   // close enough to fire
  2472.                         // see if ship has enough power to shoot, returns true if able to fire
  2473.                         // also checks if the gun is reloaded or not
  2474.                         if ( enemy[i]->canFire())
  2475.                         {  
  2476.                             // try to match players speed
  2477.                             //enemy[i]->setSpeed(player->getSpeed());
  2478.                             enemy[i]->setSpeed(0);  // stop moving and fire gun
  2479.  
  2480.                             // face player
  2481.                             enemy[i]->setFacing(chaseDIR);
  2482.                            
  2483.                             Ammo_AI[0]->spawnBullet(enemy[i]->getAnchor(),enemy[i]->getFacing());                      
  2484.                             enemyBullets++;
  2485.  
  2486.                             // SOUND :: enemies guns firing at your
  2487.                         }
  2488.                         else
  2489.                         {
  2490.                             int dir=rand()%2, times=(rand()%3+1);
  2491.                             for (int i=0; i < times;i++)
  2492.                                 enemy[i]->turn(dir);
  2493.                             //45-135 degree change one direction and move                          
  2494.                             enemy[i]->addSpeed(4);
  2495.                         }
  2496.                     } // distance
  2497.                 }; break; // CASE ..
  2498.             } // end of SWITCH()
  2499.  
  2500.             // perform the actual MOVE for enemy
  2501.             enemy[i]->doMove();
  2502.  
  2503.             // check boundaries
  2504.             if ( enemy[i]->checkBounds(0,0,GAMEWORLDWIDTH,GAMEWORLDHEIGHT) )           // BOUNDARIES CHECK
  2505.             {
  2506.                 // warp back to top left corner
  2507.                 enemy[i]->setX(300 + (rand() % 200)); // spawn point
  2508.                 enemy[i]->setY(100 + (rand() % 200));
  2509.                 enemy[i]->setFacing(SOUTH);
  2510.                 enemy[i]->setSpeed(1);
  2511.             }
  2512.         } // END ... Enemy AI code //
  2513.  
  2514. }; // end EnemyAI function //
  2515.  
  2516. // performs basic FSM and then moves enemy ship
  2517. void BossAI()
  2518. {
  2519.     // Thw ANIM will be beaks added on top --
  2520.  
  2521.     // died
  2522.     if (boss->getSTATE() == DEAD)
  2523.     {
  2524.         deaths++;
  2525.         if (deaths < lives)
  2526.         { // respawn, next color
  2527.             boss->setSTATE(ACTIVE);
  2528.             // create new boss
  2529.             respawnBoss();
  2530.  
  2531.             boss->setFrame(deaths);
  2532.             return;
  2533.         }
  2534.         else        // did boss just die? if so, make sure the planet is now "safe"
  2535.         {
  2536.             if (gameView == PLANET)
  2537.                 if ( clearedArea[CURR_MAP.system][CURR_MAP.planet] == false)
  2538.                      clearedArea[CURR_MAP.system][CURR_MAP.planet] = true;
  2539.             return; // either way, exit
  2540.         }
  2541.     }
  2542.  
  2543.     // not activated
  2544.     if (boss->getSTATE() == INACTIVE)
  2545.         return;
  2546.  
  2547. // Boss AI //
  2548.     int GUN_RANGE=RANGE_LONG, distance, SIGHT = RANGE_LONG;
  2549.     DIRS chaseDIR, fleeDIR;
  2550.  
  2551.     GUN_RANGE = Ammo[ boss->getAmmo() ]->getRange() * scalex; // 75% range in SYSTEM, 50% range in SPACE
  2552.     distance  = findDistance(boss->getAnchor(),player->getAnchor());
  2553.     chaseDIR  = getDirection(player->getAnchor()  ,boss->getAnchor()); // used to CHASE
  2554.     fleeDIR   = getDirection(boss->getAnchor(),player->getAnchor());   // used to FLEE
  2555.  
  2556.     // always move away if super close
  2557.     if (distance <= 300)
  2558.     {
  2559.         boss->setSTATE(FLEEING); // way too close, get away
  2560.         boss->setSpeed(2);
  2561.     };
  2562.     if (distance <= 200)
  2563.     {
  2564.         boss->setSTATE(ATTACKING); // way too close, just attack
  2565.         boss->setSpeed(0);
  2566.     } ;
  2567.  
  2568.     switch ( boss->getSTATE() )
  2569.     {
  2570.     case FLEEING:
  2571.         {
  2572.             // flee until at a safe distance away
  2573.             if (distance > 400)
  2574.             { // no longer need to flee
  2575.                 boss->setSTATE(ACTIVE);
  2576.             }
  2577.             else
  2578.             {   // FLEE                    
  2579.                 boss->addSpeed(1); // move towards MAX speed (caps at max)
  2580.  
  2581.                 // face player
  2582.                 boss->setFacing(fleeDIR);
  2583.  
  2584.                 if ((rand() % 100) < 1) // 10% chance for random 45 degree turns
  2585.                     boss->turn(rand() % 2);
  2586.             }
  2587.  
  2588.         }; break;
  2589.     case ACTIVE:        // Moving around normally
  2590.         {
  2591.             if ((rand() % 100) < 1) // 10% chance for random 45 degree turn
  2592.                 boss->turn(rand() % 2);
  2593.  
  2594.             // random +/- speed
  2595.             boss->addSpeed(1);
  2596.             // caps at MAX speed, so no harm in this
  2597.  
  2598.             // change state if target visible
  2599.             if (distance <= 1000)
  2600.                 boss->setSTATE(SEARCHING); // sees player on radar
  2601.  
  2602.             if (distance <= RANGE_LONG)
  2603.                 boss->setSTATE(ATTACKING);
  2604.         }; break;
  2605.     case SEARCHING:
  2606.         {   // HEAD towards player - AI "Sees" the player on radar
  2607.             boss->addSpeed(1); // move towards MAX speed (caps at max)
  2608.  
  2609.             // face player
  2610.             boss->setFacing(chaseDIR);                 
  2611.  
  2612.             // change state if target visible
  2613.             if (distance > SIGHT_RANGE)
  2614.                 boss->setSTATE(ACTIVE); // sees player on radar
  2615.             if (distance <= GUN_RANGE)
  2616.                 boss->setSTATE(ATTACKING);
  2617.         }; break;
  2618.     case ATTACKING:     // Attacking player
  2619.         {
  2620.             // make sure the target is still in range
  2621.             if (distance > RANGE_LONG)
  2622.             {
  2623.                 // unable to fire ... move first
  2624.                 boss->setSTATE(ACTIVE);
  2625.  
  2626.                 // this should make him head towards player
  2627.                 boss->setFacing(chaseDIR);
  2628.                 boss->addSpeed(2);
  2629.             }
  2630.             else
  2631.             {   // close enough to fire
  2632.                 // see if ship has enough power to shoot, returns true if able to fire
  2633.                 // also checks if the gun is reloaded or not
  2634.                 if ( boss->canFire() )
  2635.                 {  
  2636.                     // try to match players speed
  2637.                     //boss->setSpeed(player->getSpeed());
  2638.                     boss->setSpeed(0);  // stop moving and fire gun
  2639.  
  2640.                     // face player
  2641.                     boss->setFacing(chaseDIR);
  2642.  
  2643.                     DIRS dir1,dir2=chaseDIR,dir3;
  2644.                     switch(boss->getFacing())
  2645.                     {
  2646.                         case NORTH  : dir1=NW;    dir3=NE;   break; // dir1 = left, dir3=right
  2647.                         case NE     : dir1=NORTH; dir3=EAST; break;
  2648.                         case NW     : dir1=WEST;  dir3=NORTH;break;
  2649.                         case EAST   : dir1=NW;    dir3=SE;   break;
  2650.                         case WEST   : dir1=SW;    dir3=NW;   break;
  2651.                         case SOUTH  : dir1=SW;    dir3=SE;   break;
  2652.                         case SE     : dir1=EAST;  dir3=SOUTH;break;
  2653.                         case SW     : dir1=SOUTH; dir3=WEST; break;
  2654.                     };
  2655.  
  2656.                     POINT pt1,pt2=boss->getAnchor(),pt3;
  2657.                     pt1=pt2;
  2658.                     pt3=pt2;
  2659.                     switch(chaseDIR)
  2660.                     {
  2661.                         case NE:
  2662.                         case SW:
  2663.                             {
  2664.                                 pt1.x -= 64;
  2665.                                 pt3.x += 64;
  2666.  
  2667.                                 pt1.y -= 64;
  2668.                                 pt3.y += 64;
  2669.                             }; break;
  2670.  
  2671.                         case NW:
  2672.                         case SE:
  2673.                             {
  2674.                                 pt1.x += 64;
  2675.                                 pt3.x -= 64;
  2676.  
  2677.                                 pt1.y += 64;
  2678.                                 pt3.y -= 64;
  2679.                             }; break;
  2680.  
  2681.                         case WEST:
  2682.                         case EAST:
  2683.                             {
  2684.                                 pt1.x -= 64;
  2685.                                 pt3.x += 64;
  2686.                             }; break;
  2687.  
  2688.                         case NORTH:
  2689.                         case SOUTH:
  2690.                             {
  2691.                                 pt1.y -= 64;
  2692.                                 pt3.y += 64;
  2693.                             }; break;
  2694.                     }
  2695.                        
  2696.  
  2697.                     // fire (3) bullet towards player
  2698.                     Ammo_AI[1]->spawnBullet( pt1, dir3 ); // towards right
  2699.                     Ammo_AI[1]->spawnBullet( pt2, dir2);  // ahead     
  2700.                     Ammo_AI[1]->spawnBullet( pt3, dir1);  // towards left
  2701.                     enemyBullets+=3;
  2702.                     // SOUND :: enemies guns firing at your
  2703.                 }
  2704. /*              else
  2705.                 {
  2706.                     int dir=rand()%2, times=(rand()%3+1);
  2707.                     for (int i=0; i < times;i++)
  2708.                         boss->turn(dir);
  2709.                     //45-135 degree change one direction and move                          
  2710.                     boss->addSpeed(2);
  2711.                 }*/
  2712.             } // distance
  2713.         }; break; // CASE ..
  2714.     } // end of SWITCH()
  2715.  
  2716.         // perform the actual MOVE for enemy
  2717.         boss->doMove(); // which doesnt animate the body
  2718.         beeks->nextFrame();// animate the beeks tho
  2719.  
  2720.         // check boundaries
  2721.         if (boss->getX() < 0)
  2722.         {
  2723.             boss->setX(64);
  2724.             boss->setSpeed(0);
  2725.         };
  2726.         if (boss->getX() > (GAMEWORLDWIDTH-128))
  2727.         {
  2728.             boss->setX(0); // ha ha -- GAMEWORLDWIDTH-128);
  2729.             boss->setSpeed(0);
  2730.         };
  2731.         if (boss->getY() < 0)
  2732.         {
  2733.             boss->setY(1);
  2734.             boss->setSpeed(0);
  2735.         };
  2736.         if (boss->getY() > (GAMEWORLDHEIGHT-128))
  2737.         {
  2738.             boss->setY(0); // GAMEWORLDHEIGHT-128);
  2739.             boss->setSpeed(0);
  2740.         };
  2741. }; // end EnemyAI function //
  2742.  
  2743. void moveDebris()
  2744. {
  2745.     // move Debris (current view only)
  2746.     switch(gameView)
  2747.     {
  2748.         case SPACE:
  2749.             {
  2750.             for (int i=0; i < DEBRIS_AMT_SPACE; i++)
  2751.                 debris_space[i]->doMove(); // moves and rotates
  2752.             }; break;
  2753.         case SYSTEM:
  2754.             {
  2755.             for (int i=0; i < DEBRIS_AMT_SYSTEM; i++)
  2756.                 debris_system[i]->doMove(); // rotates only
  2757.             }; break;
  2758.         case PLANET:
  2759.             {
  2760.             for (int i=0; i < DEBRIS_AMT_PLANET; i++)
  2761.                 debris_planet[i]->doMove(); // static
  2762.             }; break;
  2763.     }
  2764. }
  2765.  
  2766. // check for collisions with moving debris ... and applies the effect there of
  2767. void checkDebris()
  2768. {
  2769.     //track recent collision
  2770.     if (gameView == SPACE)  lastColl.space   = currColl.space;
  2771.     if (gameView == SYSTEM) lastColl.system  = currColl.system;
  2772.     if (gameView == PLANET) lastColl.surface = currColl.surface;
  2773.  
  2774.     // check for player vs. debris collisions      
  2775.     int temp = debrisCollision(player);
  2776.     if (gameView == SPACE)  currColl.space  = temp; // resets to (0) if no collision
  2777.     if (gameView == SYSTEM) currColl.system = temp;
  2778.     if (gameView == PLANET) currColl.surface = temp;
  2779.  
  2780.     // ignore mid-air collisions on planets (clouds dont hurt)
  2781.     if (temp > -1)
  2782.         switch(gameView)
  2783.         {
  2784.             case PLANET:
  2785.                 {
  2786.                     lastColl.surface = temp;
  2787.                 };  break; // ignore collisions on planets         
  2788.             case SYSTEM:
  2789.                 {
  2790.                     //if its a new collision, apply damage
  2791.                     if (lastColl.system != temp)
  2792.                         player->applyDmg(ENERGY,1);
  2793.  
  2794.                     // save collision
  2795.                     lastColl.system = temp;
  2796.                 }; break;
  2797.             case SPACE:
  2798.                 {
  2799.                     //if its a new collision, apply damage
  2800.                     if (lastColl.system != temp)
  2801.                         player->applyDmg(ENERGY,1);
  2802.  
  2803.                     // save collision
  2804.                     lastColl.system =  temp;
  2805.                 }; break;
  2806.         }
  2807.         // we can apply physics for collision if want to -- got the formula already --
  2808.         // sure, if shields deflect a large collision - you bounce away        
  2809. }
  2810.  
  2811. void createDebris()
  2812. {
  2813.     // load the moving objects (asteroids and such)
  2814.     for (int i=0;i < DEBRIS_AMT_SPACE;i++)
  2815.     {
  2816.         debris_space[i] = new CDebris(120,110,TEXT("./Media/Images/debris_space.png"),DEBRIS_SPRITES_SPACE,GAMEWORLDWIDTH,GAMEWORLDHEIGHT);    
  2817.         hitDebris.space[i] = false;
  2818.         assert(debris_space[i]);
  2819.     }
  2820.     for (int i=0;i < DEBRIS_AMT_SYSTEM;i++)
  2821.     {
  2822.         debris_system[i] = new CDebris(120,110,TEXT("./Media/Images/debris_system.png"),DEBRIS_SPRITES_SYSTEM,GAMEWORLDWIDTH,GAMEWORLDHEIGHT);     
  2823.         hitDebris.system[i] = false;
  2824.         assert(debris_system[i]);
  2825.     }
  2826.     for (int i=0;i < DEBRIS_AMT_PLANET;i++)
  2827.     {
  2828.         debris_planet[i] = new CDebris(120,110,TEXT("./Media/Images/debris_surface.png"),DEBRIS_SPRITES_PLANET,GAMEWORLDWIDTH,GAMEWORLDHEIGHT);    
  2829.         hitDebris.surface[i] = false;
  2830.         assert(debris_planet[i]);
  2831.     }
  2832. }
  2833.  
  2834. void drawBars()
  2835. {
  2836.     // draw enemy health bars?
  2837.     // scale the bar per the gameView
  2838.     int sx = 32 / scalex;
  2839.     int sy =  6 * scaley;
  2840.     POINT dest;
  2841.     POINT curr;
  2842.  
  2843.     // Draw Players Health Bars
  2844.     if ((player->getSTATE() != DYING) && (player->getSTATE() != DEAD))
  2845.     {
  2846.         dest = player->getAnchor();
  2847.         dest.x -= ScrollX;  // + sx
  2848.         dest.y -= ScrollY;
  2849.         dest.y += (player->getHeight()/2) * scaley;
  2850.  
  2851.         drawBar(dest.x,dest.y, player->getCur(LOC_SHIELD), player->getMax(LOC_SHIELD), 1);      // SHIELDS
  2852.         dest.y += sy;
  2853.         drawBar(dest.x,dest.y, player->getCur(LOC_ARMOR) , player->getMax(LOC_ARMOR),  2);      // ARMOR
  2854.         dest.y += sy;
  2855.         drawBar(dest.x,dest.y, player->getCur(LOC_HULL)  , player->getMax(LOC_HULL),   5);      // HULL
  2856.         dest.y += sy;
  2857.         drawBar(dest.x,dest.y, player->getSolar()        , player->getSolarMax(),      6);      // solar power
  2858.         dest.y += sy;
  2859.         if (player->isLoaded())                                                                 // gun reload
  2860.             drawBar(dest.x,dest.y, 1,1,3);
  2861.         else
  2862.             drawBar(dest.x,dest.y, player->getGunDelay()     , player->weapon->getReload(),3);
  2863.     }
  2864.  
  2865.     for (int i=0; i < NUM_ENEMIES; i++)
  2866.         if ( (enemy[i]->getSTATE() != DEAD) && (enemy[i]->getSTATE() != INACTIVE) )
  2867.             {
  2868.                 curr = enemy[i]->getAnchor();
  2869.                 curr.x -= ScrollX; // convert to window coord (not game coord)
  2870.                 curr.y -= ScrollY;
  2871.  
  2872.                 dest.x = enemy[i]->getX() - ScrollX;
  2873.                 dest.y = enemy[i]->getY() - ScrollY + ((enemy[i]->getHeight() / 2) *scaley);
  2874.  
  2875.                 // on-screen ?
  2876.                 if ((curr.x >= 0) && (curr.x <= SCREEN_WIDTH) && (curr.y >= 0) && (curr.y <= SCREEN_HEIGHT))
  2877.                 { // should be visible on screen - so draw health bars
  2878.                     drawBar(dest.x,dest.y, enemy[i]->getHP(),      enemy[i]->getMaxHP(),            5);
  2879.                     dest.y += sy;
  2880.                     drawBar(dest.x,dest.y, enemy[i]->getSolar(),   enemy[i]->getSolarMax(),         6); // Power
  2881.                     dest.y += sy;
  2882.                     if ( enemy[i]->isLoaded() )
  2883.                         drawBar(dest.x,dest.y, 1, 1, 3);
  2884.                     else
  2885.                         drawBar(dest.x,dest.y, enemy[i]->getGunDelay(),enemy[i]->weapon->getReload(),   3);
  2886.                 }
  2887.             }
  2888. }
  2889.  
  2890. void DrawBG(IDirect3DSurface9 *pSource)
  2891. {
  2892.     RECT r1 = { ScrollX, ScrollY, ScrollX+SCREEN_WIDTH, ScrollY+SCREEN_HEIGHT };
  2893.     RECT r2 = { 0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1 };
  2894.    
  2895.     d3ddev->StretchRect(pSource,  &r1, backbuffer, &r2, D3DTEXF_NONE);
  2896. };
  2897.  
  2898. void animExp()
  2899. {
  2900.     for (int i=0;i < MAX_EXPLOSIONS;i++)
  2901.         if (activeEXP[i] == true)
  2902.             if (explosion[i]->nextFrame() == 1)
  2903.             { // animation complete
  2904.                 activeEXP[i] = false;
  2905.  
  2906.                 delete explosion[i];
  2907.                 // does that destroy it safely ?
  2908.             }
  2909. }
  2910. //
  2911. void newExp(POINT dest)
  2912. {
  2913.     // find the next available one to use
  2914.     int i=0;
  2915.     while ((activeEXP[i] == true) && (i < MAX_EXPLOSIONS))
  2916.         i++;
  2917.  
  2918.     if (i >= MAX_EXPLOSIONS)
  2919.         return; // quit
  2920.  
  2921.     // make it ACTIVE duh
  2922.     activeEXP[i] = true;
  2923.  
  2924.     int Height=120;
  2925.     int Width =120;
  2926.     int Frames=12;
  2927.     LPCSTR Filename = TEXT("./Media/Images/exp_red.png");
  2928.     explosion[i] = new CSprite(dest.x,dest.y,Height, Width, Filename);
  2929.     explosion[i]->setupAnim(Frames,EAST,4);
  2930.     explosion[i]->setSTATE(ACTIVE);
  2931.  
  2932.     mp3->OpenFile(".\\Media\\Sound\\explosion.mp3",800, 0, 0);
  2933.     mp3->Play();
  2934.  
  2935.   //const int MAX_EXPLOSIONS = 30;
  2936.   //CSprite *explosion[MAX_EXPLOSIONS];
  2937.   //bool activeEXP[MAX_EXPLOSIONS];
  2938. }
  2939.  
  2940. void drawExp()
  2941. {
  2942.     for (int i=0;i < MAX_EXPLOSIONS;i++)
  2943.         if (activeEXP[i] == true)
  2944.             DrawSprite( explosion[i]->getX()-ScrollX,explosion[i]->getY()-ScrollY,
  2945.                         explosion[i]->getWidth(),explosion[i]->getHeight(),
  2946.                         scalex, scaley, explosion[i]->getAngle(),
  2947.                         D3DCOLOR_XRGB(255,255,255),
  2948.                         explosion[i]->getImage(),
  2949.                         &explosion[i]->getRect(),
  2950.                         d3ddev,false);
  2951. }
  2952.  
  2953.  
  2954. // sets up random enemy drones
  2955. void createDrones()
  2956. {
  2957.     for (int i=0; i < NUM_ENEMIES; i++)
  2958.     {
  2959.         int aiGun = 0;// Guns[5] = AI Blasters
  2960.         POINT dest = {rand()%2000+24,rand()%2000+24};
  2961.         enemy[i] = new CShip(dest.x,dest.y,64,64,TEXT("./Media/Images/manta.png"),2+(rand()%4),2+(rand()%4),10,30,Guns_AI[aiGun],aiGun,0,rand()%4+1,rand()%2 +1);  
  2962.         enemy[i]->setupAnim(3,NORTH,3); // sprites per anim, initially heading, sprites per row on sheet   
  2963.         enemy[i]->setFrame(0);
  2964.         enemy[i]->setSTATE(INACTIVE);  
  2965.         enemy[i]->setBorder(0,0,GAMEWORLDWIDTH - 16,GAMEWORLDHEIGHT - 16); // set border to game window
  2966.         assert(enemy[i]);
  2967.     }
  2968.  
  2969.     int Shield = 0;
  2970.     int Armor  = rand()%6 +5; // 6-10
  2971.     int Hull   = rand()%5 +8; // 8-12
  2972.     int Speed  = 2;
  2973.     int bossGun = 1;// BOSS GUN
  2974.     POINT dest = {rand()%800+1200,rand()%800+1200};
  2975.    
  2976.     boss = new CShip(900,900,256,256,TEXT("./Media/Images/bens-jellyboss.png"),0,Speed,40,40,Guns_AI[bossGun],bossGun,Shield,Armor,Hull);  
  2977.     boss->setupAnim(8,EAST,4); // sprites per anim, initially heading, sprites per row on sheet
  2978.     boss->setDelay(6);
  2979.     boss->setSTATE(ACTIVE);
  2980.     boss->setBorder(0,0,GAMEWORLDWIDTH - 16,GAMEWORLDHEIGHT - 16); // set border to game window
  2981.  
  2982.     boss->setFrame(0);
  2983.     boss->setLastFrame(1);
  2984.     boss->setAnimate(false);
  2985.  
  2986.     beeks = new CSprite(900,900,256,256,"./Media/Images/jelly-beeks.png");
  2987.     beeks->setupAnim(16,EAST,4);
  2988.     beeks->setDelay(5);
  2989.     beeks->setFrame(0);
  2990.  
  2991.     assert(boss);
  2992. }
  2993.  
  2994. void respawnDrones(int MAX = NUM_ENEMIES)
  2995. {
  2996.     // call this when you enter a new system or map
  2997.  
  2998.     if (MAX < NUM_ENEMIES)
  2999.         for (int i=MAX; i < NUM_ENEMIES; i++)
  3000.             enemy[i]->setSTATE(INACTIVE); // be sure the others are ignored then
  3001.  
  3002.     for (int i=0; i < MAX; i++)
  3003.     {
  3004.         POINT dest = {rand()%1200+800,rand()%1200+800};
  3005.         int Shield = 0;
  3006.         int Armor  = rand()%4 +1;   // 1-4
  3007.         int Hull   = rand()%2 +1; // 1-2
  3008.         int Speed  = 9 - (Armor + Hull);
  3009.         int Angle  = rand() % 360;
  3010.  
  3011.         enemy[i]->setFrame(0);
  3012.         enemy[i]->setSTATE(ACTIVE);
  3013.         enemy[i]->setPT(dest);
  3014.         enemy[i]->setMaxSpeed(Speed);
  3015.         enemy[i]->setSpeed(Speed);
  3016.         enemy[i]->setAngle(Angle);
  3017.         enemy[i]->setupShip(Shield,Armor,Hull);
  3018.     }
  3019. }
  3020.  
  3021. void respawnBoss()
  3022. {
  3023. //spawns boss on far side of map
  3024. //when boss is destroyed this zone becomes clear
  3025. //  areacleared[CURR_MAP.system][CURR_MAP.planet] = true;
  3026.         POINT dest = {rand()%1200+800,rand()%1200+800};
  3027.         int Shield = 0;
  3028.         int Armor  = rand()%6 + 5; // 5-10
  3029.         int Hull   = rand()%5 + 8; // 8-12
  3030.         int Speed  = 2;
  3031.         int Angle  = rand() % 360;
  3032.  
  3033.         boss->setFrame(deaths);
  3034.         boss->setDelay(16);
  3035.         boss->setPT(dest);     
  3036.         boss->setSpeed(Speed);             
  3037.         boss->setAngle(Angle);
  3038.         boss->setSTATE(ACTIVE);
  3039.         boss->setupShip(Shield,Armor,Hull);
  3040. };
  3041.  
  3042. POINT offsetPT(POINT pt1, int Width, int Height,DIRS Facing)
  3043. {
  3044.         POINT dPT = pt1;
  3045.         int halfW = Width  / 2 * scalex;
  3046.         int halfH = Height / 2 * scaley;
  3047.          DIRS dir = Facing;
  3048.  
  3049.         if ( (dir == NORTH) || (dir == NE) || (dir == NW))  dPT.y -= halfH;
  3050.         if ( (dir == SOUTH) || (dir == SE) || (dir == SW))  dPT.y += halfH;
  3051.         if ( (dir == WEST)  || (dir == SW) || (dir == NW))  dPT.x -= halfW;
  3052.         if ( (dir == EAST)  || (dir == SE) || (dir == NE))  dPT.x += halfW;
  3053.  
  3054.         return dPT;
  3055. }