|
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(¶ms);
|
|
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 |
//
|