| 
							- //
 - // "$Id: blocks.cxx 7904 2010-11-28 21:12:59Z matt $"
 - //
 - // "Block Attack!" scrolling blocks game using the Fast Light Tool Kit (FLTK).
 - //
 - // Copyright 2006-2010 by Michael Sweet.
 - //
 - // This library is free software; you can redistribute it and/or
 - // modify it under the terms of the GNU Library General Public
 - // License as published by the Free Software Foundation; either
 - // version 2 of the License, or (at your option) any later version.
 - //
 - // This library is distributed in the hope that it will be useful,
 - // but WITHOUT ANY WARRANTY; without even the implied warranty of
 - // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - // Library General Public License for more details.
 - //
 - // You should have received a copy of the GNU Library General Public
 - // License along with this library; if not, write to the Free Software
 - // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 - // USA.
 - //
 - // Please report all bugs and problems on the following page:
 - //
 - //     http://www.fltk.org/str.php
 - //
 - 
 - #include <FL/Fl.H>
 - #include <FL/Fl_Double_Window.H>
 - #include <FL/Fl_Button.H>
 - #include <FL/Fl_Preferences.H>
 - #include <FL/Fl_XPM_Image.H>
 - #include <FL/Fl_XBM_Image.H>
 - #include <FL/Fl_Tiled_Image.H>
 - #include <FL/fl_draw.H>
 - #include <FL/x.H>
 - #include <stdio.h>
 - #include <stdlib.h>
 - #include <string.h>
 - #include <time.h>
 - #include <math.h>
 - 
 - // Audio headers...
 - #include <config.h>
 - 
 - #ifndef WIN32
 - #  include <unistd.h>
 - #  include <sys/time.h>
 - #endif // !WIN32
 - 
 - #ifdef HAVE_ALSA_ASOUNDLIB_H
 - #  define ALSA_PCM_NEW_HW_PARAMS_API
 - #  include <alsa/asoundlib.h>
 - #endif // HAVE_ALSA_ASOUNDLIB_H
 - #ifdef __APPLE__
 - #  include <CoreAudio/AudioHardware.h>
 - #endif // __APPLE__
 - #ifdef WIN32
 - #  include <mmsystem.h>
 - #endif // WIN32
 - 
 - 
 - #define BLOCK_COLS	20
 - #define BLOCK_ROWS	10
 - #define BLOCK_SIZE	32
 - #define BLOCK_BLAST	100
 - 
 - #include "pixmaps/blast.xpm"
 - Fl_Pixmap blast_pixmap(blast_xpm);
 - 
 - #include "pixmaps/red.xpm"
 - Fl_Pixmap red_pixmap(red_xpm);
 - #include "pixmaps/red_bomb.xpm"
 - Fl_Pixmap red_bomb_pixmap(red_bomb_xpm);
 - 
 - #include "pixmaps/green.xpm"
 - Fl_Pixmap green_pixmap(green_xpm);
 - #include "pixmaps/green_bomb.xpm"
 - Fl_Pixmap green_bomb_pixmap(green_bomb_xpm);
 - 
 - #include "pixmaps/blue.xpm"
 - Fl_Pixmap blue_pixmap(blue_xpm);
 - #include "pixmaps/blue_bomb.xpm"
 - Fl_Pixmap blue_bomb_pixmap(blue_bomb_xpm);
 - 
 - #include "pixmaps/yellow.xpm"
 - Fl_Pixmap yellow_pixmap(yellow_xpm);
 - #include "pixmaps/yellow_bomb.xpm"
 - Fl_Pixmap yellow_bomb_pixmap(yellow_bomb_xpm);
 - 
 - #include "pixmaps/cyan.xpm"
 - Fl_Pixmap cyan_pixmap(cyan_xpm);
 - #include "pixmaps/cyan_bomb.xpm"
 - Fl_Pixmap cyan_bomb_pixmap(cyan_bomb_xpm);
 - 
 - #include "pixmaps/magenta.xpm"
 - Fl_Pixmap magenta_pixmap(magenta_xpm);
 - #include "pixmaps/magenta_bomb.xpm"
 - Fl_Pixmap magenta_bomb_pixmap(magenta_bomb_xpm);
 - 
 - #include "pixmaps/gray.xpm"
 - Fl_Pixmap gray_pixmap(gray_xpm);
 - #include "pixmaps/gray_bomb.xpm"
 - Fl_Pixmap gray_bomb_pixmap(gray_bomb_xpm);
 - 
 - Fl_Pixmap *normal_pixmaps[] = {
 -   &red_pixmap,
 -   &green_pixmap,
 -   &blue_pixmap,
 -   &yellow_pixmap,
 -   &cyan_pixmap,
 -   &magenta_pixmap,
 -   &gray_pixmap
 - };
 - Fl_Pixmap *bomb_pixmaps[] = {
 -   &red_bomb_pixmap,
 -   &green_bomb_pixmap,
 -   &blue_bomb_pixmap,
 -   &yellow_bomb_pixmap,
 -   &cyan_bomb_pixmap,
 -   &magenta_bomb_pixmap,
 -   &gray_bomb_pixmap
 - };
 - 
 - const unsigned char screen_bits[] = {
 -   0xff, 0x55, 0xff, 0xaa, 0xff, 0x55, 0xff, 0xaa
 - };
 - Fl_Bitmap screen_bitmap(screen_bits, 8, 8);
 - Fl_Tiled_Image screen_tile(&screen_bitmap);
 - 
 - 
 - // Sound class...
 - //
 - // There are MANY ways to implement sound in a FLTK application.
 - // The approach we are using here is to conditionally compile OS-
 - // specific code into the application - CoreAudio for MacOS X, the
 - // standard Win32 API stuff for Windows, ALSA or X11 for Linux, and
 - // X11 for all others.  We have to support ALSA on Linux because the
 - // current Xorg releases no longer support XBell() or the PC speaker.
 - //
 - // There are several good cross-platform audio libraries we could also
 - // use, such as OpenAL, PortAudio, and SDL, however they were not chosen
 - // for this application because of our limited use of sound.
 - //
 - // Many thanks to Ian MacArthur who provided sample code that led to
 - // the CoreAudio implementation you see here!
 - class BlockSound {
 -   // Private, OS-specific data...
 - #ifdef __APPLE__
 -   AudioDeviceID device;
 - #  if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
 -   AudioDeviceIOProcID audio_proc_id;
 - #  endif
 -   AudioStreamBasicDescription format;
 -   short *data;
 -   int remaining;
 - 
 -   static OSStatus audio_cb(AudioDeviceID device,
 - 			   const AudioTimeStamp *current_time,
 - 			   const AudioBufferList *data_in,
 - 			   const AudioTimeStamp *time_in,
 - 			   AudioBufferList *data_out,
 - 			   const AudioTimeStamp *time_out,
 - 			   void *client_data);
 - #elif defined(WIN32)
 -   HWAVEOUT	device;
 -   HGLOBAL	header_handle;
 -   LPWAVEHDR	header_ptr;
 -   HGLOBAL	data_handle;
 -   LPSTR		data_ptr;
 - 
 - #else
 - #  ifdef HAVE_ALSA_ASOUNDLIB_H
 -   snd_pcm_t *handle;
 - #  endif // HAVE_ALSA_ASOUNDLIB_H
 - #endif // __APPLE__
 - 
 -   public:
 - 
 -   // Common data...
 -   static short *sample_data;
 -   static int sample_size;
 - 
 -   BlockSound();
 -   ~BlockSound();
 - 
 -   void	play_explosion(float duration);
 - };
 - 
 - // Sound class globals...
 - short *BlockSound::sample_data = NULL;
 - int BlockSound::sample_size = 0;
 - 
 - 
 - // Initialize the BlockSound class
 - BlockSound::BlockSound() {
 -   sample_size = 0;
 - 
 - #ifdef __APPLE__
 -   remaining = 0;
 - 
 -   UInt32 size = sizeof(device);
 - 
 -   if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
 - 			       &size, (void *)&device) != noErr) return;
 - 
 -   size = sizeof(format);
 -   if (AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat,
 - 			     &size, &format) != noErr) return;
 - 
 -   // Set up a format we like...
 -   format.mSampleRate       = 44100.0;	// 44.1kHz
 -   format.mChannelsPerFrame = 2;		// stereo
 - 
 -   if (AudioDeviceSetProperty(device, NULL, 0, false,
 -                              kAudioDevicePropertyStreamFormat,
 - 	                     sizeof(format), &format) != noErr) return;
 - 
 -   // Check we got linear pcm - what to do if we did not ???
 -   if (format.mFormatID != kAudioFormatLinearPCM) return;
 - 
 -   // Attach the callback and start the device
 - #  if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
 -   if (AudioDeviceCreateIOProcID(device, audio_cb, (void *)this, &audio_proc_id) != noErr) return;
 -   AudioDeviceStart(device, audio_proc_id);
 - #  else
 -   if (AudioDeviceAddIOProc(device, audio_cb, (void *)this) != noErr) return;
 -   AudioDeviceStart(device, audio_cb);
 - #  endif
 - 
 -   sample_size = (int)format.mSampleRate;
 - 
 - #elif defined(WIN32)
 -   WAVEFORMATEX	format;
 - 
 -   memset(&format, 0, sizeof(format));
 -   format.cbSize          = sizeof(format);
 -   format.wFormatTag      = WAVE_FORMAT_PCM;
 -   format.nChannels       = 2;
 -   format.nSamplesPerSec  = 44100;
 -   format.nAvgBytesPerSec = 44100 * 4;
 -   format.nBlockAlign     = 4;
 -   format.wBitsPerSample  = 16;
 - 
 -   data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, format.nSamplesPerSec * 4);
 -   if (!data_handle) return;
 - 
 -   data_ptr = (LPSTR)GlobalLock(data_handle);
 - 
 -   header_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR));
 -   if (!header_handle) return;
 - 
 -   header_ptr = (WAVEHDR *)GlobalLock(header_handle);
 - 
 -   header_ptr->lpData  = data_ptr;
 -   header_ptr->dwFlags = 0;
 -   header_ptr->dwLoops = 0;
 - 
 -   if (waveOutOpen(&device, WAVE_MAPPER, &format, 0, 0, WAVE_ALLOWSYNC)
 -           != MMSYSERR_NOERROR) return;
 - 
 -   sample_size = format.nSamplesPerSec;
 - 
 - #else
 - #  ifdef HAVE_ALSA_ASOUNDLIB_H
 -   handle = NULL;
 - 
 -   if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) >= 0) {
 -     // Initialize PCM sound stuff...
 -     snd_pcm_hw_params_t *params;
 - 
 -     snd_pcm_hw_params_alloca(¶ms);
 -     snd_pcm_hw_params_any(handle, params);
 -     snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
 -     snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16);
 -     snd_pcm_hw_params_set_channels(handle, params, 2);
 -     unsigned rate = 44100;
 -     int dir;
 -     snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir);
 -     snd_pcm_uframes_t period = (int)rate;
 -     snd_pcm_hw_params_set_period_size_near(handle, params, &period, &dir);
 - 
 -     sample_size = rate;
 - 
 -     if (snd_pcm_hw_params(handle, params) < 0) {
 -       sample_size = 0;
 -       snd_pcm_close(handle);
 -       handle = NULL;
 -     }
 -   }
 - #  endif // HAVE_ALSA_ASOUNDLIB_H
 - #endif // __APPLE__
 - 
 -   if (sample_size) {
 -     // Make an explosion sound by passing white noise through a low pass
 -     // filter with a decreasing frequency...
 -     sample_data = new short[2 * sample_size];
 - 
 -     short *sample_ptr = sample_data;
 -     int max_sample = 2 * sample_size - 2;
 - 
 -     *sample_ptr++ = 0;
 -     *sample_ptr++ = 0;
 - 
 -     for (int j = max_sample; j > 0; j --, sample_ptr ++) {
 -       float freq = (float)j / (float)max_sample;
 -       float volume = 32767.0 * (0.5 * sqrt(freq) + 0.5);
 -       float sample = 0.0001 * ((rand() % 20001) - 10000);
 - 
 -       *sample_ptr = (int)(volume * freq * sample +
 -                           (1.0 - freq) * sample_ptr[-2]);
 -     }
 -   }
 - }
 - 
 - 
 - // Cleanup the BlockSound class
 - BlockSound::~BlockSound() {
 - #ifdef __APPLE__
 -   if (sample_size) {
 - #  if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
 -     AudioDeviceStop(device, audio_proc_id);
 -     AudioDeviceDestroyIOProcID(device, audio_proc_id);
 - #  else
 -     AudioDeviceStop(device, audio_cb);
 -     AudioDeviceRemoveIOProc(device, audio_cb);
 - #  endif
 -   }
 - 
 - #elif defined(WIN32)
 -   if (sample_size) {
 -     waveOutClose(device);
 - 
 -     GlobalUnlock(header_handle);
 -     GlobalFree(header_handle);
 - 
 -     GlobalUnlock(data_handle);
 -     GlobalFree(data_handle);
 -   }
 - 
 - #else
 - #  ifdef HAVE_ALSA_ASOUNDLIB_H
 -   if (handle) {
 -     snd_pcm_drain(handle);
 -     snd_pcm_close(handle);
 -   }
 - #  endif // HAVE_ALSA_ASOUNDLIB_H
 - #endif // __APPLE__
 - 
 -   if (sample_size) {
 -     delete[] sample_data;
 -   }
 - }
 - 
 - 
 - #ifdef __APPLE__
 - // Callback function for writing audio data...
 - OSStatus
 - BlockSound::audio_cb(AudioDeviceID device,
 - 		     const AudioTimeStamp *current_time,
 - 		     const AudioBufferList *data_in,
 - 		     const AudioTimeStamp *time_in,
 - 		     AudioBufferList *data_out,
 - 		     const AudioTimeStamp *time_out,
 - 		     void *client_data) {
 -   BlockSound *ss = (BlockSound *)client_data;
 -   int count;
 -   float *buffer;
 - 
 -   if (!ss->remaining) return noErr;
 - 
 -   for (count = data_out->mBuffers[0].mDataByteSize / sizeof(float),
 -           buffer = (float*) data_out->mBuffers[0].mData;
 -        ss->remaining > 0 && count > 0;
 -        count --, ss->data ++, ss->remaining --) {
 -     *buffer++ = *(ss->data) / 32767.0;
 -   }
 - 
 -   while (count > 0) {
 -     *buffer++ = 0.0;
 -     count --;
 -   }
 - 
 -   return noErr;
 - }
 - #endif // __APPLE__
 - 
 - 
 - // Play a note for the given amount of time...
 - void
 - BlockSound::play_explosion(float duration) {
 -   Fl::check();
 - 
 -   if (duration <= 0.0)
 -     return;
 - 
 - #if defined(__APPLE__) || defined(WIN32) || defined(HAVE_ALSA_ASOUNDLIB_H)
 -   if (duration > 1.0)
 -     duration = 1.0;
 - 
 -   int samples = (int)(duration * sample_size);
 -   short *sample_ptr = sample_data + 2 * (sample_size - samples);
 - #endif // __APPLE__ || WIN32 || HAVE_ALSA_ASOUNDLIB_H
 - 
 - #ifdef __APPLE__
 -   // Point to the next note...
 -   data      = sample_ptr;
 -   remaining = samples * 2;
 - 
 - #elif defined(WIN32)
 -   if (sample_size) {
 -     memcpy(data_ptr, sample_ptr, samples * 4);
 - 
 -     header_ptr->dwBufferLength = samples * 4;
 -     waveOutPrepareHeader(device, header_ptr, sizeof(WAVEHDR));
 - 
 -     waveOutWrite(device, header_ptr, sizeof(WAVEHDR));
 -   } else Beep(440, (int)(1000.0 * duration));
 - 
 - #elif defined(HAVE_ALSA_ASOUNDLIB_H)
 -   if (handle) {
 -     // Use ALSA to play the sound...
 -     if (snd_pcm_writei(handle, sample_ptr, samples) < 0) {
 -       snd_pcm_prepare(handle);
 -       snd_pcm_writei(handle, sample_ptr, samples);
 -     }
 -     return;
 -   }
 - #endif // __APPLE__
 - }
 - 
 - 
 - class BlockWindow : public Fl_Double_Window
 - {
 -   public:
 - 
 -   struct Block
 -   {
 -     int		color;
 -     bool	bomb;
 -     int		y;
 -   };
 - 
 -   struct Column
 -   {
 -     int		num_blocks;
 -     Block	blocks[BLOCK_ROWS];
 -     int		x;
 -   };
 - 
 -   private:
 - 
 -   Fl_Button	*help_button_,
 - 		*play_button_;
 - 
 -   int		num_columns_;
 -   Column	columns_[BLOCK_COLS];
 -   int		count_;
 -   bool		help_;
 -   int		high_score_;
 -   float		interval_;
 -   int		level_;
 -   int		num_colors_;
 -   int		opened_columns_;
 -   bool		paused_;
 -   static Fl_Preferences	prefs_;
 -   int		score_;
 -   BlockSound	*sound_;
 -   char		title_[255];
 -   int		title_y_;
 - 
 -   void		_BlockWindow();
 -   int		bomb(int color);
 -   int		click(int col, int row);
 -   static void	help_cb(Fl_Widget *wi, BlockWindow *bw);
 -   void		init();
 -   static void	play_cb(Fl_Widget *wi, BlockWindow *bw);
 -   static void	timeout_cb(BlockWindow *bw);
 - 
 -   public:
 - 
 -   BlockWindow(int X, int Y, int W, int H, const char *L = 0);
 -   BlockWindow(int W, int H, const char *L = 0);
 -   ~BlockWindow();
 - 
 -   void		draw();
 -   int		handle(int event);
 -   void		new_game();
 -   int		score() { return (score_); }
 -   void          up_level();
 - };
 - 
 - 
 - Fl_Preferences	BlockWindow::prefs_(Fl_Preferences::USER, "fltk.org", "blocks");
 - 
 - 
 - int
 - main(int argc, char *argv[]) {
 -   Fl::scheme("plastic");
 -   Fl::visible_focus(0);
 - 
 -   BlockWindow	*bw = new BlockWindow(BLOCK_COLS * BLOCK_SIZE,
 -                                       BLOCK_ROWS * BLOCK_SIZE + 20,
 - 		                      "Block Attack!");
 - 
 -   bw->show(argc, argv);
 - 
 -   return (Fl::run());
 - }
 - 
 - 
 - // Create a block window at the specified position
 - BlockWindow::BlockWindow(int X, int Y, int W, int H, const char *L)
 -     : Fl_Double_Window(X, Y, W, H, L) {
 -   _BlockWindow();
 - }
 - 
 - 
 - // Create a block window
 - BlockWindow::BlockWindow(int W, int H, const char *L)
 -     : Fl_Double_Window(W, H, L) {
 -   _BlockWindow();
 - }
 - 
 - 
 - // Delete a block window
 - BlockWindow::~BlockWindow() {
 -   Fl::remove_timeout((Fl_Timeout_Handler)timeout_cb, (void *)this);
 - }
 - 
 - 
 - // Initialize a block window...
 - void
 - BlockWindow::_BlockWindow() {
 -   init();
 - 
 -   help_button_ = new Fl_Button(0, 0, 20, 20, "?");
 -   help_button_->callback((Fl_Callback *)help_cb, this);
 -   help_button_->shortcut('?');
 - 
 -   play_button_ = new Fl_Button(80, (h() - 80) / 2, 80, 80, "@>");
 -   play_button_->callback((Fl_Callback *)play_cb, this);
 -   play_button_->labelsize(44);
 -   play_button_->shortcut(' ');
 - 
 -   sound_ = new BlockSound();
 - 
 -   prefs_.get("high_score", high_score_, 0);
 - 
 -   Fl::add_timeout(0.1, (Fl_Timeout_Handler)timeout_cb, (void *)this);
 - }
 - 
 - 
 - // Bomb all blocks of a given color and return the number of affected blocks
 - int
 - BlockWindow::bomb(int color) {
 -   int		j, k;
 -   int		count;
 -   Block		*b;
 -   Column	*c;
 - 
 - 
 -   if (color >= BLOCK_BLAST) return (0);
 - 
 -   for (j = num_columns_, c = columns_, count = 1; j > 0; j --, c ++)
 -     for (k = c->num_blocks, b = c->blocks; k > 0; k --, b ++)
 -       if (b->color == color) {
 -         b->color = -color;
 - 	count ++;
 -       }
 - 
 -   return (count);
 - }
 - 
 - 
 - // Tag all blocks connected to the clicked block and return the number
 - // of affected blocks
 - int
 - BlockWindow::click(int col, int row) {
 -   Block		*b;
 -   Column	*c;
 -   int		count, color;
 - 
 - 
 -   c     = columns_ + col;
 -   b     = c->blocks + row;
 -   color = b->color;
 - 
 -   if (color < 0 || color >= BLOCK_BLAST) return (0);
 - 
 -   // Find the bottom block...
 -   while (row > 0 && b[-1].color == color) {
 -     row --;
 -     b --;
 -   }
 - 
 -   count = 0;
 - 
 -   while (row < c->num_blocks && b->color == color) {
 -     b->color = -color;
 - 
 -     if (col > 0 && row < c[-1].num_blocks &&
 -         c[-1].blocks[row].color == color) {
 -       count += click(col - 1, row);
 -     }
 - 
 -     if (col < (num_columns_ - 1) && row < c[1].num_blocks &&
 -         c[1].blocks[row].color == color) {
 -       count += click(col + 1, row);
 -     }
 - 
 -     count ++;
 -     row ++;
 -     b ++;
 -   }
 - 
 -   return (count);
 - }
 - 
 - 
 - // Draw the block window...
 - void
 - BlockWindow::draw() {
 -   int		j, k, xx, yy;
 -   Block		*b;
 -   Column	*c;
 - 
 - 
 -   // Draw the blocks...
 -   fl_color(FL_BLACK);
 -   fl_rectf(0, 0, w(), h());
 - 
 -   // Draw the blocks...
 -   for (j = num_columns_, c = columns_; j > 0; j --, c ++)
 -     for (k = c->num_blocks, b = c->blocks; k > 0; k --, b ++) {
 -       xx = w() - c->x;
 -       yy = h() - BLOCK_SIZE - b->y;
 - 
 -       if (b->color >= BLOCK_BLAST) {
 - 	b->color ++;
 -         blast_pixmap.draw(xx, yy);
 -       } else if (b->color < 0) {
 -         if (b->bomb) bomb_pixmaps[-b->color - 1]->draw(xx, yy);
 - 	else normal_pixmaps[-b->color - 1]->draw(xx, yy);
 -       } else {
 -         if (b->bomb) bomb_pixmaps[b->color - 1]->draw(xx, yy);
 - 	else normal_pixmaps[b->color - 1]->draw(xx, yy);
 -       }
 -     }
 - 
 -   if (interval_ < 0.0 || paused_) {
 -     fl_color(FL_BLACK);
 -     screen_tile.draw(0, 0, w(), h(), 0, 0);
 -   }
 - 
 -   // Redraw the widgets...
 -   play_button_->redraw();
 -   help_button_->redraw();
 -   draw_children();
 - 
 -   // Draw any paused/game over/new game message...
 -   if ((paused_ || interval_ < 0.0) && play_button_->w() == 80) {
 -     const char *s;
 - 
 -     if (help_) {
 -       s = "Click on adjacent blocks of the same color. Clear all blocks "
 -           "before they reach the left side.";
 - 
 -       fl_font(FL_HELVETICA_BOLD, 24);
 -       fl_color(FL_BLACK);
 -       fl_draw(s, 171, 3, w() - 250, h() - 6,
 -               (Fl_Align)(FL_ALIGN_WRAP | FL_ALIGN_LEFT));
 - 
 -       fl_color(FL_YELLOW);
 -       fl_draw(s, 168, 0, w() - 250, h(),
 -               (Fl_Align)(FL_ALIGN_WRAP | FL_ALIGN_LEFT));
 -     } else {
 -       if (interval_ < 0.0) {
 - #ifdef DEBUG
 - 	// Show sample waveform...
 - 	short *sample_ptr;
 - 
 - 	for (i = 0; i < 2; i ++)
 - 	{
 - 	  fl_color(FL_RED + i);
 - 	  fl_begin_line();
 - 	  for (j = 0, sample_ptr = sound_->sample_data + i;
 -                j < sound_->sample_size;
 - 	       j ++, sample_ptr += 2)
 - 	    fl_vertex(j * w() / sound_->sample_size,
 - 	              *sample_ptr * h() / 4 / 65534 + h() / 2);
 - 	  fl_end_line();
 - 	}
 - #endif // DEBUG
 - 
 - 	if (num_columns_ && (time(NULL) & 7) < 4) s = "Game Over";
 - 	else s = "Block Attack!\nby Michael R Sweet";
 -       } else s = "Paused";
 - 
 -       fl_font(FL_HELVETICA_BOLD, 32);
 -       fl_color(FL_BLACK);
 -       fl_draw(s, 6, 6, w() - 6, h() - 6, FL_ALIGN_CENTER);
 - 
 -       fl_color(FL_YELLOW);
 -       fl_draw(s, 0, 0, w(), h(), FL_ALIGN_CENTER);
 -     }
 -   }
 - 
 -   // Draw the scores and level...
 -   char s[255];
 - 
 -   sprintf(s, " Score: %d", score_);
 -   fl_color(FL_WHITE);
 -   fl_font(FL_HELVETICA, 14);
 -   fl_draw(s, 40, 0, w() - 40, 20, FL_ALIGN_LEFT);
 - 
 -   sprintf(s, "High Score: %d ", high_score_);
 -   fl_draw(s, 0, 0, w(), 20, FL_ALIGN_RIGHT);
 - 
 -   if (level_ > 1 || title_y_ <= 0)
 -   {
 -     sprintf(s, "Level: %d ", level_);
 -     fl_draw(s, 0, 0, w(), 20, FL_ALIGN_CENTER);
 -   }
 - 
 -   if (title_y_ > 0 && interval_ > 0.0)
 -   {
 -     int sz = 14 + title_y_ * 86 / h();
 - 
 -     fl_font(FL_HELVETICA_BOLD, sz);
 -     fl_color(FL_YELLOW);
 -     fl_draw(title_, 0, title_y_, w(), sz, FL_ALIGN_CENTER);
 -   }
 - }
 - 
 - 
 - // Handle mouse clicks, etc.
 - int
 - BlockWindow::handle(int event) {
 -   int		j, k, mx, my, count;
 -   Block		*b;
 -   Column	*c;
 - 
 - 
 -   if (Fl_Double_Window::handle(event)) return (1);
 -   else if (interval_ < 0.0 || paused_) return (0);
 - 
 -   switch (event) {
 -     case FL_KEYBOARD:
 -         if (Fl::event_text()) {
 -           if (strcmp(Fl::event_text(), "+") == 0)
 -             up_level();
 -         }
 -         break;
 -     case FL_PUSH :
 - 	mx    = w() - Fl::event_x() + BLOCK_SIZE;
 - 	my    = h() - Fl::event_y();
 - 	count = 0;
 - 	b     = 0;
 - 
 - 	for (j = 0, c = columns_; !count && j < num_columns_; j ++, c ++)
 - 	  for (k = 0, b = c->blocks; !count && k < c->num_blocks; k ++, b ++)
 - 	    if (mx >= c->x && mx < (c->x + BLOCK_SIZE) &&
 - 	        my >= b->y && my < (b->y + BLOCK_SIZE)) {
 - 	      if (b->bomb) count = bomb(b->color);
 - 	      else count = click(j, k);
 - 
 -               break;
 - 	    }
 - 
 -         if (count < 2) {
 - 	  for (j = 0, c = columns_; j < num_columns_; j ++, c ++)
 - 	    for (k = 0, b = c->blocks; k < c->num_blocks; k ++, b ++)
 - 	      if (b->color < 0) b->color = -b->color;
 - 	} else {
 - 	  count --;
 - 
 - 	  if (b->bomb) {
 - 	    sound_->play_explosion(0.19 + 0.005 * count);
 - 
 - 	    interval_ *= 0.995;
 - 	    score_ += count;
 - 	  } else {
 - 	    sound_->play_explosion(0.09 + 0.005 * count);
 - 
 - 	    interval_ *= 0.999;
 - 	    score_ += count * count;
 - 	  }
 - 
 - 	  if (score_ > high_score_) {
 - 	    high_score_ = score_;
 - 	    prefs_.set("high_score", high_score_);
 - 	  }
 - 
 - 	  for (j = 0, c = columns_; j < num_columns_; j ++, c ++)
 - 	    for (k = 0, b = c->blocks; k < c->num_blocks; k ++, b ++)
 - 	      if (b->color < 0) b->color = BLOCK_BLAST;
 - 	}
 - 	return (1);
 -   }
 - 
 -   return (0);
 - }
 - 
 - 
 - // Toggle the on-line help...
 - void
 - BlockWindow::help_cb(Fl_Widget *, BlockWindow *bw) {
 -   bw->paused_ = bw->help_ = !bw->help_;
 -   bw->play_button_->label("@>");
 -   bw->redraw();
 - }
 - 
 - 
 - // Initialize the block window...
 - void
 - BlockWindow::init() {
 -   count_       = 0;
 -   help_        = false;
 -   interval_    = -1.0;
 -   level_       = 1;
 -   num_colors_  = 3;
 -   num_columns_ = 0;
 -   paused_      = false;
 -   score_       = 0;
 -   title_[0]    = '\0';
 -   title_y_     = 0;
 - }
 - 
 - 
 - // Start a new game...
 - void
 - BlockWindow::new_game() {
 -   // Seed the random number generator...
 -   srand(time(NULL));
 - 
 -   init();
 - 
 -   interval_       = 0.1;
 -   opened_columns_ = 0;
 - 
 -   strcpy(title_, "Level: 1");
 -   title_y_ = h();
 - 
 -   redraw();
 - }
 - 
 - 
 - // Play/pause...
 - void
 - BlockWindow::play_cb(Fl_Widget *wi, BlockWindow *bw) {
 -   if (bw->interval_ < 0) bw->new_game();
 -   else bw->paused_ = !bw->paused_;
 - 
 -   if (bw->paused_) wi->label("@>");
 -   else {
 -     wi->label("@-2||");
 -     bw->help_ = false;
 -   }
 - }
 - 
 - void BlockWindow::up_level() {
 -   interval_ *= 0.95;
 -   opened_columns_ = 0;
 -   if (num_colors_ < 7) num_colors_ ++;
 -   level_ ++;
 -   sprintf(title_, "Level: %d", level_);
 -   title_y_ = h();
 -   Fl::repeat_timeout(interval_, (Fl_Timeout_Handler)timeout_cb, (void *)this);
 - }
 - 
 - // Animate the game...
 - void
 - BlockWindow::timeout_cb(BlockWindow *bw) {
 -   int		i, j;
 -   Block		*b;
 -   Column	*c;
 -   int		lastx, lasty;
 - 
 - 
 - #ifdef DEBUG
 -   struct timeval curtime;
 -   static struct timeval lasttime;
 - 
 - 
 -   gettimeofday(&curtime, NULL);
 -   printf("%.3f (%+f - %f)\n",
 -          curtime.tv_sec + 0.000001 * curtime.tv_usec,
 -          curtime.tv_sec - lasttime.tv_sec +
 - 	     0.000001 * (curtime.tv_usec - lasttime.tv_usec), bw->interval_);
 -   lasttime = curtime;
 - #endif // DEBUG
 - 
 -   // Update blocks that have been destroyed...
 -   for (i = 0, c = bw->columns_; i < bw->num_columns_; i ++, c ++)
 -     for (j = 0, b = c->blocks; j < c->num_blocks; j ++, b ++)
 -       if (b->color > (BLOCK_BLAST + 1)) {
 -         bw->redraw();
 - 
 - 	c->num_blocks --;
 - 
 - 	if (j < c->num_blocks) {
 - 	  memmove(b, b + 1, (c->num_blocks - j) * sizeof(Block));
 - 	}
 - 
 - 	j --;
 - 	b --;
 - 
 - 	if (!c->num_blocks) {
 - 	  bw->num_columns_ --;
 - 
 - 	  if (i < bw->num_columns_) {
 - 	    memmove(c, c + 1, (bw->num_columns_ - i) * sizeof(Column));
 -           }
 - 
 - 	  i --;
 - 	  c --;
 - 	  j = c->num_blocks;
 - 	}
 -       }
 - 
 -   // Let the rest of the blocks fall and/or move...
 -   for (i = bw->num_columns_, c = bw->columns_, lastx = c->x;
 -        i > 0;
 -        i --, c ++) {
 -     if (c->x > lastx) {
 -       c->x -= 8;
 -       bw->redraw();
 -     }
 - 
 -     lastx = c->x + BLOCK_SIZE;
 - 
 -     if (!bw->paused_ && bw->interval_ > 0.0) {
 -       bw->redraw();
 -       c->x ++;
 -     }
 - 
 -     for (j = c->num_blocks, b = c->blocks, lasty = 0; j > 0; j --, b ++) {
 -       if (b->y > lasty) {
 -         bw->redraw();
 -         b->y -= 8;
 -       }
 - 
 -       lasty = b->y + BLOCK_SIZE;
 -     }
 -   }
 - 
 -   // Slide the title text as needed...
 -   if (bw->title_y_ > 0) {
 -     bw->redraw();
 -     bw->title_y_ -= 5;
 -   }
 - 
 -   // Play the game...
 -   if (!bw->paused_ && bw->interval_ > 0.0) {
 -     bw->count_ --;
 - 
 -     if (bw->count_ <= 0) {
 -       bw->redraw();
 -       bw->count_ = BLOCK_SIZE;
 - 
 -       if (bw->num_columns_ == BLOCK_COLS) {
 - 	bw->interval_ = -1.0;
 - 	bw->sound_->play_explosion(0.8);
 - 	bw->play_button_->label("@>");
 -       } else {
 - 	bw->opened_columns_ ++;
 - 
 - 	if (bw->opened_columns_ > (2 * BLOCK_COLS)) {
 -           bw->up_level();
 - 	}
 - 
 - 	c = bw->columns_;
 - 
 - 	if (bw->num_columns_) {
 -           memmove(c + 1, c, bw->num_columns_ * sizeof(Column));
 - 	}
 - 
 - 	bw->num_columns_ ++;
 - 	c->x          = 0;
 - 	c->num_blocks = BLOCK_ROWS;
 - 
 - 	for (j = 0, b = c->blocks; j < BLOCK_ROWS; j ++, b ++) {
 -           b->bomb  = bw->num_colors_ > 3 && (rand() & 127) < bw->num_colors_;
 -           b->color = 1 + (rand() % bw->num_colors_);
 - 	  b->y     = j * (BLOCK_SIZE + 8) + 24;
 - 	}
 -       }
 -     }
 -   }
 -   else
 -   {
 -     bw->count_ --;
 - 
 -     if (bw->count_ <= 0) {
 -       bw->count_ = 40;
 -       bw->redraw();
 -     }
 -   }
 - 
 -   // Update the play/pause button as needed...
 -   if ((bw->paused_ || bw->interval_< 0.0) &&
 -       bw->play_button_->w() < 80) {
 -     int s = bw->play_button_->w() + 10;
 - 
 -     bw->play_button_->resize(s, (s - 20) * (bw->h() - s) / 120, s, s);
 -     bw->play_button_->labelsize(s / 2 + 4);
 -     bw->redraw();
 -   } else if ((!bw->paused_ && bw->interval_ > 0.0) &&
 -              bw->play_button_->w() > 20) {
 -     int s = bw->play_button_->w() - 5;
 - 
 -     bw->play_button_->resize(s, (s - 20) * (bw->h() - s) / 120, s, s);
 -     bw->play_button_->labelsize(s / 2 + 4);
 -     bw->redraw();
 -   }
 - 
 -   if (bw->interval_ > 0.0) {
 -     Fl::repeat_timeout(bw->interval_, (Fl_Timeout_Handler)timeout_cb,
 -                        (void *)bw);
 -   } else {
 -     Fl::repeat_timeout(0.1, (Fl_Timeout_Handler)timeout_cb,
 -                        (void *)bw);
 -   }
 - }
 - 
 - 
 - //
 - // End of "$Id: blocks.cxx 7904 2010-11-28 21:12:59Z matt $".
 - //
 
 
  |