home *** CD-ROM | disk | FTP | other *** search
/ Revista do CD-ROM 123 / cdrom123.iso / edu / tux / Tuxtype2-1.5.3-installer.exe / src / laser.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-01-21  |  21.1 KB  |  995 lines

  1. /***************************************************************************
  2.  -  file: laser.c
  3.  -  description: a modification of TuxMath for typing :)
  4.                             -------------------
  5.     begin                : 
  6.     copyright            : Bill Kendrick (C) 2002
  7.                            Jesse Andrews (C) 2003
  8.     email                : tuxtype-dev@tux4kids.net
  9. ***************************************************************************/
  10.  
  11. /***************************************************************************
  12. *                                                                         *
  13. *   This program is free software; you can redistribute it and/or modify  *
  14. *   it under the terms of the GNU General Public License as published by  *
  15. *   the Free Software Foundation; either version 2 of the License, or     *
  16. *   (at your option) any later version.                                   *
  17. *                                                                         *
  18. ***************************************************************************/
  19.  
  20. #include "globals.h"
  21. #include "funcs.h"
  22. #include "laser.h"
  23.  
  24. sprite * shield;
  25. SDL_Surface * images[NUM_IMAGES];
  26. Mix_Chunk * sounds[NUM_SOUNDS];
  27. Mix_Music * musics[NUM_MUSICS];
  28. SDL_Surface * bkgd;
  29.  
  30. /* --- unload all media --- */
  31. void laser_unload_data(void) {
  32.     int i;
  33.  
  34.     for (i = 0; i < NUM_IMAGES; i++)
  35.         SDL_FreeSurface(images[i]);
  36.  
  37.     if (sys_sound) {
  38.         for (i = 0; i < NUM_SOUNDS; i++)
  39.             Mix_FreeChunk(sounds[i]);
  40.         for (i = 0; i < NUM_MUSICS; i++)
  41.             Mix_FreeMusic(musics[i]);
  42.     }
  43.  
  44.     FreeSprite(shield);
  45.  
  46.     pause_unload_media();
  47.  
  48.     for ( i=1; i<255; i++ )
  49.         SDL_FreeSurface( letters[i] );
  50.  
  51.     TTF_CloseFont(font);
  52. }
  53.  
  54. /* --- Load all media --- */
  55. void laser_load_data(void) {
  56.     int i;
  57.  
  58.     font = LoadFont( ttf_font, 32);
  59.  
  60.     /* Load images: */
  61.     for (i = 0; i < NUM_IMAGES; i++) 
  62.         images[i] = LoadImage(image_filenames[i], IMG_ALPHA);
  63.  
  64.     shield = LoadSprite( "cities/shield", IMG_ALPHA );
  65.  
  66.     if (sys_sound) {
  67.         for (i = 0; i < NUM_SOUNDS; i++)
  68.             sounds[i] = LoadSound(sound_filenames[i]);
  69.  
  70.         for (i = 0; i < NUM_MUSICS; i++)
  71.             musics[i] = LoadMusic(music_filenames[i]);
  72.     }
  73.  
  74.     pause_load_media();
  75.  
  76.     for (i=1; i<255; i++) {
  77.             unsigned char t[2]=" ";
  78.             t[0]=i;
  79.             letters[i] = black_outline( t, font, &white );
  80.         }
  81. }
  82.  
  83.  
  84. #define FPS (1000 / 15)   /* 15 fps max */
  85. #define CITY_EXPL_START 3 * 5  /* Must be mult. of 5 (number of expl frames) */
  86. #define COMET_EXPL_START 2 * 2 /* Must be mult. of 2 (number of expl frames) */
  87. #define ANIM_FRAME_START 4 * 2 /* Must be mult. of 2 (number of tux frames) */
  88. #define GAMEOVER_COUNTER_START 75
  89. #define LEVEL_START_WAIT_START 20
  90. #define LASER_START 5
  91. #define NUM_ANS 8
  92.  
  93. /* Local (to game.c) 'globals': */
  94.  
  95. int wave, speed, score, pre_wave_score, num_attackers, distanceMoved;
  96. unsigned char ans[NUM_ANS];
  97. int ans_num;
  98.  
  99. comet_type comets[MAX_COMETS];
  100. city_type cities[NUM_CITIES];
  101. laser_type laser;
  102.  
  103. /* Local function prototypes: */
  104.  
  105. void laser_reset_level(int DIF_LEVEL);
  106. void laser_add_comet(int DIF_LEVEL);
  107. void laser_draw_numbers(unsigned char * str, int x);
  108. void laser_draw_line(int x1, int y1, int x2, int y2, int r, int g, int b);
  109. void laser_putpixel(SDL_Surface * surface, int x, int y, Uint32 pixel);
  110. void laser_draw_console_image(int i);
  111. void laser_draw_let(unsigned char c, int x, int y);
  112. void laser_add_score(int inc);
  113.  
  114. /* --- MAIN GAME FUNCTION!!! --- */
  115.  
  116. int laser_game(int DIF_LEVEL)
  117. {
  118.     int i, img, done, quit, frame, lowest, lowest_y, 
  119.         tux_img, old_tux_img, tux_pressing, tux_anim, tux_anim_frame,
  120.         tux_same_counter, level_start_wait, num_cities_alive,
  121.         num_comets_alive, paused, picked_comet, 
  122.         gameover;
  123.  
  124.     SDL_Event event;
  125.     Uint32    last_time, now_time;
  126.     SDLKey    key;
  127.     SDL_Rect  src, dest;
  128.     unsigned char      str[64];
  129.  
  130.     LOG( "starting Comet Zap game\n" );
  131.     DOUT( DIF_LEVEL );
  132.  
  133.     SDL_ShowCursor(0);
  134.     laser_load_data();
  135.  
  136.     /* Clear window: */
  137.   
  138.     SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
  139.     SDL_Flip(screen);
  140.  
  141.     /* --- MAIN GAME LOOP: --- */
  142.  
  143.     done = 0;
  144.     quit = 0;
  145.   
  146.     /* Prepare to start the game: */
  147.   
  148.     wave = 1;
  149.     score = 0;
  150.     gameover = 0;
  151.     level_start_wait = LEVEL_START_WAIT_START;
  152.  
  153.     
  154.     /* (Create and position cities) */
  155.   
  156.     for (i = 0; i < NUM_CITIES; i++) {
  157.         cities[i].alive = 1;
  158.         cities[i].expl = 0;
  159.         cities[i].shields = 1;
  160.  
  161.         if (NUM_CITIES % 2 == 0) {
  162.             /* Left vs. Right - makes room for Tux and the console */
  163.  
  164.             if (i < NUM_CITIES / 2) 
  165.                 cities[i].x = (((screen->w / (NUM_CITIES + 1)) * i) + ((images[IMG_CITY_BLUE] -> w) / 2));
  166.             else
  167.                 cities[i].x = (screen->w - ((((screen->w / (NUM_CITIES + 1)) * (i - (NUM_CITIES / 2)) + ((images[IMG_CITY_BLUE] -> w) / 2)))));
  168.         } else {
  169.             /* put them in order across the bottom of     *
  170.              * the screen so we can do word's in order!!! */
  171.             cities[i].x = i*screen->w / (NUM_CITIES) + images[IMG_CITY_BLUE]->w/2;
  172.         }
  173.     }
  174.  
  175.     num_cities_alive = NUM_CITIES;
  176.     num_comets_alive = 0;
  177.  
  178.  
  179.     /* (Clear laser) */
  180.  
  181.     laser.alive = 0;
  182.  
  183.   
  184.     /* Reset remaining stuff: */
  185.  
  186.     bkgd = NULL;
  187.     laser_reset_level(DIF_LEVEL);
  188.   
  189.     /* --- MAIN GAME LOOP!!! --- */
  190.   
  191.     frame = 0;
  192.     paused = 0;
  193.     picked_comet = -1;
  194.     tux_img = IMG_TUX_RELAX1;
  195.     tux_anim = -1;
  196.     tux_anim_frame = 0;
  197.     tux_same_counter = 0;
  198.     ans_num = 0;
  199.  
  200.     audioMusicPlay(musics[MUS_GAME + int_rand(0,3)], 0);
  201.  
  202.     do {
  203.  
  204.         frame++;
  205.         last_time = SDL_GetTicks();
  206.  
  207.         old_tux_img = tux_img;
  208.         tux_pressing = 0;
  209.  
  210.         /* Handle any incoming events: */
  211.      
  212.         while (SDL_PollEvent(&event) > 0) {
  213.  
  214.             if (event.type == SDL_QUIT) {
  215.                 /* Window close event - quit! */
  216.                 exit(0);
  217.           
  218.             } else if (event.type == SDL_KEYDOWN) {
  219.  
  220.                 key = event.key.keysym.sym;
  221.           
  222.                 if (key == SDLK_F11)
  223.                     SDL_SaveBMP( screen, "laser.bmp");
  224.  
  225.                 if (key == SDLK_ESCAPE)
  226.                     paused = 1;
  227.  
  228.                 /* --- eat other keys until level wait has passed --- */ 
  229.                 if (level_start_wait > 0) 
  230.                     key = SDLK_UNKNOWN;
  231.                 
  232.                 if ((event.key.keysym.unicode & 0xff)>31) {
  233.                     ans[ans_num++] = KEYMAP[event.key.keysym.unicode & 0xff];
  234.                     tux_pressing ++;
  235.                 }
  236.             }
  237.         }
  238.       
  239.       
  240.         /* Handle answer: */
  241.  
  242.         for (;ans_num>0;ans_num--) {
  243.  
  244.             /*  Pick the lowest comet which has the right answer: */
  245.     
  246.             lowest_y = 0;
  247.             lowest = -1;
  248.     
  249.             for (i = 0; i < MAX_COMETS; i++)
  250.                 if (comets[i].alive && comets[i].expl == 0 && 
  251.                     KEYMAP[comets[i].ch] == ans[ans_num-1] && comets[i].y > lowest_y) {
  252.                     lowest = i;
  253.                     lowest_y = comets[i].y;
  254.                 }
  255.     
  256.     
  257.             /* If there was an comet with this answer, destroy it! */
  258.     
  259.             if (lowest != -1) {
  260.  
  261.                 /* Destroy comet: */
  262.           
  263.                 comets[lowest].expl = COMET_EXPL_START;
  264.         
  265.                 /* Fire laser: */
  266.  
  267.                 laser.alive = LASER_START;
  268.  
  269.                 /* this is a hack so drawing to the center of the screen works */
  270.                 if (abs(comets[lowest].x - screen->w/2) < 10) {
  271.                     laser.x1 = screen->w / 2;
  272.                     laser.y1 = screen->h;
  273.         
  274.                     laser.x2 = laser.x1;
  275.                     laser.y2 = comets[lowest].y;
  276.                 } else {
  277.                     laser.x1 = screen->w / 2;
  278.                     laser.y1 = screen->h;
  279.         
  280.                     laser.x2 = comets[lowest].x;
  281.                     laser.y2 = comets[lowest].y;
  282.                 }
  283.         
  284.                 playsound(sounds[SND_LASER]);
  285.         
  286.                 /* 50% of the time.. */
  287.         
  288.                 if (int_rand(0,2) == 0) {
  289.  
  290.                     /* ... pick an animation to play: */ 
  291.                     if (int_rand(0,2) == 0)
  292.                         tux_anim = IMG_TUX_YES1;
  293.                     else
  294.                         tux_anim = IMG_TUX_YAY1;
  295.             
  296.                     tux_anim_frame = ANIM_FRAME_START;
  297.                 }
  298.  
  299.                 /* Increment score: */
  300.  
  301.                 laser_add_score( (DIF_LEVEL+1) * 5 * ((screen->h - comets[lowest].y)/20 ));
  302.  
  303.             } else {
  304.  
  305.                 /* Didn't hit anything! */
  306.         
  307.                 playsound(sounds[SND_BUZZ]);
  308.         
  309.                 if (int_rand(0,2)==0)
  310.                     tux_img = IMG_TUX_DRAT;
  311.                 else
  312.                     tux_img = IMG_TUX_YIPE;
  313.  
  314.                 laser_add_score( -25 * wave);
  315.             }
  316.         }
  317.  
  318.       
  319.         /* Handle start-wait countdown: */
  320.       
  321.         if (level_start_wait > 0) {
  322.  
  323.             level_start_wait--;
  324.       
  325.             if (level_start_wait > LEVEL_START_WAIT_START / 4)
  326.                 tux_img = IMG_TUX_RELAX1;
  327.             else if (level_start_wait > 0)
  328.                 tux_img = IMG_TUX_RELAX2;
  329.             else
  330.                 tux_img = IMG_TUX_SIT;
  331.       
  332.             if (level_start_wait == LEVEL_START_WAIT_START / 4)
  333.                 playsound(sounds[SND_ALARM]);
  334.         }
  335.  
  336.       
  337.         /* If Tux pressed a button, pick a new (different!) stance: */
  338.       
  339.         if (tux_pressing) {
  340.             while (tux_img == old_tux_img)
  341.                 tux_img = IMG_TUX_CONSOLE1 + int_rand(0,3);
  342.  
  343.             playsound(sounds[SND_CLICK]);
  344.         }
  345.       
  346.       
  347.         /* If Tux is being animated, show the animation: */
  348.  
  349.         if (tux_anim != -1) {
  350.             tux_anim_frame--;
  351.  
  352.             if (tux_anim_frame < 0)
  353.                 tux_anim = -1;
  354.             else
  355.                 tux_img = tux_anim + 1 - (tux_anim_frame / (ANIM_FRAME_START / 2));
  356.         }
  357.  
  358.  
  359.         /* Reset Tux to sitting if he's been doing nothing for a while: */
  360.  
  361.         if (old_tux_img == tux_img) {
  362.             tux_same_counter++;
  363.  
  364.             if (tux_same_counter >= 20)
  365.                 old_tux_img = tux_img = IMG_TUX_SIT;
  366.             if (tux_same_counter >= 60)
  367.                 old_tux_img = tux_img = IMG_TUX_RELAX1;
  368.         } else
  369.             tux_same_counter = 0;
  370.  
  371.  
  372.         /* Handle comets: */
  373.      
  374.         num_comets_alive = 0;
  375.  
  376.         distanceMoved += speed;
  377.       
  378.         for (i = 0; i < MAX_COMETS; i++) {
  379.             if (comets[i].alive) {
  380.  
  381.                 num_comets_alive++;
  382.  
  383.                 comets[i].x = comets[i].x + 0;
  384.                 comets[i].y = comets[i].y + speed;
  385.           
  386.                 if (comets[i].y >= (screen->h - images[IMG_CITY_BLUE]->h) && comets[i].expl == 0) {
  387.  
  388.                     /* Disable shields or destroy city: */
  389.               
  390.                     if (cities[comets[i].city].shields) {
  391.                         cities[comets[i].city].shields = 0;
  392.                         playsound(sounds[SND_SHIELDSDOWN]);
  393.                         laser_add_score(-500 * (DIF_LEVEL+1));
  394.                     } else {
  395.                         cities[comets[i].city].expl = CITY_EXPL_START;
  396.                         playsound(sounds[SND_EXPLOSION]);
  397.                         laser_add_score(-1000 * (DIF_LEVEL+1));
  398.                     }
  399.  
  400.                     tux_anim = IMG_TUX_FIST1;
  401.                     tux_anim_frame = ANIM_FRAME_START;
  402.  
  403.                     /* Destroy comet: */
  404.  
  405.                     comets[i].expl = COMET_EXPL_START;
  406.                 }
  407.  
  408.                 /* Handle comet explosion animation: */
  409.  
  410.                 if (comets[i].expl != 0) {
  411.                     comets[i].expl--;
  412.  
  413.                     if (comets[i].expl == 0)
  414.                         comets[i].alive = 0;
  415.                 }
  416.             }
  417.         }
  418.  
  419.  
  420.         /* Handle laser: */
  421.  
  422.         if (laser.alive > 0)
  423.             laser.alive--;
  424.      
  425.         /* Comet time! */
  426.  
  427.         if (level_start_wait == 0 && (frame % 5) == 0 && gameover == 0) {
  428.             if (num_attackers > 0) {
  429.  
  430.                 /* More comets to add during this wave! */
  431.         
  432.                 if ((num_comets_alive < 2 || int_rand(0,4) == 0) && distanceMoved > 40) {
  433.                     distanceMoved = 0;
  434.                     laser_add_comet(DIF_LEVEL);
  435.                     num_attackers--;
  436.                 }
  437.             } else {
  438.                 if (num_comets_alive == 0) {
  439.  
  440.                     /* Time for the next wave! */
  441.  
  442.                     /* FIXME: End of level stuff goes here */
  443.  
  444.                     if (num_cities_alive > 0) {
  445.  
  446.                         /* Go on to the next wave: */
  447.                         wave++;
  448.                         laser_reset_level(DIF_LEVEL);
  449.  
  450.                     } else {
  451.  
  452.                         /* No more cities!  Game over! */
  453.                         gameover = GAMEOVER_COUNTER_START;
  454.                     }
  455.                 }
  456.             }
  457.         }
  458.  
  459.  
  460.         /* Handle cities: */
  461.      
  462.         num_cities_alive = 0;
  463.  
  464.         for (i = 0; i < NUM_CITIES; i++) 
  465.             if (cities[i].alive) {
  466.  
  467.                 num_cities_alive++;
  468.  
  469.                 /* Handle animated explosion: */
  470.  
  471.                 if (cities[i].expl) {
  472.                     cities[i].expl--;
  473.           
  474.                     if (cities[i].expl == 0)
  475.                         cities[i].alive = 0;
  476.                 }
  477.             }
  478.                         
  479.  
  480.         /* Handle game-over: */
  481.  
  482.         if (gameover > 0) {
  483.             gameover--;
  484.  
  485.             if (gameover == 0)
  486.                 done = 1;
  487.         }
  488.                 
  489.                 if ((num_cities_alive==0) && (gameover == 0))
  490.                     gameover = GAMEOVER_COUNTER_START;
  491.       
  492.         /* Draw background: */
  493.      
  494.         SDL_BlitSurface(bkgd, NULL, screen, NULL);
  495.  
  496.         /* Draw wave: */
  497.  
  498.         dest.x = 0;
  499.         dest.y = 0;
  500.         dest.w = images[IMG_WAVE]->w;
  501.         dest.h = images[IMG_WAVE]->h;
  502.  
  503.         SDL_BlitSurface(images[IMG_WAVE], NULL, screen, &dest);
  504.  
  505.         sprintf(str, "%d", wave);
  506.         laser_draw_numbers(str, images[IMG_WAVE]->w + (images[IMG_NUMBERS]->w / 10));
  507.  
  508.  
  509.         /* Draw score: */
  510.  
  511.         dest.x = (screen->w - ((images[IMG_NUMBERS]->w / 10) * 7) - images[IMG_SCORE]->w);
  512.         dest.y = 0;
  513.         dest.w = images[IMG_SCORE]->w;
  514.         dest.h = images[IMG_SCORE]->h;
  515.  
  516.         SDL_BlitSurface(images[IMG_SCORE], NULL, screen, &dest);
  517.       
  518.         sprintf(str, "%.6d", score);
  519.         laser_draw_numbers(str, screen->w - ((images[IMG_NUMBERS]->w / 10) * 6));
  520.       
  521.       
  522.         /* Draw comets: */
  523.       
  524.         for (i = 0; i < MAX_COMETS; i++) 
  525.             if (comets[i].alive) {
  526.  
  527.                 /* Decide which image to display: */
  528.                 if (comets[i].expl == 0)
  529.                     img = IMG_COMET1 + ((frame + i) % 3);
  530.                 else
  531.                     img = (IMG_COMETEX2 - (comets[i].expl / (COMET_EXPL_START / 2)));
  532.           
  533.  
  534.                 /* Draw it! */
  535.  
  536.                 dest.x = comets[i].x - (images[img]->w / 2);
  537.                 dest.y = comets[i].y - images[img]->h;
  538.                 dest.w = images[img]->w;
  539.                 dest.h = images[img]->h;
  540.           
  541.                 SDL_BlitSurface(images[img], NULL, screen, &dest);
  542.             }
  543.  
  544.  
  545.         /* Draw letters: */
  546.  
  547.         for (i = 0; i < MAX_COMETS; i++)
  548.             if (comets[i].alive && comets[i].expl == 0)
  549.                 laser_draw_let(comets[i].ch, comets[i].x, comets[i].y);
  550.       
  551.         /* Draw cities: */
  552.       
  553.         if (frame%2 == 0) next_frame( shield );
  554.         for (i = 0; i < NUM_CITIES; i++) {
  555.  
  556.             /* Decide which image to display: */
  557.      
  558.             if (cities[i].alive) {
  559.                 if (cities[i].expl == 0)
  560.                     img = IMG_CITY_BLUE;
  561.                 else
  562.                     img = (IMG_CITY_BLUE_EXPL5 - (cities[i].expl / (CITY_EXPL_START / 5)));
  563.             } else 
  564.                 img = IMG_CITY_BLUE_DEAD;
  565.       
  566.       
  567.             /* Change image to appropriate color: */
  568.       
  569.             img += ((wave % MAX_CITY_COLORS) * (IMG_CITY_GREEN - IMG_CITY_BLUE));
  570.       
  571.       
  572.             /* Draw it! */
  573.       
  574.             dest.x = cities[i].x - (images[img]->w / 2);
  575.             dest.y = (screen->h) - (images[img]->h);
  576.             dest.w = (images[img]->w);
  577.             dest.h = (images[img]->h);
  578.       
  579.             SDL_BlitSurface(images[img], NULL, screen, &dest);
  580.  
  581.             /* Draw sheilds: */
  582.  
  583.             if (cities[i].shields) {
  584.  
  585.                 dest.x = cities[i].x - (shield->frame[shield->cur]->w / 2);
  586.                 dest.h = (screen->h) - (shield->frame[shield->cur]->h);
  587.                 dest.w = src.w;
  588.                 dest.h = src.h;
  589.                 SDL_BlitSurface( shield->frame[shield->cur], NULL, screen, &dest);
  590.  
  591.             }
  592.         }
  593.  
  594.  
  595.         /* Draw laser: */
  596.  
  597.         if (laser.alive)
  598.             laser_draw_line(laser.x1, laser.y1, laser.x2, laser.y2, 255 / (LASER_START - laser.alive),
  599.                             192 / (LASER_START - laser.alive), 64);
  600.  
  601.         laser_draw_console_image(IMG_CONSOLE);
  602.  
  603.         if (gameover > 0)
  604.             tux_img = IMG_TUX_FIST1 + ((frame / 2) % 2);
  605.  
  606.         laser_draw_console_image(tux_img);
  607.  
  608.  
  609.         /* Draw "Game Over" */
  610.  
  611.         if (gameover > 0) {
  612.  
  613.             dest.x = (screen->w - images[IMG_GAMEOVER]->w) / 2;
  614.             dest.y = (screen->h - images[IMG_GAMEOVER]->h) / 2;
  615.             dest.w = images[IMG_GAMEOVER]->w;
  616.             dest.h = images[IMG_GAMEOVER]->h;
  617.     
  618.             SDL_BlitSurface(images[IMG_GAMEOVER], NULL, screen, &dest);
  619.         }
  620.       
  621.       
  622.         /* Swap buffers: */
  623.       
  624.         SDL_Flip(screen);
  625.  
  626.  
  627.         /* If we're in "PAUSE" mode, pause! */
  628.  
  629.         if (paused) {
  630.             quit = Pause();
  631.             paused = 0;
  632.         }
  633.  
  634.       
  635.         /* Keep playing music: */
  636.       
  637.         if (sys_sound && !Mix_PlayingMusic())
  638.             audioMusicPlay(musics[MUS_GAME + int_rand(0,3)], 0);
  639.       
  640.         /* Pause (keep frame-rate event) */
  641.       
  642.         now_time = SDL_GetTicks();
  643.         if (now_time < last_time + FPS)
  644.             SDL_Delay(last_time + FPS - now_time);
  645.     }
  646.         while (!done && !quit);
  647.  
  648.   
  649.     /* Free background: */
  650.  
  651.     if (bkgd != NULL)
  652.         SDL_FreeSurface(bkgd);
  653.  
  654.     /* Stop music: */
  655.     if ((sys_sound) && (Mix_PlayingMusic()))
  656.         Mix_HaltMusic();
  657.  
  658.     laser_unload_data();
  659.  
  660.     return 1;
  661. }
  662.  
  663.  
  664. /* Reset stuff for the next level! */
  665.  
  666. void laser_reset_level(int DIF_LEVEL)
  667. {
  668.   unsigned char fname[1024];
  669.   static int last_bkgd = -1;
  670.   int i;
  671.   
  672.   /* Clear all comets: */
  673.   
  674.   for (i = 0; i < MAX_COMETS; i++)
  675.     comets[i].alive = 0;
  676.   
  677.   /* Load diffrent random background image: */
  678.  
  679.   do {
  680.     i = int_rand(0,NUM_BKGDS-1);
  681.   }
  682.   while (i == last_bkgd);
  683.  
  684.   last_bkgd = i;
  685.  
  686.   sprintf(fname, "backgrounds/%d.jpg", i);
  687.  
  688.   if (bkgd != NULL)
  689.     SDL_FreeSurface(bkgd);
  690.  
  691.   bkgd = LoadImage(fname, IMG_REGULAR);
  692.  
  693.   if (bkgd == NULL)
  694.   {
  695.     fprintf(stderr,
  696.      "\nWarning: Could not load background image:\n"
  697.      "%s\n"
  698.      "The Simple DirectMedia error that ocurred was: %s\n",
  699.      fname, SDL_GetError());
  700.   }
  701.  
  702.   /* Record score before this wave: */
  703.  
  704.   pre_wave_score = score;
  705.  
  706.   /* Set number of attackers & speed for this wave: */
  707.  
  708.   switch (DIF_LEVEL) {
  709.     case 0 : speed = 1 + (wave/5); num_attackers=15; break;
  710.     case 1 : speed = 1 + (wave/4); num_attackers=15; break;
  711.     case 2 : speed = 1 + ((wave<<1)/3); num_attackers=(wave<<1); break;
  712.     case 3 : speed = 1 + wave; num_attackers=(wave<<1); break;
  713.   }
  714.  
  715.   distanceMoved = 100; // so that we don't have to wait to start the level
  716. }
  717.  
  718.  
  719. /* Add an comet to the game (if there's room): */
  720.  
  721. void laser_add_comet(int DIF_LEVEL) {
  722.  
  723.     int target, location = 0;
  724.     static int last = -1;
  725.     int targeted[NUM_CITIES] = { 0 };
  726.     int add = int_rand(1,DIF_LEVEL+2);
  727.  
  728.     DEBUGCODE { printf(" Adding %d comets \n", add); }
  729.  
  730.     if (NUM_CITIES%2 == 0) {
  731.     while ((add > 0) && (location != MAX_COMETS)) {
  732.   
  733.           /* Look for a free comet slot: */
  734.          while ((comets[location].alive == 1) && (location < MAX_COMETS))
  735.             location++; 
  736.  
  737.           if (location < MAX_COMETS) {
  738.  
  739.             comets[location].alive = 1;
  740.  
  741.             /* Pick a city to attack: */
  742.     
  743.             do { 
  744.                 target = int_rand( 0, NUM_CITIES );
  745.                 } while (target == last || targeted[target] == 1);
  746.  
  747.             last = target;
  748.             targeted[target] = 1;
  749.  
  750.             /* Set in to attack that city: */
  751.       
  752.             comets[location].city = target; 
  753.  
  754.             /* Start at the top, above the city in question: */
  755.       
  756.             comets[location].x = cities[target].x;
  757.             comets[location].y = 0;
  758.  
  759.             /* Pick a letter */
  760.     
  761.             comets[location].ch = get_letter();
  762.             add--;
  763.         }
  764.         DEBUGCODE {
  765.               if (location == MAX_COMETS) 
  766.                 printf("Location == MAX_COMETS, we have max on screen\n"); 
  767.         }
  768.     } }
  769.     else {
  770.         unsigned char *word = WORDS_get();
  771.         int i=0;
  772.         do { 
  773.             target = int_rand( 0, NUM_CITIES-strlen(word)+1);
  774.             } while (target == last);
  775.         last = target;
  776.  
  777.         for (i=0; i<strlen(word); i++) {
  778.              while ((comets[location].alive == 1) && (location < MAX_COMETS))
  779.                 location++; 
  780.  
  781.               if (location < MAX_COMETS) {
  782.  
  783.                 comets[location].alive = 1;
  784.                 comets[location].city = target+i; 
  785.                 comets[location].x = cities[target+i].x;
  786.                 comets[location].y = 0;
  787.                 comets[location].ch = word[i];
  788.             }
  789.         }
  790.     }
  791. }
  792.  
  793.  
  794. /* Draw numbers/symbols over the attacker: */
  795.  
  796. void laser_draw_let(unsigned char c, int x, int y)
  797. {
  798.     SDL_Rect dst;
  799.     dst.y = y-35;
  800.     dst.x = x - (letters[(int)c]->w/2);
  801.     SDL_BlitSurface(letters[(int)c], NULL, screen, &dst); 
  802. }
  803.  
  804.  
  805. /* Draw status numbers: */
  806.  
  807. void laser_draw_numbers(unsigned char * str, int x)
  808. {
  809.   int i, cur_x, c;
  810.   SDL_Rect src, dest;
  811.  
  812.  
  813.   cur_x = x;
  814.  
  815.  
  816.   /* Draw each character: */
  817.   
  818.   for (i = 0; i < strlen(str); i++)
  819.     {
  820.       c = -1;
  821.  
  822.  
  823.       /* Determine which character to display: */
  824.       
  825.       if (str[i] >= '0' && str[i] <= '9')
  826.     c = str[i] - '0';
  827.       
  828.  
  829.       /* Display this character! */
  830.       
  831.       if (c != -1)
  832.     {
  833.       src.x = c * (images[IMG_NUMBERS]->w / 10);
  834.       src.y = 0;
  835.       src.w = (images[IMG_NUMBERS]->w / 10);
  836.       src.h = images[IMG_NUMBERS]->h;
  837.       
  838.       dest.x = cur_x;
  839.       dest.y = 0;
  840.       dest.w = src.w;
  841.       dest.h = src.h;
  842.       
  843.       SDL_BlitSurface(images[IMG_NUMBERS], &src,
  844.               screen, &dest);
  845.  
  846.  
  847.           /* Move the 'cursor' one character width: */
  848.  
  849.       cur_x = cur_x + (images[IMG_NUMBERS]->w / 10);
  850.     }
  851.     }
  852. }
  853.  
  854. /* Draw a line: */
  855.  
  856. void laser_draw_line(int x1, int y1, int x2, int y2, int red, int grn, int blu)
  857. {
  858.   int dx, dy, tmp;
  859.   float m, b;
  860.   Uint32 pixel;
  861.   SDL_Rect dest;
  862.  
  863.   pixel = SDL_MapRGB(screen->format, red, grn, blu);
  864.  
  865.   dx = x2 - x1;
  866.   dy = y2 - y1;
  867.  
  868.   laser_putpixel(screen, x1, y1, pixel);
  869.   
  870.   if (dx != 0)
  871.   {
  872.     m = ((float) dy) / ((float) dx);
  873.     b = y1 - m * x1;
  874.  
  875.     if (x2 > x1)
  876.       dx = 1;
  877.     else
  878.       dx = -1;
  879.  
  880.     while (x1 != x2)
  881.     {
  882.       x1 = x1 + dx;
  883.       y1 = m * x1 + b;
  884.       
  885.       laser_putpixel(screen, x1, y1, pixel);
  886.     }
  887.   }
  888.   else
  889.   {
  890.     if (y1 > y2)
  891.     {
  892.       tmp = y1;
  893.       y1 = y2;
  894.       y2 = tmp;
  895.     }
  896.     
  897.     dest.x = x1;
  898.     dest.y = y1;
  899.     dest.w = 3;
  900.     dest.h = y2 - y1;
  901.  
  902.     SDL_FillRect(screen, &dest, pixel);
  903.   }
  904. }
  905.  
  906.  
  907. /* Draw a single pixel into the surface: */
  908.  
  909. void laser_putpixel(SDL_Surface * surface, int x, int y, Uint32 pixel)
  910. {
  911. #ifdef PUTPIXEL_RAW
  912.   int bpp;
  913.   Uint8 * p;
  914.   
  915.   /* Determine bytes-per-pixel for the surface in question: */
  916.   
  917.   bpp = surface->format->BytesPerPixel;
  918.   
  919.   
  920.   /* Set a pointer to the exact location in memory of the pixel
  921.      in question: */
  922.   
  923.   p = (Uint8 *) (surface->pixels +       /* Start at beginning of RAM */
  924.                  (y * surface->pitch) +  /* Go down Y lines */
  925.                  (x * bpp));             /* Go in X pixels */
  926.   
  927.   
  928.   /* Assuming the X/Y values are within the bounds of this surface... */
  929.   
  930.   if (x >= 0 && y >= 0 && x < surface -> w && y < surface -> h)
  931.     {
  932.       /* Set the (correctly-sized) piece of data in the surface's RAM
  933.          to the pixel value sent in: */
  934.       
  935.       if (bpp == 1)
  936.         *p = pixel;
  937.       else if (bpp == 2)
  938.         *(Uint16 *)p = pixel;
  939.       else if (bpp == 3)
  940.         {
  941.           if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
  942.             {
  943.               p[0] = (pixel >> 16) & 0xff;
  944.               p[1] = (pixel >> 8) & 0xff;
  945.               p[2] = pixel & 0xff;
  946.             }
  947.           else
  948.             {
  949.               p[0] = pixel & 0xff;
  950.               p[1] = (pixel >> 8) & 0xff;
  951.               p[2] = (pixel >> 16) & 0xff;
  952.             }
  953.         }
  954.       else if (bpp == 4)
  955.         {
  956.           *(Uint32 *)p = pixel;
  957.         }
  958.     }
  959. #else
  960.   SDL_Rect dest;
  961.  
  962.   dest.x = x;
  963.   dest.y = y;
  964.   dest.w = 3;
  965.   dest.h = 4;
  966.  
  967.   SDL_FillRect(surface, &dest, pixel);
  968. #endif
  969. }
  970.  
  971.  
  972. /* Draw image at lower center of screen: */
  973.  
  974. void laser_draw_console_image(int i)
  975. {
  976.   SDL_Rect dest;
  977.  
  978.   dest.x = (screen->w - images[i]->w) / 2;
  979.   dest.y = (screen->h - images[i]->h);
  980.   dest.w = images[i]->w;
  981.   dest.h = images[i]->h;
  982.  
  983.   SDL_BlitSurface(images[i], NULL, screen, &dest);
  984. }
  985.  
  986.  
  987. /* Increment score: */
  988.  
  989. void laser_add_score(int inc)
  990. {
  991.   score += inc;
  992.   if (score < 0) score = 0;
  993. }
  994.  
  995.