summaryrefslogtreecommitdiff
path: root/third_party/windows/fltk-1.1.10/test/blocks.cxx
diff options
context:
space:
mode:
authorYuval Adam <yuv.adm@gmail.com>2014-08-08 14:42:07 +0300
committerYuval Adam <yuv.adm@gmail.com>2014-08-08 14:42:07 +0300
commita6163888f3c56123b1db313743c6147ba498732c (patch)
treeff7d15d991d1d09ba6cbc0cec80924f57445bfdd /third_party/windows/fltk-1.1.10/test/blocks.cxx
parentc3e4c9a25c2910d2d66d52215b3406b13d5b23d5 (diff)
Add third_party libs
Diffstat (limited to 'third_party/windows/fltk-1.1.10/test/blocks.cxx')
-rw-r--r--third_party/windows/fltk-1.1.10/test/blocks.cxx1019
1 files changed, 1019 insertions, 0 deletions
diff --git a/third_party/windows/fltk-1.1.10/test/blocks.cxx b/third_party/windows/fltk-1.1.10/test/blocks.cxx
new file mode 100644
index 0000000..5f7339b
--- /dev/null
+++ b/third_party/windows/fltk-1.1.10/test/blocks.cxx
@@ -0,0 +1,1019 @@
+//
+// "$Id: blocks.cxx 5976 2007-11-19 14:14:13Z matt $"
+//
+// "Block Attack!" scrolling blocks game using the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2006 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;
+ 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
+ if (AudioDeviceAddIOProc(device, audio_cb, (void *)this) != noErr) return;
+
+ // Start the device...
+ AudioDeviceStart(device, audio_cb);
+
+ 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(&params);
+ 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) {
+ AudioDeviceStop(device, audio_cb);
+ AudioDeviceRemoveIOProc(device, audio_cb);
+ }
+
+#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 5976 2007-11-19 14:14:13Z matt $".
+//