Blame test/blocks.cxx

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