home *** CD-ROM | disk | FTP | other *** search
/ Revista do CD-ROM 123 / cdrom123.iso / edu / tux / Tuxtype2-1.5.3-installer.exe / src / playgame.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-03-25  |  42.8 KB  |  1,516 lines

  1. /***************************************************************************
  2. playgame.c 
  3. -  description: Cascade game
  4. -------------------
  5. begin                : Fri May 5 2000
  6. copyright            : (C) 2000 by Sam Hart
  7.                      : (C) 2003 by Jesse Andrews
  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 "playgame.h"
  23. #include "snow.h"
  24.  
  25. void add_words( int level );
  26.  
  27. int tux_max_width;                // the max width of the images of tux
  28. int number_max_w;                 // the max width of a number image
  29. int o_lives; // something cal is working on
  30. int sound_vol;
  31.  
  32. SDL_Surface *background;
  33.  
  34. SDL_Surface *level[NUM_LEVELS];
  35. SDL_Surface *number[NUM_NUMS];
  36. SDL_Surface *curlev;
  37. SDL_Surface *lives;
  38. SDL_Surface *fish;
  39. SDL_Surface *congrats[CONGRATS_FRAMES];
  40. SDL_Surface *ohno[OH_NO_FRAMES];
  41.  
  42. SDL_Surface *letter[256];
  43. SDL_Surface *red_letter[256];
  44. sprite *fishy;
  45. sprite *splat;
  46.  
  47. /* --- Data Structure for Dirty Blitting --- */
  48. SDL_Rect srcupdate[MAX_UPDATES];
  49. SDL_Rect dstupdate[MAX_UPDATES];
  50. int numupdates = 0; // tracks how many blits to be done
  51.  
  52. struct blit {
  53.     SDL_Surface *src;
  54.     SDL_Rect *srcrect;
  55.     SDL_Rect *dstrect;
  56.     unsigned char type;
  57. } blits[MAX_UPDATES];
  58.  
  59. /***************************************
  60.  int_rand: returns an integer x
  61.            such that - min <= x <= max
  62. ***************************************/
  63. int int_rand(int min, int max) {
  64.     return min + (int) (((double)(max-min))*(float)rand()/(RAND_MAX+1.0)); // JA - FIX this doesn't return MAX
  65. }
  66.  
  67. int check_word( int f ) {
  68.     int i;
  69.  
  70.     if (strlen(fish_object[f].word) > tux_object.wordlen) 
  71.         return 0;
  72.  
  73.     for (i=0; i<strlen(fish_object[f].word); i++) 
  74.         if (KEYMAP[fish_object[f].word[i]] != KEYMAP[tux_object.word[tux_object.wordlen-strlen(fish_object[f].word)+i]])
  75.             return 0;
  76.  
  77.     return 1;
  78. }
  79.  
  80. void create_letters( void ) {
  81.     int i;
  82.     for (i = 1; i < 255; i++) {
  83.         letter[i] = ttf_letter(i, white);
  84.         red_letter[i] = ttf_letter(i, red);
  85.     }
  86. }
  87.  
  88. void remove_letters( void ) {
  89.     int i;
  90.     for (i = 1; i < 255; i++) {
  91.             SDL_FreeSurface(letter[i]);
  92.             SDL_FreeSurface(red_letter[i]);
  93.         } 
  94. }
  95.  
  96. /***************************************
  97.     WaitFrame: wait for the next frame
  98. ***************************************/
  99. void WaitFrame(void) {
  100.     static Uint32  next_tick = 0;
  101.     Uint32         this_tick = SDL_GetTicks();
  102.  
  103.     if (this_tick < next_tick)
  104.         SDL_Delay(next_tick - this_tick);
  105.  
  106.     next_tick = this_tick + (1000 / FRAMES_PER_SEC);
  107. }
  108.  
  109. /***********************
  110.  InitEngine
  111.  ***********************/
  112. void InitEngine(void) {
  113.     int i;
  114.  
  115.     /* --- Set up the update rectangle pointers --- */
  116.     
  117.     for (i = 0; i < MAX_UPDATES; ++i) {
  118.         blits[i].srcrect = &srcupdate[i];
  119.         blits[i].dstrect = &dstupdate[i];
  120.     }
  121. }
  122.  
  123. /****************************************************
  124.  ResetObjects : Clear and reset all objects to dead
  125. ****************************************************/
  126.  
  127. void ResetObjects( void ) {
  128.     int i;
  129.  
  130.     LOG( "RESETTING OBJECTS\n" );
  131.  
  132.     for (i = 0; i < MAX_FISHIES_HARD + 1; i++) {
  133.         fish_object[i] = null_fishy;
  134.         splat_object[i] = null_splat;
  135.     }
  136.  
  137.     tux_object.facing = RIGHT;
  138.     tux_object.x = screen->w / 2;
  139.     tux_object.y = screen->h - tux_object.spr[0][RIGHT]->frame[0]->h - 1;
  140.     tux_object.dx = 0;
  141.     tux_object.dy = 0;
  142.     tux_object.endx = tux_object.x;
  143.     tux_object.endy = tux_object.y;
  144.     tux_object.state = TUX_STANDING;
  145.     tux_object.word[0] = 0;
  146.     tux_object.wordlen = 0;
  147.  
  148.     LOG( "OBJECTS RESET\n" );
  149. }
  150.  
  151. void DrawSprite(sprite *gfx, int x, int y) {
  152.     struct blit *update;
  153.     update = &blits[numupdates++];
  154.     update->src = gfx->frame[gfx->cur];
  155.     update->srcrect->x = 0;
  156.     update->srcrect->y = 0;
  157.     update->srcrect->w = gfx->frame[gfx->cur]->w;
  158.     update->srcrect->h = gfx->frame[gfx->cur]->h;
  159.     update->dstrect->x = x;
  160.     update->dstrect->y = y;
  161.     update->dstrect->w = gfx->frame[gfx->cur]->w;
  162.     update->dstrect->h = gfx->frame[gfx->cur]->h;
  163.     update->type = 'D';
  164. }
  165.  
  166. /**********************
  167. DrawObject : Draw an object at the specified
  168. location. No respect to clipping!
  169. *************************/
  170. void DrawObject(SDL_Surface * sprite, int x, int y) {
  171.     struct blit *update;
  172.     update = &blits[numupdates++];
  173.     update->src = sprite;
  174.     update->srcrect->x = 0;
  175.     update->srcrect->y = 0;
  176.     update->srcrect->w = sprite->w;
  177.     update->srcrect->h = sprite->h;
  178.     update->dstrect->x = x;
  179.     update->dstrect->y = y;
  180.     update->dstrect->w = sprite->w;
  181.     update->dstrect->h = sprite->h;
  182.     update->type = 'D';
  183. }
  184.  
  185. /************************
  186. UpdateScreen : Update the screen and increment the frame num
  187. ***************************/
  188. void UpdateScreen(int *frame) {
  189.     int i;
  190.  
  191.     /* -- First erase everything we need to -- */
  192.     for (i = 0; i < numupdates; i++)
  193.         if (blits[i].type == 'E') 
  194.             SDL_LowerBlit(blits[i].src, blits[i].srcrect, screen, blits[i].dstrect);
  195.     SNOW_erase();
  196.  
  197.     /* -- then draw -- */ 
  198.     for (i = 0; i < numupdates; i++)
  199.         if (blits[i].type == 'D') 
  200.             SDL_BlitSurface(blits[i].src, blits[i].srcrect, screen, blits[i].dstrect);
  201.     SNOW_draw();
  202.  
  203.     /* -- update the screen only where we need to! -- */
  204.     if (SNOW_on) 
  205.         SDL_UpdateRects(screen, SNOW_add( (SDL_Rect*)&dstupdate, numupdates ), SNOW_rects);
  206.     else 
  207.         SDL_UpdateRects(screen, numupdates, dstupdate);
  208.  
  209.     numupdates = 0;
  210.     *frame = *frame + 1;
  211. }
  212.  
  213. void EraseSprite(sprite *img, int x, int y) {
  214.     struct blit *update;
  215.  
  216.     update = &blits[numupdates++];
  217.     update->src = background;
  218.     update->srcrect->x = x;
  219.     update->srcrect->y = y;
  220.     update->srcrect->w = img->frame[img->cur]->w;
  221.     update->srcrect->h = img->frame[img->cur]->h;
  222.  
  223.     /* check to see if we are trying blit data that doesn't exist!!! */
  224.  
  225.     if (update->srcrect->x + update->srcrect->w > background->w)
  226.         update->srcrect->w = background->w - update->srcrect->x;
  227.     if (update->srcrect->y + update->srcrect->h > background->h)
  228.         update->srcrect->h = background->h - update->srcrect->y;
  229.  
  230.     update->dstrect->x = x;
  231.     update->dstrect->y = y;
  232.     update->dstrect->w = update->srcrect->w;
  233.     update->dstrect->h = update->srcrect->h;
  234.     update->type = 'E';
  235. }
  236.  
  237. /*************************
  238. EraseObject : Erase an object from the screen
  239. **************************/
  240. void EraseObject(SDL_Surface * sprite, int x, int y) {
  241.     struct blit *update;
  242.  
  243.     update = &blits[numupdates++];
  244.     update->src = background;
  245.     update->srcrect->x = x;
  246.     update->srcrect->y = y;
  247.     update->srcrect->w = sprite->w;
  248.     update->srcrect->h = sprite->h;
  249.  
  250.     /* check to see if we are trying blit data that doesn't exist!!! */
  251.  
  252.     if (update->srcrect->x + update->srcrect->w > background->w)
  253.         update->srcrect->w = background->w - update->srcrect->x;
  254.     if (update->srcrect->y + update->srcrect->h > background->h)
  255.         update->srcrect->h = background->h - update->srcrect->y;
  256.  
  257.     update->dstrect->x = x;
  258.     update->dstrect->y = y;
  259.     update->dstrect->w = update->srcrect->w;
  260.     update->dstrect->h = update->srcrect->h; 
  261.     update->type = 'E';
  262. }
  263.  
  264. /******************************
  265. AddRect : Dont actually blit a surface,
  266.     but add a rect to be updated next
  267.     update
  268. *******************************/
  269. void AddRect(SDL_Rect * src, SDL_Rect * dst) {
  270.     /*borrowed from SL's alien (and modified)*/
  271.     struct blit    *update;
  272.  
  273.     update = &blits[numupdates++];
  274.  
  275.     update->srcrect->x = src->x;
  276.     update->srcrect->y = src->y;
  277.     update->srcrect->w = src->w;
  278.     update->srcrect->h = src->h;
  279.     update->dstrect->x = dst->x;
  280.     update->dstrect->y = dst->y;
  281.     update->dstrect->w = dst->w;
  282.     update->dstrect->h = dst->h;
  283.     update->type = 'I';
  284. }
  285.  
  286. /*********************
  287. LoadOthers : Load all other graphics
  288. **********************/
  289. void LoadOthers( void ) {
  290.     int i;
  291.     unsigned char filename[FNLEN];
  292.  
  293.     LOG( "=LoadOthers()\n" );
  294.  
  295.     font = LoadFont( ttf_font, ttf_font_size );
  296.  
  297.     curlev = black_outline(_("Level"), font, &white);
  298.     lives  = black_outline(_("Lives"), font, &white);
  299.     fish   = black_outline(_("Fish"), font, &white);
  300.  
  301.     level[0] = black_outline(_("Easy"), font, &white);
  302.     level[1] = black_outline(_("Medium"), font, &white);
  303.     level[2] = black_outline(_("Hard"), font, &white);
  304.     level[3] = black_outline(_("Practice"), font, &white);
  305.  
  306.     number_max_w = 0;
  307.     for (i = 0; i < NUM_NUMS; i++) {
  308.         sprintf(filename, "num_%i.png", i);
  309.         number[i] = LoadImage( filename, IMG_COLORKEY );
  310.         if (number[i]->w > number_max_w)
  311.             number_max_w = number[i]->w;
  312.     }
  313.  
  314.     for (i = 0; i < CONGRATS_FRAMES; i++) {
  315.         congrats[i] = black_outline(_("Congratulations"), font, &white);
  316.     }
  317.  
  318.     for (i = 0; i < OH_NO_FRAMES; i++) {
  319.         ohno[i] = black_outline(_("Oh No!"), font, &white);
  320.     }
  321.     
  322.     if (sys_sound) {
  323.         LOG( "=Loading Sound FX\n" );
  324.  
  325.         sound[WIN_WAV] = LoadSound( "win.wav" );
  326.         sound[WINFINAL_WAV] = LoadSound( "winfinal.wav" );
  327.         sound[BITE_WAV] = LoadSound( "bite.wav" );
  328.         sound[LOSE_WAV] = LoadSound( "lose.wav" );
  329.         sound[RUN_WAV] = LoadSound( "run.wav" );
  330.         sound[SPLAT_WAV] = LoadSound( "splat.wav" );
  331.         sound[EXCUSEME_WAV] = LoadSound( "excuseme.wav" );
  332.  
  333.         LOG( "=Done Loading Sound FX\n" );
  334.     } else 
  335.         LOG( "=NO SOUND FX LOADED (not selected)\n" );
  336.  
  337.     pause_load_media();
  338.  
  339.     LOG( "=Setting NULL fish & splat & word\n" );
  340.  
  341.     null_fishy.alive = 0;
  342.     null_fishy.can_eat = 0;
  343.     null_fishy.word = NULL;
  344.     null_fishy.x = 0;
  345.     null_fishy.y = 0;
  346.     null_fishy.dy = 0;
  347.  
  348.     null_splat.x = 0;
  349.     null_splat.y = 0;
  350.     null_splat.alive = 0;
  351.  
  352.     LOG( "=LoadOthers() END\n" );
  353. }
  354.  
  355. void debugDISPLAY( unsigned char *msg, int x, int y ) {
  356.     SDL_Surface *m;
  357.     m = TTF_RenderText_Solid( font, msg, white );
  358.     EraseObject(m, x, y);
  359.     DrawObject(m, x, y);
  360. }
  361.  
  362. /***************************
  363. LoadFishies : Load the fish animations and graphics
  364. *****************************/
  365. void LoadFishies( void ) {
  366.     int i;
  367.  
  368.     LOG( "=LoadFishies()\n" );
  369.  
  370.     fishy = LoadSprite( "fishy", IMG_COLORKEY );
  371.     splat = LoadSprite( "splat", IMG_COLORKEY );
  372.  
  373.     for (i = 0; i < MAX_FISHIES_HARD; i++) {
  374.         fish_object[i].alive = 1;
  375.         fish_object[i].can_eat = 0;
  376.         splat_object[i].alive = 0;
  377.     }
  378.  
  379.     LOG( "=LoadFishies(): END\n" );
  380. }
  381.  
  382. /******************************
  383. LoadTuxAnims : Load the Tux graphics and animations
  384. *******************************/
  385. void LoadTuxAnims( void ) {
  386.     int i;
  387.     int height = 0;                //temp width/height varis to determine max's
  388.  
  389.     LOG( "=LoadTuxAnims(): Loading Tux Animations\n" );
  390.  
  391.     for ( i=0; i < TUX_NUM_STATES; i++ ) {
  392.         tux_object.spr[i][RIGHT] = LoadSprite( tux_sprite_fns[i], IMG_COLORKEY ); 
  393.         tux_object.spr[i][LEFT] = FlipSprite( tux_object.spr[i][RIGHT], 1, 0 ); 
  394.     }
  395.  
  396.     tux_max_width = tux_object.spr[TUX_STANDING][RIGHT]->frame[0]->w;
  397.     height        = tux_object.spr[TUX_STANDING][RIGHT]->frame[0]->h;
  398.  
  399.     LOG( "=LoadTuxAnims(): END\n" );
  400. }
  401.  
  402. /******************************
  403. DrawNumbers : Draw numbers at
  404. a certain x,y. See "usage"
  405. bellow
  406. *******************************/
  407. void DrawNumbers(int num, int x, int y, int places) {
  408. //usage:
  409. //      num    = number to draw onscreen
  410. //      x, y   = coords to place number (starting upper left)
  411. //      places = number of places to fit it into (i.e., if
  412. //                                       number = 5 and places = 2, would draw "05")
  413. //                                       if places = 0, then will simply display as
  414. //                                       many as necessary
  415.     unsigned char numnuts[FNLEN];
  416.     int needed_places, i;
  417.     int uddernumber;
  418.  
  419.     sprintf(numnuts, "%d", num);
  420.     i = 0;
  421.     needed_places = strlen(numnuts);
  422.  
  423.     if (needed_places < FNLEN && needed_places <= places) {
  424.         if (places > 0) {
  425.             for (i = 1; i <= (places - needed_places); i++) {
  426.                 DrawObject(number[0], x, y);
  427.                 x += number[0]->w;
  428.             }
  429.         }
  430.     }
  431.     for (i = 0; i < needed_places; i++) {
  432.         uddernumber = numnuts[i] - '0';
  433.  
  434.         DrawObject(number[uddernumber], x, y);
  435.         x += number[uddernumber]->w;
  436.     }
  437. }
  438.  
  439. /*************************
  440. EraseNumbers: Erase numbers
  441. from the screen. See "usage"
  442. *****************************/
  443. void EraseNumbers(int num, int x, int y, int places) {
  444. //usage:
  445. //      num    = number to draw onscreen
  446. //      x, y   = coords to place number (starting upper left)
  447. //      places = number of places to fit it into (i.e., if
  448. //                                       number = 5 and places = 2, would draw "05")
  449. //                                       if places = 0, then will simply display as
  450. //                                       many as necessary
  451.     unsigned char numnuts[FNLEN];
  452.     int needed_places, i;
  453.     int uddernumber;
  454.  
  455.     sprintf(numnuts, "%d", num);
  456.     i = 0;
  457.     needed_places = strlen(numnuts);
  458.  
  459.     if (needed_places < FNLEN && needed_places <= places) {
  460.         if (places > 0) {
  461.             for (i = 1; i <= (places - needed_places); i++) {
  462.                 EraseObject(number[0], x, y);
  463.                 x += number[0]->w;
  464.             }
  465.         }
  466.     }
  467.     for (i = 0; i < needed_places; i++) {
  468.         uddernumber = numnuts[i] - '0';
  469.         EraseObject(number[uddernumber], x, y);
  470.         x += number[uddernumber]->w;
  471.     }
  472. }
  473.  
  474. /**********************
  475. FreeGame : Free all
  476. the game elements
  477. ***********************/
  478. void FreeGame( void ) {
  479.     int i;
  480.  
  481.     TTF_CloseFont(font);
  482.  
  483.     LOG( "FreeGame():\n-Freeing Tux Animations\n" );
  484.  
  485.     for ( i=0; i < TUX_NUM_STATES; i++ ) {
  486.         FreeSprite(tux_object.spr[i][RIGHT]);
  487.         FreeSprite(tux_object.spr[i][LEFT]);
  488.     }
  489.  
  490.     LOG( "-Freeing fishies\n" );
  491.  
  492.     FreeSprite( fishy );
  493.     FreeSprite( splat );
  494.  
  495.     LOG( "-Freeing other game graphics\n" );
  496.  
  497.     SDL_FreeSurface(background);
  498.     SDL_FreeSurface(curlev);
  499.     SDL_FreeSurface(fish);
  500.     SDL_FreeSurface(lives);
  501.  
  502.     for (i = 0; i < NUM_LEVELS; i++)
  503.         SDL_FreeSurface(level[i]);
  504.  
  505.     for (i = 0; i < NUM_NUMS; i++)
  506.         SDL_FreeSurface(number[i]);
  507.  
  508.     for (i = 0; i < 256; i++) {
  509.         if (letter[i]) SDL_FreeSurface(letter[i]);
  510.         if (red_letter[i]) SDL_FreeSurface(red_letter[i]);
  511.     }
  512.  
  513.     for (i = 0; i < CONGRATS_FRAMES; i++)
  514.         SDL_FreeSurface(congrats[i]);
  515.  
  516.     for (i = 0; i < OH_NO_FRAMES; i++)
  517.         SDL_FreeSurface(ohno[i]);
  518.  
  519.     if (sys_sound) {
  520.         LOG( "-Freeing sound\n" );
  521.  
  522.         for (i = 0; i < NUM_WAVES; ++i) 
  523.             Mix_FreeChunk(sound[i]);
  524.     }
  525.  
  526.     pause_unload_media();
  527.  
  528.     LOG( "FreeGame(): END\n" );
  529. }
  530.  
  531. /***************************
  532. DrawBackground : This
  533. function updates the entire
  534. background. Usefull when
  535. loading new backgrounds,
  536. or clearing game screen
  537. ****************************/
  538. void DrawBackground( void ) {
  539.     struct blit *update;
  540.  
  541.     LOG( "-DrawBackground(): Updating entire background\n" );
  542.  
  543.     numupdates=0;  // drawing entire background writes over all other stuff, so don't draw them
  544.  
  545.     update = &blits[numupdates++];
  546.     update->src = background;
  547.  
  548.     update->srcrect->x = update->dstrect->x = 0;
  549.     update->srcrect->y = update->dstrect->y = 0;
  550.     update->srcrect->w = update->dstrect->w = background->w;
  551.     update->srcrect->h = update->dstrect->h = background->h;
  552.  
  553.     update->type = 'D';
  554. }
  555.  
  556. /****************************
  557. SpawnFishies: Spawn the fishes
  558. in the key cascade game
  559. *****************************/
  560. void SpawnFishies(int diflevel, int *fishies, int *frame ) {
  561.     int i, spacing;
  562.  
  563.     switch (diflevel) {
  564.         case INF_PRACT:
  565.         case EASY:   spacing = FISH_SPACING_EASY; break;
  566.         case MEDIUM: spacing = FISH_SPACING_MEDIUM; break;
  567.         case HARD:   spacing = FISH_SPACING_HARD; break;
  568.     }
  569.  
  570.     /* --- return without spawn if there isn't room yet --- */
  571.  
  572.     for (i = 0; i < *fishies; i++)
  573.         if (fish_object[i].y < (fishy->frame[0]->h + spacing))
  574.             return;
  575.         
  576.     LOG( "=>Spawning fishy\n" );
  577.  
  578.     fish_object[*fishies].alive = 1;
  579.     fish_object[*fishies].can_eat = 0;
  580.  
  581.     fish_object[*fishies].word = WORDS_get();
  582.     fish_object[*fishies].len = strlen(fish_object[*fishies].word);
  583.     fish_object[*fishies].w = fishy->frame[0]->w * fish_object[*fishies].len;
  584.     fish_object[*fishies].x = int_rand(0, screen->w - fish_object[*fishies].w);
  585.     fish_object[*fishies].y = 0;
  586.  
  587.     /* set the percentage of the speed based on length */
  588.     fish_object[*fishies].dy = pow(0.92,fish_object[*fishies].len-1);
  589.     /* ex: a 9 letter word will be roughly twice as slow! 0.92^8 */
  590.  
  591.     /* give it a random variance so the fish "crunch" isn't constant */
  592.     fish_object[*fishies].dy *= (int_rand(75,100)/100.0);
  593.     switch (diflevel) {
  594.         case INF_PRACT:
  595.             fish_object[*fishies].dy = DEFAULT_SPEED;
  596.             break;
  597.         case EASY:
  598.             fish_object[*fishies].dy *= MAX_SPEED_EASY;
  599.             break;
  600.         case MEDIUM:
  601.             fish_object[*fishies].dy *= MAX_SPEED_MEDIUM;
  602.             break;
  603.         case HARD:
  604.             fish_object[*fishies].dy *= MAX_SPEED_HARD;
  605.             break;
  606.        }
  607.  
  608.     fish_object[*fishies].splat_time = *frame + (480 - fishy->frame[0]->h - tux_object.spr[TUX_STANDING][0]->frame[0]->h)/fish_object[*fishies].dy;
  609.  
  610.     DEBUGCODE {
  611.         fprintf(stderr, "Spawn fishy with word '%s'\n", fish_object[*fishies].word);
  612.     }
  613.  
  614.     *fishies = *fishies + 1;
  615. }
  616.  
  617. /***************************
  618. CheckFishies : Check all the fishies and splats.
  619.                sort the splats and fishies
  620. ****************************/
  621. void CheckFishies(int *fishies, int *splats) {
  622.     int forward, backward;
  623.     struct fishypoo fish_temp;
  624.     struct splatter splat_temp;
  625.  
  626.     LOG( "CheckFishies\n" );
  627.  
  628.     /* move any fish from the rear to fill up gaps in the
  629.      * front
  630.      */
  631.     forward = 0;
  632.     backward = MAX_FISHIES_HARD;
  633.     while (forward < backward) {
  634.         while (backward > 0 && !fish_object[backward].alive)
  635.             backward--;
  636.         while (forward < backward && fish_object[forward].alive)
  637.             forward++;
  638.         if ((fish_object[backward].alive) && (!fish_object[forward].alive)) {
  639.             /* swap alive to be infront of dead */
  640.             fish_temp = fish_object[backward];
  641.             fish_object[backward] = fish_object[forward];
  642.             fish_object[forward] = fish_temp;
  643.         }
  644.     }
  645.     
  646.     /* same thing for splats */
  647.  
  648.     forward = 0;
  649.     backward = MAX_FISHIES_HARD;
  650.     while (forward < backward) {
  651.         while (backward > 0 && !splat_object[backward].alive)
  652.             backward--;
  653.         while (forward < backward && splat_object[forward].alive)
  654.             forward++;
  655.         if ((splat_object[backward].alive) && (!splat_object[forward].alive)) {
  656.             /* swap alive to be infront of dead */
  657.             splat_temp = splat_object[backward];
  658.             splat_object[backward] = splat_object[forward];
  659.             splat_object[forward] = splat_temp;
  660.         }
  661.     }
  662.  
  663.     /* update the count for fishies & splats */
  664.  
  665.     *splats = *fishies = 0;
  666.  
  667.     for (forward = 0; forward < MAX_FISHIES_HARD; forward++)
  668.         if (fish_object[forward].alive)
  669.             *fishies+=1;
  670.         else
  671.             break;
  672.  
  673.     for (forward = 0; forward < MAX_FISHIES_HARD; forward++)
  674.         if (splat_object[forward].alive)
  675.             *splats+=1;
  676.         else
  677.             break;
  678. }
  679.  
  680. // Restrict x to a value in the range from a ... b
  681. int int_restrict(int a, int x, int b) {
  682.     if (x < a) x = a;
  683.     if (x > b) x = b;
  684.     return x;
  685. }
  686.  
  687. float float_restrict(float a, float x, float b) {
  688.     if (x < a) x = a;
  689.     if (x > b) x = b;
  690.     return x;
  691. }
  692.  
  693. /***************************
  694. AddSplat: A fish has died, add a splat where he used to be
  695. ****************************/
  696. void AddSplat(int *splats, struct fishypoo *f, int *curlives, int *frame) {
  697.     int i;
  698.  
  699.     for ( i = 0; i < f->len; i++ ) {
  700.         splat_object[*splats].x = int_restrict( 0, f->x+(fishy->frame[0]->w*i) + ((fishy->frame[fishy->cur]->w)>>1)-((splat->frame[0]->w)>>1), screen->w-splat->frame[0]->h-1 );
  701.         splat_object[*splats].y = screen->h - splat->frame[0]->h - 1;
  702.         splat_object[*splats].alive = 10; // JA tweak here! frames of live of the splat
  703.         *splats = *splats + 1;
  704.     }
  705.  
  706.     f->alive = 0;
  707.  
  708.     *curlives = *curlives - 1;
  709.     if (*curlives <= 0)
  710.         *curlives = 0;
  711.  
  712.     if ( sys_sound ) 
  713.         Mix_PlayChannel(SPLAT_WAV, sound[SPLAT_WAV], 0);
  714. }
  715.  
  716. void DrawFish( int which ) {
  717.     int j, red_letters;
  718.  
  719.     for ( j=0; j < fish_object[which].len; j++ )
  720.         DrawSprite( fishy, fish_object[which].x + (fishy->frame[0]->w*j), fish_object[which].y );
  721.  
  722.     /* we only draw the letter if tux cannot eat it yet */
  723.  
  724.     if (!fish_object[which].can_eat) {
  725.         red_letters = -1;
  726.  
  727.         j=0;
  728.         while ( j < tux_object.wordlen && red_letters == -1 ) {
  729.             int k;
  730.             for ( k=0; k<tux_object.wordlen - j; k++)
  731.                 if ( KEYMAP[fish_object[which].word[k]] != KEYMAP[tux_object.word[j+k]] ) 
  732.                     k=100000;
  733.  
  734.             if (k < 100000)
  735.                 red_letters = tux_object.wordlen - j;    
  736.             else
  737.                 j++;
  738.         }
  739.     
  740.         for (j = 0; j < strlen(fish_object[which].word); j++)
  741.             if (fish_object[which].word[j]!=32) {
  742.                 if (j < red_letters)
  743.                     DrawObject(red_letter[(int)fish_object[which].word[j]], (fish_object[which].x + (j * fishy->frame[0]->w)), fish_object[which].y);        
  744.                 else
  745.                     DrawObject(letter[(int)fish_object[which].word[j]], (fish_object[which].x + (j * fishy->frame[0]->w)), fish_object[which].y);
  746.             }
  747.     }
  748. }
  749.  
  750. /****************************
  751. MoveFishies : Display and
  752. move the fishies according
  753. to their settings
  754. *****************************/
  755. void MoveFishies(int *fishies, int *splats, int *lifes, int *frame) {
  756.     int i, j;
  757.  
  758.     LOG("start MoveFishies\n");
  759.  
  760.     for (i = 0; i < *fishies; i++)
  761.         if (fish_object[i].alive) {
  762.             for (j=0; j < fish_object[i].len; j++)
  763.                 EraseSprite( fishy, fish_object[i].x + (fishy->frame[0]->w*j), fish_object[i].y );
  764.     
  765.             fish_object[i].y += fish_object[i].dy;
  766.     
  767.             if (fish_object[i].y >= (screen->h) - fishy->frame[fishy->cur]->h - 1) 
  768.                 AddSplat( splats, &fish_object[i], lifes, frame );
  769.         }
  770.     
  771.     for (i = 0; i < *fishies; i++)
  772.         if (fish_object[i].alive && fish_object[i].can_eat) 
  773.             DrawFish( i );
  774.  
  775.     for (i = 0; i < *fishies; i++)
  776.         if (fish_object[i].alive && !fish_object[i].can_eat) 
  777.             DrawFish( i );
  778.  
  779.     for (i = 0; i < *splats; i++) 
  780.         if (splat_object[i].alive) {
  781.             splat_object[i].alive--;
  782.             if (splat_object[i].alive>1)
  783.                     DrawSprite( splat, splat_object[i].x, splat_object[i].y);
  784.                 else 
  785.                     EraseSprite( splat, splat_object[i].x, splat_object[i].y);
  786.         }
  787.  
  788.     LOG("end MoveFishies\n");
  789. }
  790.  
  791. /* UpdateTux : anytime a key is pressed, we need check to
  792.  * see if a fish can be eaten.  The fish that could hit
  793.  * the bottom of the screen first should be choosen if 
  794.  * two fishies match what is typed
  795.  */
  796. void UpdateTux(unsigned char letter_pressed, int fishies, int frame) {
  797.     int i;
  798.     int time_it_splats=0;
  799.     int which=-1;
  800.  
  801.     /* --- move our word array to make room if needed --- */
  802.  
  803.     if (tux_object.wordlen == MAX_WORD_SIZE) {
  804.         for (i = 0; i < MAX_WORD_SIZE; i++) 
  805.             tux_object.word[i] = tux_object.word[i + 1];
  806.         tux_object.wordlen--;
  807.     }
  808.  
  809.     /* --- add letter pressed to word array --- */
  810.  
  811.     tux_object.word[tux_object.wordlen] = letter_pressed;
  812.     tux_object.wordlen++;
  813.     tux_object.word[tux_object.wordlen] = 0;
  814.  
  815.     /* choose the word that matchs what has been typed  */
  816.     /* and will hit the ground first                    */
  817.     for (i = 0; i < fishies; i++) 
  818.         if ((fish_object[i].alive && !fish_object[i].can_eat) && check_word(i) && (time_it_splats > fish_object[i].splat_time || !time_it_splats)) {
  819.             time_it_splats = fish_object[i].splat_time;
  820.             which = i;
  821.         }
  822.  
  823.     if (which!=-1) {
  824.         fish_object[which].can_eat = 1;
  825.         tux_object.wordlen = 0;
  826.         tux_object.word[0] = 0;
  827.     }
  828.  
  829. }
  830.  
  831. /*************************
  832. CheckCollision: Check
  833. for collisions between Tux
  834. and Fishies. If collided,
  835. perform appropriate action
  836. ***************************/
  837. void CheckCollision(int fishies, int *fish_left, int frame ) {
  838.     int i, j;
  839.  
  840.     LOG( "start CheckCollision\n" );
  841.  
  842.     for (i = 0; i < fishies; i++) {
  843.         if ((fish_object[i].y >= tux_object.y - fishy->frame[0]->h) &&
  844.             (fish_object[i].x + (fish_object[i].w-fishy->frame[0]->w)/2 >= tux_object.x) &&
  845.             (fish_object[i].x + (fish_object[i].w+fishy->frame[0]->w)/2 <= tux_object.x + tux_max_width)) {
  846.  
  847.             if (fish_object[i].can_eat) {
  848.                         LOG( "**EATING A FISHY** - in CheckCollision()\n" );
  849.  
  850.                 fish_object[i].alive = 0;
  851.                 fish_object[i].can_eat = 0;
  852.  
  853.                 for (j = 0; j < fish_object[i].len; j++) 
  854.                     EraseSprite(fishy, (fish_object[i].x + (j * fishy->frame[0]->w)), fish_object[i].y);
  855.  
  856.                 *fish_left = *fish_left - 1;
  857.  
  858.                 tux_object.state = TUX_GULPING;
  859.                 rewind(tux_object.spr[TUX_GULPING][tux_object.facing]);
  860.                 tux_object.dx = 0;
  861.                 tux_object.endx = tux_object.x;
  862.  
  863.                 if (sys_sound) Mix_PlayChannel(BITE_WAV, sound[BITE_WAV], 0);
  864.  
  865.             } else if (tux_object.state == TUX_STANDING) {
  866.                 LOG( "***EXCUSE ME!** - in CheckCollision()\n" );
  867.  
  868.                 if (sys_sound && !Mix_Playing(EXCUSEME_WAV))
  869.                     Mix_PlayChannel(EXCUSEME_WAV, sound[EXCUSEME_WAV], 0);
  870.             }
  871.         }
  872.     }
  873.     LOG( "end CheckCollision\n" );
  874. }
  875.  
  876. void next_tux_frame(void) {
  877.  
  878.     if ( tux_object.state != TUX_GULPING ) {
  879.         next_frame(tux_object.spr[tux_object.state][tux_object.facing]);
  880.     } else {
  881.         next_frame(tux_object.spr[TUX_GULPING][tux_object.facing]);
  882.         if (tux_object.spr[TUX_GULPING][tux_object.facing]->cur==0) 
  883.             tux_object.state = TUX_STANDING;
  884.     }
  885. }
  886.  
  887. /***********************************
  888. MoveTux : Update Tux's location & then blit him!
  889. ************************************/
  890. void MoveTux( int frame, int fishies ) {
  891.     int i;
  892.     int which=-1, time_to_splat=0;
  893.  
  894.     LOG( "MoveTux\n" );
  895.  
  896.     EraseSprite( tux_object.spr[tux_object.state][tux_object.facing], tux_object.x, tux_object.y );
  897.  
  898.     if (tux_object.state != TUX_GULPING) {
  899.         for (i=0; i<fishies; i++) 
  900.             if (fish_object[i].can_eat && (!time_to_splat || fish_object[i].splat_time < time_to_splat)) {
  901.                 time_to_splat = fish_object[i].splat_time;
  902.                 which = i;
  903.             }
  904.         if (which != -1) {
  905.             int endx = int_restrict( 0, fish_object[which].x + (fish_object[which].w/2) - (tux_object.spr[TUX_GULPING][RIGHT]->frame[0]->w / 2), screen->w - tux_max_width - 1 );
  906.             if (endx != tux_object.endx) {
  907.                 tux_object.endx = endx;
  908.  
  909.                 if (tux_object.endx >= tux_object.x)
  910.                     tux_object.facing = RIGHT;
  911.                 else
  912.                     tux_object.facing = LEFT;
  913.  
  914.                 /* see how fast we need to go to get there... */
  915.                 if (time_to_splat - frame > (abs(tux_object.endx - tux_object.x) / WALKING_SPEED)) {
  916.                     tux_object.dx = WALKING_SPEED;
  917.                     tux_object.state = TUX_WALKING;
  918.  
  919.                     //stop running sound (if playing)                                               
  920.                     if (sys_sound && Mix_Playing(RUN_WAV))
  921.                         Mix_HaltChannel(RUN_WAV);
  922.                 } else {
  923.                     if (time_to_splat > frame) 
  924.                         tux_object.dx = float_restrict( MIN_RUNNING_SPEED, abs(tux_object.endx - tux_object.x) / (time_to_splat-frame), MAX_RUNNING_SPEED );
  925.                     else {
  926.                         tux_object.dx = MAX_RUNNING_SPEED;
  927.                         if (sys_sound && !Mix_Playing(RUN_WAV))
  928.                             if (abs(tux_object.endx - tux_object.x) > 50)
  929.                                 Mix_PlayChannel(RUN_WAV, sound[RUN_WAV], 0);
  930.                     }
  931.  
  932.                     tux_object.state = TUX_RUNNING;
  933.                 }
  934.             }
  935.         }
  936.     }
  937.  
  938.     /* --- move tux (if moving) --- */
  939.     
  940.     tux_object.x = float_restrict(0, tux_object.x + (tux_object.facing==RIGHT ? 1.0 : -1.0)*tux_object.dx, (screen->w - tux_max_width));
  941.  
  942.     /* if done with certain frames, then reset to standing */
  943.  
  944.     if (tux_object.state == TUX_WALKING || tux_object.state == TUX_RUNNING) {
  945.         if ((tux_object.facing == RIGHT && tux_object.x >= tux_object.endx) ||
  946.             (tux_object.facing == LEFT && tux_object.x <= tux_object.endx)) {
  947.  
  948.             LOG( "-In MoveTux(): returning tux to standing\n" );
  949.             tux_object.state = TUX_STANDING;
  950.             tux_object.dx = 0;
  951.             tux_object.x = tux_object.endx;
  952.         }
  953.     }
  954.  
  955.     if ((frame % 8) == 0) next_tux_frame();
  956. }
  957.  
  958. void draw_bar(int curlevel, int diflevel, int curlives, int oldlives, int fish_left, int oldfish_left) {
  959.     /* --- draw difficulty --- */
  960.  
  961.     DrawObject(level[diflevel], 1, 1);
  962.  
  963.     /* --- draw level --- */
  964.     DrawObject(curlev, 1 + GRAPHIC_SPACE + level[diflevel]->w, 1);
  965.     DrawNumbers(curlevel + 1, 1 + 2 * GRAPHIC_SPACE + level[diflevel]->w + curlev->w, 1, 0);
  966.  
  967.     /* --- draw lives --- */
  968.     DrawObject(lives, (screen->w) - (1+lives->w+fish->w+((MAX_FISHIES_DIGITS+1)*2*number_max_w)+GRAPHIC_SPACE), 1);
  969.  
  970.     if (oldlives != curlives) {
  971.         EraseNumbers(oldlives, (screen->w) - (1+fish->w+((MAX_FISHIES_DIGITS+1)*2*number_max_w)+GRAPHIC_SPACE), 1, 0);
  972.         oldlives = curlives;
  973.     }
  974.  
  975.     DrawNumbers(curlives, (screen->w) - (1 + fish->w + ((MAX_FISHIES_DIGITS + 1) * 2 * number_max_w) + GRAPHIC_SPACE), 1, 0);
  976.  
  977.     /* --- draw fish left --- */
  978.     DrawObject(fish, (screen->w) - (1 + fish->w + (MAX_FISHIES_DIGITS * number_max_w)), 1);
  979.     if (oldfish_left != fish_left) {
  980.         EraseNumbers(oldfish_left, (screen->w) - (1 + (MAX_FISHIES_DIGITS * number_max_w)), 1, MAX_FISHIES_DIGITS);
  981.         oldfish_left = fish_left;
  982.     }
  983.     DrawNumbers(fish_left, (screen->w) - (1 + (MAX_FISHIES_DIGITS * number[4]->w)), 1, MAX_FISHIES_DIGITS);
  984. }
  985.  
  986. // This creates our letters.  Black outlined white letters
  987. SDL_Surface *ttf_letter(unsigned char ch, SDL_Color c) {
  988.     SDL_Surface *out, *temp;
  989.     SDL_Rect dstrect;
  990.     unsigned char let[2] = " ";
  991.     out = SDL_CreateRGBSurface(screen->flags, 36, 50, 24, 0, 0, 0, 0);
  992.     SDL_FillRect(out, NULL, SDL_MapRGB(out->format, 255, 255, 0));
  993.  
  994.     let[0] = ch;
  995.     temp = TTF_RenderText_Solid(font, let, black);
  996.     dstrect.w = temp->w;
  997.     dstrect.h = temp->h;
  998.     dstrect.x = 17 - (temp->w) / 2;
  999.     dstrect.y = 24 - (temp->h) / 2;
  1000.     SDL_BlitSurface(temp, NULL, out, &dstrect);
  1001.     dstrect.x += 2;
  1002.     SDL_BlitSurface(temp, NULL, out, &dstrect);
  1003.     dstrect.y += 2;
  1004.     SDL_BlitSurface(temp, NULL, out, &dstrect);
  1005.     dstrect.x -= 2;
  1006.     SDL_BlitSurface(temp, NULL, out, &dstrect);
  1007.     SDL_FreeSurface(temp);
  1008.     temp = TTF_RenderText_Solid(font, let, c);
  1009.     dstrect.x++;
  1010.     dstrect.y--;
  1011.     SDL_BlitSurface(temp, NULL, out, &dstrect);
  1012.     SDL_FreeSurface(temp);
  1013.  
  1014. // From here to the end is just to correct for the fact that the
  1015. // letters aren't centered on the texture we create...  It 
  1016. // is a horrible way to do it, but it works :)
  1017.     {
  1018.         int a, A;
  1019.         int r, g, b;
  1020.         int min = out->w, max = 0;
  1021.         SDL_Rect tt;
  1022.         Uint8 *t = out->pixels;
  1023.         for (A = 0; A < out->h; A++) {
  1024.             for (a = 0; a < out->w; a++) {
  1025.                 r = *t;
  1026.                 t++;
  1027.                 g = *t;
  1028.                 t++;
  1029.                 b = *t;
  1030.                 t++;
  1031.                 if ((r != 255) || (g != 255) || (b != 0)) {
  1032.                     if (a < min)
  1033.                         min = a;
  1034.                     if (a > max)
  1035.                         max = a;
  1036.                 }
  1037.             }
  1038.         }
  1039.         temp = SDL_CreateRGBSurface(screen->flags, 36, 50, 24, 0, 0, 0, 0);
  1040.         SDL_FillRect(temp, NULL, SDL_MapRGB(out->format, 255, 255, 0));
  1041.         tt.x = min;
  1042.         tt.y = 0;
  1043.         dstrect.w = tt.w = max - min + 1;
  1044.         dstrect.h = tt.h = 50;
  1045.         dstrect.x = 18 - (tt.w / 2);
  1046.         dstrect.y = 1;
  1047.  
  1048.         SDL_BlitSurface(out, &tt, temp, &dstrect);
  1049.         SDL_SetColorKey(temp, (SDL_SRCCOLORKEY | SDL_RLEACCEL),
  1050.                         SDL_MapRGB(temp->format, 255, 255, 0));
  1051.         SDL_FreeSurface(out);
  1052.     }
  1053.     return temp;
  1054. }
  1055.  
  1056. /*************************************************************************
  1057. * PlayCascade : This is the main Cascade game loop               *
  1058. *************************************************************************/
  1059. int PlayCascade( int diflevel ) {
  1060.     unsigned char filename[FNLEN];
  1061.     int still_playing = 1;
  1062.     int playing_level = 1;
  1063.     int setup_new_level = 1;
  1064.     int won_level = 0;
  1065.     int quitting = 0;
  1066.     int curlevel = 0;
  1067.     int i;
  1068.     int curlives;
  1069.     int oldlives=0, oldfish_left=0;
  1070.     int fish_left, fishies = 0, local_max_fishies=1;
  1071.     int frame = 0;
  1072.     int done_frames;
  1073.     int splats = 0;
  1074.     SDL_Event event;
  1075.     SDL_Surface *temp_text[CONGRATS_FRAMES + OH_NO_FRAMES];
  1076.     SDL_Rect text_rect;
  1077.     int text_y_end;
  1078.     int xamp, yamp, x_not, y_not;
  1079.     int temp_text_frames;
  1080.     int temp_text_count;
  1081.  
  1082.     DEBUGCODE {
  1083.         fprintf(stderr, "->PlayCascade: level=%i\n", diflevel );
  1084.     }
  1085.  
  1086.     SDL_WarpMouse(screen->w / 2, screen->h / 2);
  1087.     SDL_ShowCursor(0);
  1088.  
  1089.     SNOW_init();
  1090.  
  1091.     LoadTuxAnims(); 
  1092.     LoadFishies();
  1093.     LoadOthers();
  1094.  
  1095.     create_letters();
  1096.     
  1097.     LOG( " starting game \n ");
  1098.     while (still_playing) {
  1099.  
  1100.         if (setup_new_level) {
  1101.  
  1102.             switch (diflevel) {
  1103.                 case EASY:
  1104.                             fish_left = MAX_FISHIES_EASY;
  1105.                             if (o_lives >  LIVES_INIT_EASY){
  1106.                                 curlives = o_lives;
  1107.                         }else
  1108.                             curlives = LIVES_INIT_EASY;
  1109.                             break;
  1110.                 case MEDIUM:
  1111.                             fish_left = MAX_FISHIES_MEDIUM;
  1112.                             if (o_lives >  LIVES_INIT_MEDIUM){
  1113.                                 curlives = o_lives;
  1114.                         }else
  1115.                             curlives =  LIVES_INIT_MEDIUM;
  1116.                             break;
  1117.                 case HARD:
  1118.                             fish_left = MAX_FISHIES_HARD;
  1119.                             if (o_lives >  LIVES_INIT_HARD){
  1120.                                 curlives = o_lives;
  1121.                         }else
  1122.                             curlives =  LIVES_INIT_HARD;
  1123.                             break;
  1124.             }
  1125.  
  1126.             local_max_fishies = fish_left;
  1127.  
  1128.             if (curlevel != 0) {
  1129.                 SDL_FreeSurface(background);
  1130.             }
  1131.  
  1132.             if (diflevel == INF_PRACT)
  1133.                 sprintf(filename, "pract.png");
  1134.             else
  1135.                 sprintf(filename, "kcas%i_%i.png", diflevel+1, curlevel+1);
  1136.  
  1137.             /* ---  Special Hidden Code  --- */
  1138.  
  1139.             if (hidden && curlevel == 3)
  1140.                 sprintf(filename, "hidden.png");
  1141.  
  1142.             DEBUGCODE {
  1143.                 fprintf(stderr, "->>Loading background: %s\n", filename);
  1144.             }
  1145.  
  1146.             background = LoadImage( filename, IMG_REGULAR );
  1147.             SNOW_setBkg( background );
  1148.  
  1149.             DrawBackground();
  1150.  
  1151.             ResetObjects();
  1152.  
  1153.             if (sys_sound) {
  1154.                 sprintf(filename, "kmus%i.wav", curlevel + 1);
  1155.                 audioMusicLoad( filename, -1 );
  1156.             }
  1157.  
  1158.             LOG( "->>PLAYING THE GAME\n" );
  1159.  
  1160.             setup_new_level = 0;
  1161.         }
  1162.  
  1163.         /* --- Poll input queue, get keyboard info --- */
  1164.  
  1165.         while (playing_level) {
  1166.  
  1167.             oldlives = curlives;
  1168.             oldfish_left = fish_left;
  1169.  
  1170.             EraseSprite( tux_object.spr[tux_object.state][tux_object.facing], tux_object.x, tux_object.y );
  1171.  
  1172.             /* --- Checking input --- */
  1173.  
  1174.             while ( SDL_PollEvent( &event ) ) 
  1175.                 if ( event.type == SDL_QUIT ) {
  1176.                     exit(0);
  1177.                 } else if (event.type == SDL_KEYDOWN) {
  1178.     
  1179.                     if (event.key.keysym.sym == SDLK_F11) 
  1180.                         SDL_SaveBMP( screen, "screenshot.bmp" );
  1181.                     if (event.key.keysym.sym == SDLK_F6){
  1182.                         o_lives=o_lives-10;
  1183.                         curlives=curlives-10;
  1184.                     }
  1185.                     if (event.key.keysym.sym == SDLK_F7) {
  1186.                         o_lives=o_lives+10;
  1187.                         curlives=curlives+10;
  1188.                     }
  1189.                     if (event.key.keysym.sym == SDLK_F12) 
  1190.                         SNOW_toggle();
  1191.                     if (event.key.keysym.sym == SDLK_ESCAPE) {
  1192.  
  1193.                         if (Pause() == 1) {
  1194.                             playing_level = 0;
  1195.                             still_playing = 0;
  1196.                             quitting = 1;
  1197.                         } 
  1198.                         DrawBackground();
  1199.                     }
  1200.                     if ((event.key.keysym.unicode & 0xff) > 31)
  1201.                         UpdateTux(KEYMAP[event.key.keysym.unicode & 0xff], fishies, frame);
  1202.                 }
  1203.  
  1204.             /* --- fishy updates --- */
  1205.  
  1206.             if ((frame % 10) == 0) next_frame( fishy );
  1207.             
  1208.             if (fishies < local_max_fishies)
  1209.                 SpawnFishies( diflevel, &fishies, &frame );
  1210.  
  1211.             MoveTux( frame, fishies );
  1212.             CheckCollision(fishies, &fish_left, frame );
  1213.             DrawSprite( tux_object.spr[tux_object.state][tux_object.facing], tux_object.x, tux_object.y );
  1214.             MoveFishies(&fishies, &splats, &curlives, &frame);
  1215.             CheckFishies(&fishies, &splats);
  1216.             SNOW_update();
  1217.  
  1218.             /* --- update top score/info bar --- */
  1219.  
  1220.             if (diflevel != INF_PRACT) {
  1221.                 draw_bar(curlevel, diflevel, curlives, oldlives, fish_left, oldfish_left);
  1222.  
  1223.                 if (curlives <= 0) {
  1224.                     playing_level = 0;
  1225.                     still_playing = 0;
  1226.                 }
  1227.             } else
  1228.                 fish_left = 1; // in practice there is always 1 fish left!
  1229.  
  1230.             if (fish_left <= 0) {
  1231.                 won_level = 1;
  1232.                 playing_level = 0;
  1233.                 curlevel++;
  1234.                 setup_new_level = 1;
  1235.                 still_playing = 1;
  1236.             }
  1237.  
  1238.             if (!quitting) {
  1239.                 UpdateScreen(&frame);
  1240.  
  1241.                 if (speed_up == 0)
  1242.                     WaitFrame();
  1243.             }
  1244.         }
  1245.  
  1246.         if (sys_sound)
  1247.             Mix_FadeOutMusic(MUSIC_FADE_OUT_MS);
  1248.  
  1249.         DrawBackground();
  1250.  
  1251.         if (quitting == 0) {
  1252.  
  1253.             if (won_level) {
  1254.  
  1255.                 won_level = 0;
  1256.                 if (curlevel < 4) {
  1257.  
  1258.                     LOG( "--->NEXT LEVEL!\n" );
  1259.  
  1260.                     done_frames = MAX_END_FRAMES_BETWEEN_LEVELS;
  1261.                     playing_level = 1;
  1262.                     xamp = 0;
  1263.                     yamp = 0;
  1264.  
  1265.                 } else {
  1266.  
  1267.                     LOG( "--->WINNER!\n" );
  1268.  
  1269.                     done_frames = MAX_END_FRAMES_WIN_GAME;
  1270.                     still_playing = 0;
  1271.                     xamp = WIN_GAME_XAMP;
  1272.                     yamp = WIN_GAME_YAMP;
  1273.  
  1274.                     if (sys_sound) 
  1275.                         Mix_PlayChannel(WINFINAL_WAV, sound[WINFINAL_WAV], 0);
  1276.                 }
  1277.  
  1278.                 if (sys_sound) 
  1279.                     Mix_PlayChannel(WIN_WAV, sound[WIN_WAV], 0);
  1280.  
  1281.                 for (i = 0; i < CONGRATS_FRAMES; i++)
  1282.                     temp_text[i] = congrats[i];
  1283.  
  1284.                 temp_text_frames = CONGRATS_FRAMES;
  1285.                 tux_object.state = TUX_WINNING;
  1286.  
  1287.             } else {
  1288.  
  1289.                 LOG( "--->LOST :(\n" );
  1290.  
  1291.                 done_frames = MAX_END_FRAMES_GAMEOVER;
  1292.                 xamp = 0;
  1293.                 yamp = 0;
  1294.  
  1295.                 if (sys_sound)
  1296.                     Mix_PlayChannel(LOSE_WAV, sound[LOSE_WAV], 0);
  1297.  
  1298.                 for (i = 0; i < OH_NO_FRAMES; i++)
  1299.                     temp_text[i] = ohno[i];
  1300.  
  1301.                 temp_text_frames = OH_NO_FRAMES;
  1302.                 tux_object.state = TUX_YIPING;
  1303.             }
  1304.  
  1305.             /* --- draw the animation here --- */
  1306.  
  1307.             temp_text_count = 0;
  1308.             text_y_end = (screen->h / 2) - (temp_text[0]->h / 2);
  1309.             text_rect.x = (screen->w / 2) - (temp_text[0]->w / 2);
  1310.             text_rect.y = screen->h - temp_text[0]->h - 1;
  1311.             x_not = text_rect.x;
  1312.  
  1313.             LOG( "--->Starting Ending Animation\n" );
  1314.             
  1315.             for ( i=0; i<= done_frames; i++ ) {
  1316.                 temp_text_count = (temp_text_count+1) % temp_text_frames;
  1317.  
  1318.                 text_rect.y -= END_FRAME_DY;
  1319.                 y_not = text_rect.y;
  1320.  
  1321.                 if (text_rect.y < text_y_end) {
  1322.                     y_not = text_y_end + yamp * sin(i / WIN_GAME_ANGLE_MULT);
  1323.                     text_rect.y = text_y_end;
  1324.                     text_rect.x = x_not + xamp * cos(i / WIN_GAME_ANGLE_MULT);
  1325.                 }
  1326.  
  1327.                 DrawSprite( tux_object.spr[tux_object.state][tux_object.facing], tux_object.x, tux_object.y );
  1328.                 DrawObject(temp_text[temp_text_count], text_rect.x, y_not);
  1329.                 DrawObject(level[diflevel], 1, 1);
  1330.                 draw_bar(curlevel - 1, diflevel, curlives, oldlives, fish_left, oldfish_left);
  1331.  
  1332.                 next_tux_frame();
  1333.                 SNOW_update();
  1334.                 UpdateScreen(&frame);
  1335.  
  1336.                 EraseSprite( tux_object.spr[tux_object.state][tux_object.facing], tux_object.x, tux_object.y );
  1337.                 
  1338.                 EraseObject(temp_text[temp_text_count], text_rect.x, y_not);
  1339.  
  1340.                 if (speed_up == 0)
  1341.                     WaitFrame();
  1342.             }
  1343.         }
  1344.     }
  1345.  
  1346.     SNOW_on = 0;
  1347.  
  1348.     LOG( "->Done with level... cleaning up\n" );
  1349.  
  1350.     FreeGame();
  1351.  
  1352.     LOG( "->PlayCascade: END\n" );
  1353.  
  1354.     return 1;
  1355. }
  1356.  
  1357. /*************************************************/
  1358. /* TransWipe: Performs various wipes to new bkgs */
  1359. /*************************************************/
  1360. /*
  1361.  * Given a wipe request type, and any variables
  1362.  * that wipe requires, will perform a wipe from
  1363.  * the current screen image to a new one.
  1364.  */
  1365. void TransWipe(SDL_Surface * newbkg, int type, int var1, int var2)
  1366. {
  1367.     int i, j, x1, x2, y1, y2;
  1368.     int step1, step2, step3, step4;
  1369.     int frame;
  1370.     SDL_Rect src;
  1371.     SDL_Rect dst;
  1372.  
  1373.     LOG("->TransWipe(): START\n");
  1374.  
  1375.     numupdates = 0;
  1376.     frame = 0;
  1377.  
  1378.     if(newbkg->w == screen->w && newbkg->h == screen->h) {
  1379.         if( type == RANDOM_WIPE )
  1380.             type = (RANDOM_WIPE* ((float) rand()) / (RAND_MAX+1.0));
  1381.  
  1382.         switch( type ) {
  1383.             case WIPE_BLINDS_VERT: {
  1384.                 LOG("--+ Doing 'WIPE_BLINDS_VERT'\n");
  1385.                 /* var1 is num of divisions
  1386.                    var2 is how many frames animation should take */
  1387.                 if( var1 < 1 ) var1 = 1;
  1388.                 if( var2 < 1 ) var2 = 1;
  1389.                 step1 = screen->w / var1;
  1390.                 step2 = step1 / var2;
  1391.  
  1392.                 for(i = 0; i <= var2; i++) {
  1393.                     for(j = 0; j <= var1; j++) {
  1394.                         x1 = step1 * (j - 0.5) - i * step2 + 1;
  1395.                         x2 = step1 * (j - 0.5) + i * step2 + 1;
  1396.                         src.x = x1;
  1397.                         src.y = 0;
  1398.                         src.w = step2;
  1399.                         src.h = screen->h;
  1400.                         dst.x = x2;
  1401.                         dst.y = 0;
  1402.                         dst.w = step2;
  1403.                         dst.h = screen->h;
  1404.                         SDL_BlitSurface(newbkg, &src, screen, &src);
  1405.                         SDL_BlitSurface(newbkg, &dst, screen, &dst);
  1406.                         AddRect(&src, &src);
  1407.                         AddRect(&dst, &dst);
  1408.                     }
  1409.                     UpdateScreen(&frame);
  1410.                 }
  1411.  
  1412.                 src.x = 0;
  1413.                 src.y = 0;
  1414.                 src.w = screen->w;
  1415.                 src.h = screen->h;
  1416.                 SDL_BlitSurface(newbkg, NULL, screen, &src);
  1417.                 SDL_Flip(screen);
  1418.  
  1419.                 break;
  1420.             } case WIPE_BLINDS_HORIZ: {
  1421.                 LOG("--+ Doing 'WIPE_BLINDS_HORIZ'\n");
  1422.                 /* var1 is num of divisions
  1423.                    var2 is how many frames animation should take */
  1424.                 if( var1 < 1 ) var1 = 1;
  1425.                 if( var2 < 1 ) var2 = 1;
  1426.                 step1 = screen->h / var1;
  1427.                 step2 = step1 / var2;
  1428.  
  1429.                 for(i = 0; i <= var2; i++) {
  1430.                     for(j = 0; j <= var1; j++) {
  1431.                         y1 = step1 * (j - 0.5) - i * step2 + 1;
  1432.                         y2 = step1 * (j - 0.5) + i * step2 + 1;
  1433.                         src.x = 0;
  1434.                         src.y = y1;
  1435.                         src.w = screen->w;
  1436.                         src.h = step2;
  1437.                         dst.x = 0;
  1438.                         dst.y = y2;
  1439.                         dst.w = screen->w;
  1440.                         dst.h = step2;
  1441.                         SDL_BlitSurface(newbkg, &src, screen, &src);
  1442.                         SDL_BlitSurface(newbkg, &dst, screen, &dst);
  1443.                         AddRect(&src, &src);
  1444.                         AddRect(&dst, &dst);
  1445.                     }
  1446.                     UpdateScreen(&frame);
  1447.                 }
  1448.  
  1449.                 src.x = 0;
  1450.                 src.y = 0;
  1451.                 src.w = screen->w;
  1452.                 src.h = screen->h;
  1453.                 SDL_BlitSurface(newbkg, NULL, screen, &src);
  1454.                 SDL_Flip(screen);
  1455.  
  1456.                 break;
  1457.             } case WIPE_BLINDS_BOX: {
  1458.                 LOG("--+ Doing 'WIPE_BLINDS_BOX'\n");
  1459.                 /* var1 is num of divisions
  1460.                    var2 is how many frames animation should take */
  1461.                 if( var1 < 1 ) var1 = 1;
  1462.                 if( var2 < 1 ) var2 = 1;
  1463.                 step1 = screen->w / var1;
  1464.                 step2 = step1 / var2;
  1465.                 step3 = screen->h / var1;
  1466.                 step4 = step1 / var2;
  1467.  
  1468.                 for(i = 0; i <= var2; i++) {
  1469.                     for(j = 0; j <= var1; j++) {
  1470.                         x1 = step1 * (j - 0.5) - i * step2 + 1;
  1471.                         x2 = step1 * (j - 0.5) + i * step2 + 1;
  1472.                         src.x = x1;
  1473.                         src.y = 0;
  1474.                         src.w = step2;
  1475.                         src.h = screen->h;
  1476.                         dst.x = x2;
  1477.                         dst.y = 0;
  1478.                         dst.w = step2;
  1479.                         dst.h = screen->h;
  1480.                         SDL_BlitSurface(newbkg, &src, screen, &src);
  1481.                         SDL_BlitSurface(newbkg, &dst, screen, &dst);
  1482.                         AddRect(&src, &src);
  1483.                         AddRect(&dst, &dst);
  1484.                         y1 = step3 * (j - 0.5) - i * step4 + 1;
  1485.                         y2 = step3 * (j - 0.5) + i * step4 + 1;
  1486.                         src.x = 0;
  1487.                         src.y = y1;
  1488.                         src.w = screen->w;
  1489.                         src.h = step4;
  1490.                         dst.x = 0;
  1491.                         dst.y = y2;
  1492.                         dst.w = screen->w;
  1493.                         dst.h = step4;
  1494.                         SDL_BlitSurface(newbkg, &src, screen, &src);
  1495.                         SDL_BlitSurface(newbkg, &dst, screen, &dst);
  1496.                         AddRect(&src, &src);
  1497.                         AddRect(&dst, &dst);
  1498.                     }
  1499.                     UpdateScreen(&frame);
  1500.                 }
  1501.  
  1502.                 src.x = 0;
  1503.                 src.y = 0;
  1504.                 src.w = screen->w;
  1505.                 src.h = screen->h;
  1506.                 SDL_BlitSurface(newbkg, NULL, screen, &src);
  1507.                 SDL_Flip(screen);
  1508.  
  1509.                 break;
  1510.             } default:
  1511.                 break;
  1512.         }
  1513.     }
  1514. }
  1515.  
  1516.