2 // "$Id: blocks.cxx 7904 2010-11-28 21:12:59Z matt $"
4 // "Block Attack!" scrolling blocks game using the Fast Light Tool Kit (FLTK).
6 // Copyright 2006-2010 by Michael Sweet.
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
29 #include <FL/Fl_Double_Window.H>
30 #include <FL/Fl_Button.H>
31 #include <FL/Fl_Preferences.H>
32 #include <FL/Fl_XPM_Image.H>
33 #include <FL/Fl_XBM_Image.H>
34 #include <FL/Fl_Tiled_Image.H>
35 #include <FL/fl_draw.H>
48 # include <sys/time.h>
51 #ifdef HAVE_ALSA_ASOUNDLIB_H
52 # define ALSA_PCM_NEW_HW_PARAMS_API
53 # include <alsa/asoundlib.h>
54 #endif // HAVE_ALSA_ASOUNDLIB_H
56 # include <CoreAudio/AudioHardware.h>
59 # include <mmsystem.h>
66 #define BLOCK_BLAST 100
68 #include "pixmaps/blast.xpm"
69 Fl_Pixmap
blast_pixmap(blast_xpm
);
71 #include "pixmaps/red.xpm"
72 Fl_Pixmap
red_pixmap(red_xpm
);
73 #include "pixmaps/red_bomb.xpm"
74 Fl_Pixmap
red_bomb_pixmap(red_bomb_xpm
);
76 #include "pixmaps/green.xpm"
77 Fl_Pixmap
green_pixmap(green_xpm
);
78 #include "pixmaps/green_bomb.xpm"
79 Fl_Pixmap
green_bomb_pixmap(green_bomb_xpm
);
81 #include "pixmaps/blue.xpm"
82 Fl_Pixmap
blue_pixmap(blue_xpm
);
83 #include "pixmaps/blue_bomb.xpm"
84 Fl_Pixmap
blue_bomb_pixmap(blue_bomb_xpm
);
86 #include "pixmaps/yellow.xpm"
87 Fl_Pixmap
yellow_pixmap(yellow_xpm
);
88 #include "pixmaps/yellow_bomb.xpm"
89 Fl_Pixmap
yellow_bomb_pixmap(yellow_bomb_xpm
);
91 #include "pixmaps/cyan.xpm"
92 Fl_Pixmap
cyan_pixmap(cyan_xpm
);
93 #include "pixmaps/cyan_bomb.xpm"
94 Fl_Pixmap
cyan_bomb_pixmap(cyan_bomb_xpm
);
96 #include "pixmaps/magenta.xpm"
97 Fl_Pixmap
magenta_pixmap(magenta_xpm
);
98 #include "pixmaps/magenta_bomb.xpm"
99 Fl_Pixmap
magenta_bomb_pixmap(magenta_bomb_xpm
);
101 #include "pixmaps/gray.xpm"
102 Fl_Pixmap
gray_pixmap(gray_xpm
);
103 #include "pixmaps/gray_bomb.xpm"
104 Fl_Pixmap
gray_bomb_pixmap(gray_bomb_xpm
);
106 Fl_Pixmap
*normal_pixmaps
[] = {
115 Fl_Pixmap
*bomb_pixmaps
[] = {
121 &magenta_bomb_pixmap
,
125 const unsigned char screen_bits
[] = {
126 0xff, 0x55, 0xff, 0xaa, 0xff, 0x55, 0xff, 0xaa
128 Fl_Bitmap
screen_bitmap(screen_bits
, 8, 8);
129 Fl_Tiled_Image
screen_tile(&screen_bitmap
);
134 // There are MANY ways to implement sound in a FLTK application.
135 // The approach we are using here is to conditionally compile OS-
136 // specific code into the application - CoreAudio for MacOS X, the
137 // standard Win32 API stuff for Windows, ALSA or X11 for Linux, and
138 // X11 for all others. We have to support ALSA on Linux because the
139 // current Xorg releases no longer support XBell() or the PC speaker.
141 // There are several good cross-platform audio libraries we could also
142 // use, such as OpenAL, PortAudio, and SDL, however they were not chosen
143 // for this application because of our limited use of sound.
145 // Many thanks to Ian MacArthur who provided sample code that led to
146 // the CoreAudio implementation you see here!
148 // Private, OS-specific data...
150 AudioDeviceID device
;
151 # if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
152 AudioDeviceIOProcID audio_proc_id
;
154 AudioStreamBasicDescription format
;
158 static OSStatus
audio_cb(AudioDeviceID device
,
159 const AudioTimeStamp
*current_time
,
160 const AudioBufferList
*data_in
,
161 const AudioTimeStamp
*time_in
,
162 AudioBufferList
*data_out
,
163 const AudioTimeStamp
*time_out
,
167 HGLOBAL header_handle
;
168 LPWAVEHDR header_ptr
;
173 # ifdef HAVE_ALSA_ASOUNDLIB_H
175 # endif // HAVE_ALSA_ASOUNDLIB_H
181 static short *sample_data
;
182 static int sample_size
;
187 void play_explosion(float duration
);
190 // Sound class globals...
191 short *BlockSound::sample_data
= NULL
;
192 int BlockSound::sample_size
= 0;
195 // Initialize the BlockSound class
196 BlockSound::BlockSound() {
202 UInt32 size
= sizeof(device
);
204 if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice
,
205 &size
, (void *)&device
) != noErr
) return;
207 size
= sizeof(format
);
208 if (AudioDeviceGetProperty(device
, 0, false, kAudioDevicePropertyStreamFormat
,
209 &size
, &format
) != noErr
) return;
211 // Set up a format we like...
212 format
.mSampleRate
= 44100.0; // 44.1kHz
213 format
.mChannelsPerFrame
= 2; // stereo
215 if (AudioDeviceSetProperty(device
, NULL
, 0, false,
216 kAudioDevicePropertyStreamFormat
,
217 sizeof(format
), &format
) != noErr
) return;
219 // Check we got linear pcm - what to do if we did not ???
220 if (format
.mFormatID
!= kAudioFormatLinearPCM
) return;
222 // Attach the callback and start the device
223 # if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
224 if (AudioDeviceCreateIOProcID(device
, audio_cb
, (void *)this, &audio_proc_id
) != noErr
) return;
225 AudioDeviceStart(device
, audio_proc_id
);
227 if (AudioDeviceAddIOProc(device
, audio_cb
, (void *)this) != noErr
) return;
228 AudioDeviceStart(device
, audio_cb
);
231 sample_size
= (int)format
.mSampleRate
;
236 memset(&format
, 0, sizeof(format
));
237 format
.cbSize
= sizeof(format
);
238 format
.wFormatTag
= WAVE_FORMAT_PCM
;
239 format
.nChannels
= 2;
240 format
.nSamplesPerSec
= 44100;
241 format
.nAvgBytesPerSec
= 44100 * 4;
242 format
.nBlockAlign
= 4;
243 format
.wBitsPerSample
= 16;
245 data_handle
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_SHARE
, format
.nSamplesPerSec
* 4);
246 if (!data_handle
) return;
248 data_ptr
= (LPSTR
)GlobalLock(data_handle
);
250 header_handle
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_SHARE
, sizeof(WAVEHDR
));
251 if (!header_handle
) return;
253 header_ptr
= (WAVEHDR
*)GlobalLock(header_handle
);
255 header_ptr
->lpData
= data_ptr
;
256 header_ptr
->dwFlags
= 0;
257 header_ptr
->dwLoops
= 0;
259 if (waveOutOpen(&device
, WAVE_MAPPER
, &format
, 0, 0, WAVE_ALLOWSYNC
)
260 != MMSYSERR_NOERROR
) return;
262 sample_size
= format
.nSamplesPerSec
;
265 # ifdef HAVE_ALSA_ASOUNDLIB_H
268 if (snd_pcm_open(&handle
, "default", SND_PCM_STREAM_PLAYBACK
, 0) >= 0) {
269 // Initialize PCM sound stuff...
270 snd_pcm_hw_params_t
*params
;
272 snd_pcm_hw_params_alloca(¶ms
);
273 snd_pcm_hw_params_any(handle
, params
);
274 snd_pcm_hw_params_set_access(handle
, params
, SND_PCM_ACCESS_RW_INTERLEAVED
);
275 snd_pcm_hw_params_set_format(handle
, params
, SND_PCM_FORMAT_S16
);
276 snd_pcm_hw_params_set_channels(handle
, params
, 2);
277 unsigned rate
= 44100;
279 snd_pcm_hw_params_set_rate_near(handle
, params
, &rate
, &dir
);
280 snd_pcm_uframes_t period
= (int)rate
;
281 snd_pcm_hw_params_set_period_size_near(handle
, params
, &period
, &dir
);
285 if (snd_pcm_hw_params(handle
, params
) < 0) {
287 snd_pcm_close(handle
);
291 # endif // HAVE_ALSA_ASOUNDLIB_H
295 // Make an explosion sound by passing white noise through a low pass
296 // filter with a decreasing frequency...
297 sample_data
= new short[2 * sample_size
];
299 short *sample_ptr
= sample_data
;
300 int max_sample
= 2 * sample_size
- 2;
305 for (int j
= max_sample
; j
> 0; j
--, sample_ptr
++) {
306 float freq
= (float)j
/ (float)max_sample
;
307 float volume
= 32767.0 * (0.5 * sqrt(freq
) + 0.5);
308 float sample
= 0.0001 * ((rand() % 20001) - 10000);
310 *sample_ptr
= (int)(volume
* freq
* sample
+
311 (1.0 - freq
) * sample_ptr
[-2]);
317 // Cleanup the BlockSound class
318 BlockSound::~BlockSound() {
321 # if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
322 AudioDeviceStop(device
, audio_proc_id
);
323 AudioDeviceDestroyIOProcID(device
, audio_proc_id
);
325 AudioDeviceStop(device
, audio_cb
);
326 AudioDeviceRemoveIOProc(device
, audio_cb
);
332 waveOutClose(device
);
334 GlobalUnlock(header_handle
);
335 GlobalFree(header_handle
);
337 GlobalUnlock(data_handle
);
338 GlobalFree(data_handle
);
342 # ifdef HAVE_ALSA_ASOUNDLIB_H
344 snd_pcm_drain(handle
);
345 snd_pcm_close(handle
);
347 # endif // HAVE_ALSA_ASOUNDLIB_H
351 delete[] sample_data
;
357 // Callback function for writing audio data...
359 BlockSound::audio_cb(AudioDeviceID device
,
360 const AudioTimeStamp
*current_time
,
361 const AudioBufferList
*data_in
,
362 const AudioTimeStamp
*time_in
,
363 AudioBufferList
*data_out
,
364 const AudioTimeStamp
*time_out
,
366 BlockSound
*ss
= (BlockSound
*)client_data
;
370 if (!ss
->remaining
) return noErr
;
372 for (count
= data_out
->mBuffers
[0].mDataByteSize
/ sizeof(float),
373 buffer
= (float*) data_out
->mBuffers
[0].mData
;
374 ss
->remaining
> 0 && count
> 0;
375 count
--, ss
->data
++, ss
->remaining
--) {
376 *buffer
++ = *(ss
->data
) / 32767.0;
389 // Play a note for the given amount of time...
391 BlockSound::play_explosion(float duration
) {
397 #if defined(__APPLE__) || defined(WIN32) || defined(HAVE_ALSA_ASOUNDLIB_H)
401 int samples
= (int)(duration
* sample_size
);
402 short *sample_ptr
= sample_data
+ 2 * (sample_size
- samples
);
403 #endif // __APPLE__ || WIN32 || HAVE_ALSA_ASOUNDLIB_H
406 // Point to the next note...
408 remaining
= samples
* 2;
412 memcpy(data_ptr
, sample_ptr
, samples
* 4);
414 header_ptr
->dwBufferLength
= samples
* 4;
415 waveOutPrepareHeader(device
, header_ptr
, sizeof(WAVEHDR
));
417 waveOutWrite(device
, header_ptr
, sizeof(WAVEHDR
));
418 } else Beep(440, (int)(1000.0 * duration
));
420 #elif defined(HAVE_ALSA_ASOUNDLIB_H)
422 // Use ALSA to play the sound...
423 if (snd_pcm_writei(handle
, sample_ptr
, samples
) < 0) {
424 snd_pcm_prepare(handle
);
425 snd_pcm_writei(handle
, sample_ptr
, samples
);
433 class BlockWindow
: public Fl_Double_Window
447 Block blocks
[BLOCK_ROWS
];
453 Fl_Button
*help_button_
,
457 Column columns_
[BLOCK_COLS
];
466 static Fl_Preferences prefs_
;
474 int click(int col
, int row
);
475 static void help_cb(Fl_Widget
*wi
, BlockWindow
*bw
);
477 static void play_cb(Fl_Widget
*wi
, BlockWindow
*bw
);
478 static void timeout_cb(BlockWindow
*bw
);
482 BlockWindow(int X
, int Y
, int W
, int H
, const char *L
= 0);
483 BlockWindow(int W
, int H
, const char *L
= 0);
487 int handle(int event
);
489 int score() { return (score_
); }
494 Fl_Preferences
BlockWindow::prefs_(Fl_Preferences::USER
, "fltk.org", "blocks");
498 main(int argc
, char *argv
[]) {
499 Fl::scheme("plastic");
500 Fl::visible_focus(0);
502 BlockWindow
*bw
= new BlockWindow(BLOCK_COLS
* BLOCK_SIZE
,
503 BLOCK_ROWS
* BLOCK_SIZE
+ 20,
506 bw
->show(argc
, argv
);
512 // Create a block window at the specified position
513 BlockWindow::BlockWindow(int X
, int Y
, int W
, int H
, const char *L
)
514 : Fl_Double_Window(X
, Y
, W
, H
, L
) {
519 // Create a block window
520 BlockWindow::BlockWindow(int W
, int H
, const char *L
)
521 : Fl_Double_Window(W
, H
, L
) {
526 // Delete a block window
527 BlockWindow::~BlockWindow() {
528 Fl::remove_timeout((Fl_Timeout_Handler
)timeout_cb
, (void *)this);
532 // Initialize a block window...
534 BlockWindow::_BlockWindow() {
537 help_button_
= new Fl_Button(0, 0, 20, 20, "?");
538 help_button_
->callback((Fl_Callback
*)help_cb
, this);
539 help_button_
->shortcut('?');
541 play_button_
= new Fl_Button(80, (h() - 80) / 2, 80, 80, "@>");
542 play_button_
->callback((Fl_Callback
*)play_cb
, this);
543 play_button_
->labelsize(44);
544 play_button_
->shortcut(' ');
546 sound_
= new BlockSound();
548 prefs_
.get("high_score", high_score_
, 0);
550 Fl::add_timeout(0.1, (Fl_Timeout_Handler
)timeout_cb
, (void *)this);
554 // Bomb all blocks of a given color and return the number of affected blocks
556 BlockWindow::bomb(int color
) {
563 if (color
>= BLOCK_BLAST
) return (0);
565 for (j
= num_columns_
, c
= columns_
, count
= 1; j
> 0; j
--, c
++)
566 for (k
= c
->num_blocks
, b
= c
->blocks
; k
> 0; k
--, b
++)
567 if (b
->color
== color
) {
576 // Tag all blocks connected to the clicked block and return the number
577 // of affected blocks
579 BlockWindow::click(int col
, int row
) {
589 if (color
< 0 || color
>= BLOCK_BLAST
) return (0);
591 // Find the bottom block...
592 while (row
> 0 && b
[-1].color
== color
) {
599 while (row
< c
->num_blocks
&& b
->color
== color
) {
602 if (col
> 0 && row
< c
[-1].num_blocks
&&
603 c
[-1].blocks
[row
].color
== color
) {
604 count
+= click(col
- 1, row
);
607 if (col
< (num_columns_
- 1) && row
< c
[1].num_blocks
&&
608 c
[1].blocks
[row
].color
== color
) {
609 count
+= click(col
+ 1, row
);
621 // Draw the block window...
623 BlockWindow::draw() {
629 // Draw the blocks...
631 fl_rectf(0, 0, w(), h());
633 // Draw the blocks...
634 for (j
= num_columns_
, c
= columns_
; j
> 0; j
--, c
++)
635 for (k
= c
->num_blocks
, b
= c
->blocks
; k
> 0; k
--, b
++) {
637 yy
= h() - BLOCK_SIZE
- b
->y
;
639 if (b
->color
>= BLOCK_BLAST
) {
641 blast_pixmap
.draw(xx
, yy
);
642 } else if (b
->color
< 0) {
643 if (b
->bomb
) bomb_pixmaps
[-b
->color
- 1]->draw(xx
, yy
);
644 else normal_pixmaps
[-b
->color
- 1]->draw(xx
, yy
);
646 if (b
->bomb
) bomb_pixmaps
[b
->color
- 1]->draw(xx
, yy
);
647 else normal_pixmaps
[b
->color
- 1]->draw(xx
, yy
);
651 if (interval_
< 0.0 || paused_
) {
653 screen_tile
.draw(0, 0, w(), h(), 0, 0);
656 // Redraw the widgets...
657 play_button_
->redraw();
658 help_button_
->redraw();
661 // Draw any paused/game over/new game message...
662 if ((paused_
|| interval_
< 0.0) && play_button_
->w() == 80) {
666 s
= "Click on adjacent blocks of the same color. Clear all blocks "
667 "before they reach the left side.";
669 fl_font(FL_HELVETICA_BOLD
, 24);
671 fl_draw(s
, 171, 3, w() - 250, h() - 6,
672 (Fl_Align
)(FL_ALIGN_WRAP
| FL_ALIGN_LEFT
));
675 fl_draw(s
, 168, 0, w() - 250, h(),
676 (Fl_Align
)(FL_ALIGN_WRAP
| FL_ALIGN_LEFT
));
678 if (interval_
< 0.0) {
680 // Show sample waveform...
683 for (i
= 0; i
< 2; i
++)
685 fl_color(FL_RED
+ i
);
687 for (j
= 0, sample_ptr
= sound_
->sample_data
+ i
;
688 j
< sound_
->sample_size
;
689 j
++, sample_ptr
+= 2)
690 fl_vertex(j
* w() / sound_
->sample_size
,
691 *sample_ptr
* h() / 4 / 65534 + h() / 2);
696 if (num_columns_
&& (time(NULL
) & 7) < 4) s
= "Game Over";
697 else s
= "Block Attack!\nby Michael R Sweet";
700 fl_font(FL_HELVETICA_BOLD
, 32);
702 fl_draw(s
, 6, 6, w() - 6, h() - 6, FL_ALIGN_CENTER
);
705 fl_draw(s
, 0, 0, w(), h(), FL_ALIGN_CENTER
);
709 // Draw the scores and level...
712 sprintf(s
, " Score: %d", score_
);
714 fl_font(FL_HELVETICA
, 14);
715 fl_draw(s
, 40, 0, w() - 40, 20, FL_ALIGN_LEFT
);
717 sprintf(s
, "High Score: %d ", high_score_
);
718 fl_draw(s
, 0, 0, w(), 20, FL_ALIGN_RIGHT
);
720 if (level_
> 1 || title_y_
<= 0)
722 sprintf(s
, "Level: %d ", level_
);
723 fl_draw(s
, 0, 0, w(), 20, FL_ALIGN_CENTER
);
726 if (title_y_
> 0 && interval_
> 0.0)
728 int sz
= 14 + title_y_
* 86 / h();
730 fl_font(FL_HELVETICA_BOLD
, sz
);
732 fl_draw(title_
, 0, title_y_
, w(), sz
, FL_ALIGN_CENTER
);
737 // Handle mouse clicks, etc.
739 BlockWindow::handle(int event
) {
740 int j
, k
, mx
, my
, count
;
745 if (Fl_Double_Window::handle(event
)) return (1);
746 else if (interval_
< 0.0 || paused_
) return (0);
750 if (Fl::event_text()) {
751 if (strcmp(Fl::event_text(), "+") == 0)
756 mx
= w() - Fl::event_x() + BLOCK_SIZE
;
757 my
= h() - Fl::event_y();
761 for (j
= 0, c
= columns_
; !count
&& j
< num_columns_
; j
++, c
++)
762 for (k
= 0, b
= c
->blocks
; !count
&& k
< c
->num_blocks
; k
++, b
++)
763 if (mx
>= c
->x
&& mx
< (c
->x
+ BLOCK_SIZE
) &&
764 my
>= b
->y
&& my
< (b
->y
+ BLOCK_SIZE
)) {
765 if (b
->bomb
) count
= bomb(b
->color
);
766 else count
= click(j
, k
);
772 for (j
= 0, c
= columns_
; j
< num_columns_
; j
++, c
++)
773 for (k
= 0, b
= c
->blocks
; k
< c
->num_blocks
; k
++, b
++)
774 if (b
->color
< 0) b
->color
= -b
->color
;
779 sound_
->play_explosion(0.19 + 0.005 * count
);
784 sound_
->play_explosion(0.09 + 0.005 * count
);
787 score_
+= count
* count
;
790 if (score_
> high_score_
) {
791 high_score_
= score_
;
792 prefs_
.set("high_score", high_score_
);
795 for (j
= 0, c
= columns_
; j
< num_columns_
; j
++, c
++)
796 for (k
= 0, b
= c
->blocks
; k
< c
->num_blocks
; k
++, b
++)
797 if (b
->color
< 0) b
->color
= BLOCK_BLAST
;
806 // Toggle the on-line help...
808 BlockWindow::help_cb(Fl_Widget
*, BlockWindow
*bw
) {
809 bw
->paused_
= bw
->help_
= !bw
->help_
;
810 bw
->play_button_
->label("@>");
815 // Initialize the block window...
817 BlockWindow::init() {
831 // Start a new game...
833 BlockWindow::new_game() {
834 // Seed the random number generator...
842 strcpy(title_
, "Level: 1");
851 BlockWindow::play_cb(Fl_Widget
*wi
, BlockWindow
*bw
) {
852 if (bw
->interval_
< 0) bw
->new_game();
853 else bw
->paused_
= !bw
->paused_
;
855 if (bw
->paused_
) wi
->label("@>");
862 void BlockWindow::up_level() {
865 if (num_colors_
< 7) num_colors_
++;
867 sprintf(title_
, "Level: %d", level_
);
869 Fl::repeat_timeout(interval_
, (Fl_Timeout_Handler
)timeout_cb
, (void *)this);
872 // Animate the game...
874 BlockWindow::timeout_cb(BlockWindow
*bw
) {
882 struct timeval curtime
;
883 static struct timeval lasttime
;
886 gettimeofday(&curtime
, NULL
);
887 printf("%.3f (%+f - %f)\n",
888 curtime
.tv_sec
+ 0.000001 * curtime
.tv_usec
,
889 curtime
.tv_sec
- lasttime
.tv_sec
+
890 0.000001 * (curtime
.tv_usec
- lasttime
.tv_usec
), bw
->interval_
);
894 // Update blocks that have been destroyed...
895 for (i
= 0, c
= bw
->columns_
; i
< bw
->num_columns_
; i
++, c
++)
896 for (j
= 0, b
= c
->blocks
; j
< c
->num_blocks
; j
++, b
++)
897 if (b
->color
> (BLOCK_BLAST
+ 1)) {
902 if (j
< c
->num_blocks
) {
903 memmove(b
, b
+ 1, (c
->num_blocks
- j
) * sizeof(Block
));
909 if (!c
->num_blocks
) {
912 if (i
< bw
->num_columns_
) {
913 memmove(c
, c
+ 1, (bw
->num_columns_
- i
) * sizeof(Column
));
922 // Let the rest of the blocks fall and/or move...
923 for (i
= bw
->num_columns_
, c
= bw
->columns_
, lastx
= c
->x
;
931 lastx
= c
->x
+ BLOCK_SIZE
;
933 if (!bw
->paused_
&& bw
->interval_
> 0.0) {
938 for (j
= c
->num_blocks
, b
= c
->blocks
, lasty
= 0; j
> 0; j
--, b
++) {
944 lasty
= b
->y
+ BLOCK_SIZE
;
948 // Slide the title text as needed...
949 if (bw
->title_y_
> 0) {
955 if (!bw
->paused_
&& bw
->interval_
> 0.0) {
958 if (bw
->count_
<= 0) {
960 bw
->count_
= BLOCK_SIZE
;
962 if (bw
->num_columns_
== BLOCK_COLS
) {
963 bw
->interval_
= -1.0;
964 bw
->sound_
->play_explosion(0.8);
965 bw
->play_button_
->label("@>");
967 bw
->opened_columns_
++;
969 if (bw
->opened_columns_
> (2 * BLOCK_COLS
)) {
975 if (bw
->num_columns_
) {
976 memmove(c
+ 1, c
, bw
->num_columns_
* sizeof(Column
));
981 c
->num_blocks
= BLOCK_ROWS
;
983 for (j
= 0, b
= c
->blocks
; j
< BLOCK_ROWS
; j
++, b
++) {
984 b
->bomb
= bw
->num_colors_
> 3 && (rand() & 127) < bw
->num_colors_
;
985 b
->color
= 1 + (rand() % bw
->num_colors_
);
986 b
->y
= j
* (BLOCK_SIZE
+ 8) + 24;
995 if (bw
->count_
<= 0) {
1001 // Update the play/pause button as needed...
1002 if ((bw
->paused_
|| bw
->interval_
< 0.0) &&
1003 bw
->play_button_
->w() < 80) {
1004 int s
= bw
->play_button_
->w() + 10;
1006 bw
->play_button_
->resize(s
, (s
- 20) * (bw
->h() - s
) / 120, s
, s
);
1007 bw
->play_button_
->labelsize(s
/ 2 + 4);
1009 } else if ((!bw
->paused_
&& bw
->interval_
> 0.0) &&
1010 bw
->play_button_
->w() > 20) {
1011 int s
= bw
->play_button_
->w() - 5;
1013 bw
->play_button_
->resize(s
, (s
- 20) * (bw
->h() - s
) / 120, s
, s
);
1014 bw
->play_button_
->labelsize(s
/ 2 + 4);
1018 if (bw
->interval_
> 0.0) {
1019 Fl::repeat_timeout(bw
->interval_
, (Fl_Timeout_Handler
)timeout_cb
,
1022 Fl::repeat_timeout(0.1, (Fl_Timeout_Handler
)timeout_cb
,
1029 // End of "$Id: blocks.cxx 7904 2010-11-28 21:12:59Z matt $".