This repository has been archived on 2024-12-16. You can view files and clone it, but cannot push or open issues or pull requests.
CodeBlocksPortable/WATCOM/samples/win/shootgal/shootgal.c

1120 lines
37 KiB
C

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "shootgal.h"
#include "win1632.h"
static char ShootGalClass[32]="ShootGalClass";
HWND MessageWnd = NULL;
HWND ScoreWnd = NULL;
BOOL MessagesOn = FALSE;
int PASCAL WinMain( HINSTANCE, HINSTANCE, LPSTR, int );
static BOOL FirstInstance( HINSTANCE );
static BOOL AnyInstance( HINSTANCE, int );
BOOL _EXPORT FAR PASCAL About( HWND, UINT, WPARAM, LPARAM );
BOOL _EXPORT FAR PASCAL SpeedDlgProc( HWND, UINT, WPARAM, LPARAM );
long _EXPORT FAR PASCAL WindowProc( HWND, UINT, WPARAM, LPARAM );
BOOL TurnMessageWindowOn( HWND );
BOOL TurnScoreWindowOn( HWND );
BOOL _EXPORT FAR PASCAL MessageWindowProc( HWND, UINT, WPARAM, LPARAM );
BOOL _EXPORT FAR PASCAL ScoreProc( HWND, UINT, WPARAM, LPARAM );
static void CheckHit( HDC, POINT );
static void DrawBitmap( HDC, HBITMAP, int, int );
POINT RandPoint( RECT, POINT );
void _EXPORT FAR PASCAL DrawBolt( int, int, LPSTR );
static void ShootBolt( HWND );
static void BoomSound( void );
static void BoltSound( void );
/*
* WinMain - initialization, message loop
*/
int PASCAL WinMain( HINSTANCE this_inst, HINSTANCE prev_inst, LPSTR cmdline,
int cmdshow )
/*******************************/
{
MSG msg;
cmdline = cmdline; /* shut up compiler warning */
prev_inst = prev_inst;
#ifdef __WINDOWS_386__
sprintf( ShootGalClass,"ShootGalClass%d", this_inst );
#else
if( !prev_inst )
#endif
if( !FirstInstance( this_inst ) ) return( FALSE );
if( !AnyInstance( this_inst, cmdshow ) ) return( FALSE );
while( GetMessage( &msg, NULL, 0, 0 ) ) {
/*
* check to see if any of the messages are for a modeless dialog box,
*/
if( ( MessageWnd == NULL || !IsDialogMessage( MessageWnd, &msg ) ) &&
( ScoreWnd == NULL || !IsDialogMessage( ScoreWnd, &msg ) ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
return( msg.wParam );
} /* WinMain */
/*
* FirstInstance - register window class for the application,
* and do any other application initialization
*/
static BOOL FirstInstance( HINSTANCE this_inst )
/*******************************************/
{
WNDCLASS wc;
BOOL rc;
/*
* set up and register window classes
*/
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (LPVOID) WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof( DWORD );
wc.hInstance = this_inst;
wc.hIcon = LoadIcon( this_inst, "ShootGalIcon" );
wc.hCursor = LoadCursor( this_inst, "guncursor" );
wc.hbrBackground = GetStockObject( WHITE_BRUSH );
wc.lpszMenuName = "ShootGalMenu";
wc.lpszClassName = ShootGalClass;
rc = RegisterClass( &wc );
return( rc );
} /* FirstInstance */
/*
* AnyInstance - do work required for every instance of the application:
* create the window, initialize data
*/
static BOOL AnyInstance( HINSTANCE this_inst, int cmdshow )
/******************************************************/
{
HWND window_handle;
BITMAP bitmapbuff;
extra_data *edata_ptr;
/*
* create main window
*/
window_handle = CreateWindow(
ShootGalClass, /* class */
"Open Watcom Shooting Gallery - Sample Application", /* caption */
WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL, /* style */
CW_USEDEFAULT, /* init. x pos */
CW_USEDEFAULT, /* init. y pos */
CW_USEDEFAULT, /* init. x size */
CW_USEDEFAULT, /* init. y size */
NULL, /* parent window */
NULL, /* menu handle */
this_inst, /* program handle */
NULL /* create parms */
);
if( !window_handle ) return( FALSE );
/*
* get a timer
*/
while( !SetTimer( window_handle, TARGET_TIMER, STD_TARGET_SPEED,
(LPVOID) NULL ) ) {
if( MessageBox( window_handle, "Too many timers in use!", NULL,
MB_ICONEXCLAMATION | MB_RETRYCANCEL ) == IDCANCEL ) {
return( FALSE );
}
}
/*
* initialize data
*/
edata_ptr = calloc( 1, sizeof( extra_data ) );
if( edata_ptr == NULL ) return( FALSE );
edata_ptr->target_bmp = LoadBitmap( this_inst, "target" );
GetObject( edata_ptr->target_bmp, sizeof( BITMAP ), (LPSTR) &bitmapbuff);
edata_ptr->sound_on = FALSE;
edata_ptr->score_on = FALSE;
edata_ptr->target.x = 0;
edata_ptr->target.y = 0;
edata_ptr->size.x = bitmapbuff.bmWidth;
edata_ptr->size.y = bitmapbuff.bmHeight;
edata_ptr->aim = edata_ptr->target;
edata_ptr->bolt = edata_ptr->aim;
edata_ptr->target_speed = STD_TARGET_SPEED;
edata_ptr->bolt_speed = STD_BOLT_SPEED;
GetClientRect( window_handle, &edata_ptr->client_rect );
edata_ptr->message_window_proc =
MakeProcInstance( (FARPROC)MessageWindowProc, this_inst );
edata_ptr->score_window_proc =
MakeProcInstance( (FARPROC)ScoreProc, this_inst );
edata_ptr->bolt_icon = LoadIcon( this_inst, "Bolt" );
/*
* put a pointer to the above structure in the main window structure
*/
SetWindowLong( window_handle, EXTRA_DATA_OFFSET, (DWORD) edata_ptr );
/*
* display window
*/
ShowWindow( window_handle, cmdshow );
UpdateWindow( window_handle );
return( TRUE );
} /* AnyInstance */
/*
* About - processes messages for the about dialogue.
*/
BOOL _EXPORT FAR PASCAL About( HWND window_handle, UINT msg,
WPARAM wparam, LPARAM lparam )
/********************************************************/
{
lparam = lparam; /* turn off warning */
window_handle = window_handle;
switch( msg ) {
case WM_INITDIALOG:
return( TRUE );
case WM_COMMAND:
if( LOWORD( wparam ) == IDOK ) {
EndDialog( window_handle, TRUE );
return( TRUE );
}
break;
}
return( FALSE );
} /* About */
/*
* SpeedDlgProc - processes messages for the speed dialogue box.
*
* Allows the user to select speeds for the target or lightning bolt,
* depending on which selection was chosen.
*/
BOOL _EXPORT FAR PASCAL SpeedDlgProc( HWND dialog_wnd, UINT msg,
WPARAM wparam, LPARAM lparam )
/********************************************************/
{
extra_data *edata_ptr;
short speed;
static short old_speed = 0; /* in case the user hits CANCEL */
static short what_are_we_setting = 0;
static short fastest_speed = 0;
static short slowest_speed = 0;
HWND scrollbar;
WORD scroll_code;
edata_ptr = (extra_data *) GetWindowLong(
GetWindow( dialog_wnd, GW_OWNER ), EXTRA_DATA_OFFSET );
switch( msg ) {
case WM_INITDIALOG:
what_are_we_setting = (short)lparam;
if( what_are_we_setting == SET_TARGET_SPEED ) {
SetDlgItemText( dialog_wnd, SET_WHAT, (LPSTR)"Set Target Speed" );
old_speed = edata_ptr->target_speed;
fastest_speed = FASTEST_TARGET_SPEED;
slowest_speed = SLOWEST_TARGET_SPEED;
} else {
SetDlgItemText( dialog_wnd, SET_WHAT, (LPSTR)"Set Lightning Bolt Speed" );
SetDlgItemText( dialog_wnd, TEST, (LPSTR)"Click RIGHT mouse button to test." );
/*
* we want fastest on left, slowest on right,
* so use negative numbers for bolt speed
*/
old_speed = -edata_ptr->bolt_speed;
fastest_speed = -FASTEST_BOLT_SPEED;
slowest_speed = -SLOWEST_BOLT_SPEED;
}
scrollbar = GetDlgItem( dialog_wnd, SPEED_SCROLL );
SetScrollRange( scrollbar, SB_CTL, fastest_speed, slowest_speed, FALSE );
SetScrollPos( scrollbar, SB_CTL, old_speed, FALSE );
return( TRUE );
case WM_RBUTTONDOWN:
if( what_are_we_setting == SET_BOLT_SPEED ) {
/*
* shoot bolt diagonally accross the screen as a test
*/
edata_ptr->aim.x = edata_ptr->client_rect.left;
edata_ptr->aim.y = edata_ptr->client_rect.bottom;
ShootBolt( GetWindow( dialog_wnd, GW_OWNER ) );
}
break;
case WM_HSCROLL:
speed = ( what_are_we_setting == SET_TARGET_SPEED )
? edata_ptr->target_speed : -edata_ptr->bolt_speed;
scrollbar = GetDlgItem( dialog_wnd, SPEED_SCROLL );
scroll_code = GET_WM_HSCROLL_CODE( wparam, lparam );
switch( scroll_code ) {
case SB_PAGEDOWN:
speed += 15; /* note - no break - flow through to next case */
case SB_LINEDOWN:
speed = min( slowest_speed, ++speed );
break;
case SB_PAGEUP:
speed -= 15; /* note - no break - flow through to next case */
case SB_LINEUP:
speed = max( fastest_speed, --speed );
break;
case SB_TOP:
speed = fastest_speed;
break;
case SB_BOTTOM:
speed = slowest_speed;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
speed = GET_WM_HSCROLL_POS( wparam, lparam );
break;
default:
return( FALSE );
}
SetScrollPos( scrollbar, SB_CTL, speed , TRUE );
if( what_are_we_setting == SET_TARGET_SPEED ) {
edata_ptr->target_speed = speed;
/* restart timer at new speed */
KillTimer( GetWindow( dialog_wnd, GW_OWNER), TARGET_TIMER );
SetTimer( GetWindow( dialog_wnd, GW_OWNER), TARGET_TIMER,
speed, (LPVOID) NULL );
} else {
/* change speed back to positive value */
edata_ptr-> bolt_speed = -speed;
}
break;
case WM_COMMAND:
switch( LOWORD( wparam ) ) {
case IDOK:
EndDialog( dialog_wnd, TRUE );
return( TRUE );
case IDCANCEL:
/* change speed back to old value */
if( what_are_we_setting == SET_TARGET_SPEED ) {
edata_ptr->target_speed = old_speed;
} else {
edata_ptr->bolt_speed = -old_speed;
}
EndDialog( dialog_wnd, TRUE );
return( TRUE );
break;
}
}
return( FALSE );
} /* SpeedDlgProc */
/*
* WindowProc - handle messages for the main application window
*/
LONG _EXPORT FAR PASCAL WindowProc( HWND window_handle, UINT msg,
WPARAM wparam, LPARAM lparam )
/*************************************************************/
{
FARPROC proc;
HANDLE inst_handle;
extra_data *edata_ptr;
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
HBRUSH brush;
WORD cmd;
/*
* if the message window is ON, send all messages we want to display to the
* message window, so that we can see what is happening
* ( before we actually process the message )
*/
if( MessagesOn ) {
switch( msg ) {
case WM_COMMAND:
case WM_MOUSEMOVE:
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
case WM_KEYDOWN:
case WM_KEYUP:
case WM_CHAR:
case WM_TIMER:
case WM_HSCROLL:
case WM_VSCROLL:
SendMessage( MessageWnd, msg, wparam, lparam );
break;
}
}
/*
* now process the message
*/
switch( msg ) {
case WM_CREATE:
inst_handle = GET_HINST( window_handle );
/*
* make sure message window is turned OFF to start
*/
MessagesOn = FALSE;
CheckMenuItem ( GetMenu( window_handle ), MENU_MESSAGE_WINDOW_ON,
MF_BYCOMMAND | MF_UNCHECKED );
break;
case WM_LBUTTONDOWN:
/*
* zap the target with a lightning bolt!
*/
edata_ptr = (extra_data *) GetWindowLong( window_handle,
EXTRA_DATA_OFFSET );
/*
* set the aim point to where the mouse was just clicked
* set the bolt start point to the top left corner of the window
*/
MAKE_POINT( edata_ptr->aim, lparam );
edata_ptr->bolt.x = edata_ptr->client_rect.right - BOLTWIDTH;
edata_ptr->bolt.y = edata_ptr->client_rect.top;
/*
* shoot the bolt from the current bolt position to the aim point
*/
ShootBolt( window_handle );
break;
case WM_SIZE:
edata_ptr = (extra_data *) GetWindowLong( window_handle,
EXTRA_DATA_OFFSET );
/*
* store the new size of the window
*/
GetClientRect( window_handle, &edata_ptr->client_rect );
SetScrollRange( window_handle, SB_HORZ, edata_ptr->client_rect.left,
edata_ptr->client_rect.right, TRUE );
SetScrollRange( window_handle, SB_VERT, edata_ptr->client_rect.top,
edata_ptr->client_rect.bottom, TRUE );
break;
case WM_COMMAND:
cmd = LOWORD( wparam );
switch( cmd ) {
case MENU_ABOUT:
inst_handle = GET_HINST( window_handle );
proc = MakeProcInstance( (FARPROC)About, inst_handle );
DialogBox( inst_handle,"AboutBox", window_handle, (DLGPROC)proc );
FreeProcInstance( proc );
break;
case MENU_EXIT:
SendMessage( window_handle, WM_CLOSE, 0, 0L );
break;
case MENU_SET_TARGET_SPEED:
inst_handle = GET_HINST( window_handle );
proc = MakeProcInstance( (FARPROC)SpeedDlgProc, inst_handle );
DialogBoxParam( inst_handle,"SpeedDlg", window_handle, (DLGPROC)proc,
(DWORD)SET_TARGET_SPEED );
FreeProcInstance( proc );
break;
case MENU_SET_BOLT_SPEED:
inst_handle = GET_HINST( window_handle );
proc = MakeProcInstance( (FARPROC)SpeedDlgProc, inst_handle );
DialogBoxParam( inst_handle,"SpeedDlg", window_handle, (DLGPROC)proc,
(DWORD)SET_BOLT_SPEED );
FreeProcInstance( proc );
break;
case MENU_SCORE_WINDOW_ON:
/*
* toggle the score window on or off
*/
edata_ptr = (extra_data *) GetWindowLong( window_handle,
EXTRA_DATA_OFFSET );
if( !edata_ptr->score_on ) {
TurnScoreWindowOn( window_handle );
CheckMenuItem( GetMenu( window_handle ),
cmd, MF_BYCOMMAND | MF_CHECKED );
edata_ptr->score_on = TRUE;
} else {
SendMessage( ScoreWnd, WM_CLOSE, 0, 0L );
CheckMenuItem ( GetMenu( window_handle ), cmd,
MF_BYCOMMAND | MF_UNCHECKED );
edata_ptr->score_on = FALSE;
}
break;
case MENU_SOUND_ON:
/*
* toggle the sound on or off
*/
edata_ptr = (extra_data *) GetWindowLong( window_handle,
EXTRA_DATA_OFFSET );
if( !edata_ptr->sound_on ) {
CheckMenuItem ( GetMenu( window_handle ),
cmd, MF_BYCOMMAND | MF_CHECKED );
edata_ptr->sound_on = TRUE;
} else {
CheckMenuItem ( GetMenu( window_handle ), cmd,
MF_BYCOMMAND | MF_UNCHECKED );
edata_ptr->sound_on = FALSE;
}
break;
case MENU_MESSAGE_WINDOW_ON:
/*
* toggle the message window on or off
*/
if( !MessagesOn ) {
TurnMessageWindowOn( window_handle );
CheckMenuItem( GetMenu( window_handle ),
cmd, MF_BYCOMMAND | MF_CHECKED );
MessagesOn = TRUE;
} else {
SendMessage( MessageWnd, WM_CLOSE, 0, 0L );
CheckMenuItem( GetMenu( window_handle ), cmd,
MF_BYCOMMAND | MF_UNCHECKED );
MessagesOn = FALSE;
}
break;
}
break;
case WM_PAINT:
edata_ptr = (extra_data *) GetWindowLong( window_handle,
EXTRA_DATA_OFFSET );
hdc = BeginPaint (window_handle, &ps);
/*
* paint the invalid area with the background colour
*/
brush = CreateSolidBrush( BACKGROUND );
FillRect( hdc, &ps.rcPaint, brush );
DeleteObject( brush );
rect.left = edata_ptr->target.x;
rect.top = edata_ptr->target.y;
rect.right = rect.left + edata_ptr->size.x;
rect.bottom = rect.top + edata_ptr->size.y;
/*
* if part of the target bitmap is invalid, redraw it
*/
if( IntersectRect( &rect, &rect, &ps.rcPaint ) ) {
DrawBitmap( hdc, edata_ptr->target_bmp,
edata_ptr->target.x, edata_ptr->target.y );
}
EndPaint(window_handle, &ps);
break;
case WM_HSCROLL:
case WM_VSCROLL:
/*
* use the scrollbars to move the target around
*/
{
short position; /* the x or y position of the scrollbar */
short max;
short min;
WORD code;
WORD pos;
edata_ptr = (extra_data *) GetWindowLong( window_handle,
EXTRA_DATA_OFFSET );
if( msg == WM_HSCROLL ) {
position = edata_ptr->target.x;
code = GET_WM_HSCROLL_CODE( wparam, lparam );
pos = GET_WM_HSCROLL_POS( wparam, lparam );
} else {
position = edata_ptr->target.y;
code = GET_WM_VSCROLL_CODE( wparam, lparam );
pos = GET_WM_VSCROLL_POS( wparam, lparam );
}
switch( code ) {
case SB_PAGEDOWN:
position += 15;
break;
case SB_LINEDOWN:
position++;
break;
case SB_PAGEUP:
position -= 15;
break;
case SB_LINEUP:
position--;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
position = pos;
break;
default:
return( 0L );
}
if( msg == WM_HSCROLL ) {
GetScrollRange( window_handle, SB_HORZ, (LPINT)&min, (LPINT)&max );
edata_ptr->target.x = max( min( position, max ), min );
SetScrollPos( window_handle, SB_HORZ, edata_ptr->target.x , TRUE );
} else {
GetScrollRange( window_handle, SB_VERT, (LPINT)&min, (LPINT)&max );
edata_ptr->target.y = max( min( position, max ), min );
SetScrollPos( window_handle, SB_VERT, edata_ptr->target.y, TRUE );
}
InvalidateRect( window_handle, &edata_ptr->client_rect, FALSE );
}
break;
case WM_MOVE_TARGET:
/*
* move the target to a random location on the screen
*/
edata_ptr = (extra_data *) GetWindowLong( window_handle,
EXTRA_DATA_OFFSET );
rect.left = edata_ptr->target.x;
rect.top = edata_ptr->target.y;
rect.right = rect.left + edata_ptr->size.x;
rect.bottom = rect.top + edata_ptr->size.y;
InvalidateRect( window_handle, &rect, TRUE );
edata_ptr->target = RandPoint( edata_ptr->client_rect, edata_ptr->size );
rect.left = edata_ptr->target.x;
rect.top = edata_ptr->target.y;
rect.right = rect.left + edata_ptr->size.x;
rect.bottom = rect.top + edata_ptr->size.y;
InvalidateRect( window_handle, &rect, TRUE );
/* set the scrollbars to indicate the new position */
SetScrollPos( window_handle, SB_HORZ, edata_ptr->target.x , TRUE );
SetScrollPos( window_handle, SB_VERT, edata_ptr->target.y, TRUE );
break;
case WM_TIMER:
SendMessage( window_handle, WM_MOVE_TARGET, 0, 0L );
break;
break;
case WM_DESTROY:
edata_ptr = (extra_data *) GetWindowLong( window_handle,
EXTRA_DATA_OFFSET );
KillTimer( window_handle, TARGET_TIMER ); /* Stops the timer */
#ifndef __NT__
FreeProcInstance( edata_ptr->message_window_proc );
FreeProcInstance( edata_ptr->score_window_proc );
#endif
PostQuitMessage( 0 );
break;
default:
return( DefWindowProc( window_handle, msg, wparam, lparam ) );
}
return( 0L );
} /* WindowProc */
/*
* TurnMessageWindowOn - create the Message window, which will display
* messages received by WindowProc
* this window is a modeless dialog box
*/
BOOL TurnMessageWindowOn( HWND window_handle )
/********************************************/
{
HANDLE inst_handle;
extra_data *edata_ptr;
edata_ptr = (extra_data *) GetWindowLong( window_handle, EXTRA_DATA_OFFSET );
inst_handle = GET_HINST( window_handle );
MessageWnd = CreateDialog( inst_handle,"MessageWindow", window_handle,
(DLGPROC)edata_ptr->message_window_proc );
return( MessageWnd != NULL );
} /* TurnMessageWindowOn */
/*
* TurnMessageWindowOn - create the score window, which will display
* the number of shots the user has taken and what locations they have hit
* this window is a modeless dialog box
*/
BOOL TurnScoreWindowOn( HWND window_handle )
/******************************************/
{
HANDLE inst_handle;
extra_data *edata_ptr;
edata_ptr = (extra_data *) GetWindowLong( window_handle, EXTRA_DATA_OFFSET );
inst_handle = GET_HINST( window_handle );
ScoreWnd = CreateDialog( inst_handle,"ScoreWindow", window_handle,
(DLGPROC)edata_ptr->score_window_proc );
return( ScoreWnd != NULL );
} /* TurnScoreWindowOn */
/*
* processes messages for the score dialog box
*/
BOOL _EXPORT FAR PASCAL ScoreProc( HWND window_handle, UINT msg,
WPARAM wparam, LPARAM lparam )
/********************************************************************/
{
extra_data *edata_ptr;
wparam = wparam;
lparam = lparam;
edata_ptr = (extra_data *) GetWindowLong(
GetWindow( window_handle, GW_OWNER ), EXTRA_DATA_OFFSET );
switch (msg) {
case WM_INITDIALOG:
SetDlgItemInt( window_handle, SHOTS, 0, FALSE );
SetDlgItemInt( window_handle, YELLOW, 0, FALSE );
SetDlgItemInt( window_handle, RED, 0, FALSE );
SetDlgItemInt( window_handle, BLUE, 0, FALSE );
SetDlgItemInt( window_handle, BLACK, 0, FALSE );
SetDlgItemInt( window_handle, WHITE, 0, FALSE );
SetDlgItemInt( window_handle, MISSED, 0, FALSE );
return( TRUE );
case WM_CLOSE:
CheckMenuItem ( GetMenu( GetWindow( window_handle, GW_OWNER ) ),
MENU_SCORE_WINDOW_ON, MF_BYCOMMAND | MF_UNCHECKED );
DestroyWindow( window_handle );
/* not EndDialog, since this is a MODELESS dialog box */
edata_ptr->score_on = FALSE;
ScoreWnd = NULL;
break;
}
return( FALSE );
} /* ScoreProc */
BOOL _EXPORT FAR PASCAL MessageWindowProc( HWND window_handle, UINT msg,
WPARAM wparam, LPARAM lparam )
/********************************************************************/
{
char textbuffer[48];
/* buffer to hold strings before they are sent to dialog box controls */
static unsigned long timercount = 0;
/* counter - incremented each time a timer message is recieved */
/*
* other than WM_INITDIALOG & WM_CLOSE, all messages should be displayed
* in the dialog box, in the appropriate location
* so use wsprintf to format the message & then send the string to a
* static text control
*/
switch (msg) {
case WM_INITDIALOG:
return( TRUE );
case WM_CLOSE:
CheckMenuItem ( GetMenu( GetWindow( window_handle, GW_OWNER ) ),
MENU_MESSAGE_WINDOW_ON, MF_BYCOMMAND | MF_UNCHECKED );
DestroyWindow( window_handle );
/* not EndDialog, since this is a MODELESS dialog box */
MessagesOn = FALSE;
MessageWnd = NULL;
break;
case WM_MOUSEMOVE:
wsprintf( textbuffer, "WM_MOUSEMOVE: %x, %x, %x", wparam,
(int)(short)LOWORD(lparam ), (int)(short)HIWORD(lparam ) );
SetDlgItemText( window_handle, MOUSE_MOVE_BOX, (LPSTR)textbuffer );
return( TRUE );
case WM_LBUTTONDOWN:
wsprintf( textbuffer, "WM_LBUTTONDOWN: %x, %x, %x", wparam,
(int)(short)LOWORD(lparam ), (int)(short)HIWORD(lparam ) );
SetDlgItemText( window_handle, L_BUTTON_BOX, (LPSTR)textbuffer );
return( TRUE );
case WM_LBUTTONUP:
wsprintf( textbuffer, "WM_LBUTTONUP: %x, %x, %x", wparam,
(int)(short)LOWORD(lparam ), (int)(short)HIWORD(lparam ) );
SetDlgItemText( window_handle, L_BUTTON_BOX, (LPSTR)textbuffer );
return( TRUE );
case WM_LBUTTONDBLCLK:
wsprintf(textbuffer, "WM_LBUTTONDBLCLK: %x, %x, %x", wparam,
(int)(short)LOWORD(lparam ), (int)(short)HIWORD(lparam ) );
SetDlgItemText( window_handle, L_BUTTON_BOX, (LPSTR)textbuffer );
return( TRUE );
case WM_RBUTTONDOWN:
wsprintf(textbuffer, "WM_RBUTTONDOWN: %x, %x, %x", wparam,
(int)(short)LOWORD(lparam ), (int)(short)HIWORD(lparam ) );
SetDlgItemText( window_handle, R_BUTTON_BOX, (LPSTR)textbuffer );
return( TRUE );
case WM_RBUTTONUP:
wsprintf(textbuffer, "WM_RBUTTONUP: %x, %x, %x", wparam,
(int)(short)LOWORD(lparam ), (int)(short)HIWORD(lparam ) );
SetDlgItemText( window_handle, R_BUTTON_BOX, (LPSTR)textbuffer );
return( TRUE );
case WM_RBUTTONDBLCLK:
wsprintf(textbuffer, "WM_RBUTTONDBLCLK: %x, %x, %x", wparam,
(int)(short)LOWORD(lparam ), (int)(short)HIWORD(lparam ) );
SetDlgItemText( window_handle, R_BUTTON_BOX, (LPSTR)textbuffer );
return( TRUE );
case WM_KEYDOWN:
wsprintf(textbuffer, "WM_KEYDOWN: %x, %x, %x", wparam,
(int)(short)LOWORD(lparam ), (int)(short)HIWORD(lparam ) );
SetDlgItemText( window_handle, KEY_UP_OR_DOWN_BOX, (LPSTR)textbuffer );
return( TRUE );
case WM_KEYUP:
wsprintf(textbuffer, "WM_KEYUP: %x, %x, %x", wparam,
(int)(short)LOWORD(lparam ), (int)(short)HIWORD(lparam ) );
SetDlgItemText( window_handle, KEY_UP_OR_DOWN_BOX, (LPSTR)textbuffer );
return( TRUE );
case WM_CHAR:
wsprintf(textbuffer, "WM_CHAR: %c, %x, %x", wparam , LOWORD(lparam ), HIWORD(lparam ));
SetDlgItemText( window_handle, CHARACTER_BOX, (LPSTR)textbuffer );
return( TRUE );
case WM_TIMER:
{
extra_data *edata_ptr;
edata_ptr = (extra_data *) GetWindowLong(
GetWindow( window_handle, GW_OWNER ), EXTRA_DATA_OFFSET );
timercount += edata_ptr->target_speed;
wsprintf(textbuffer, "WM_TIMER: %d seconds", timercount / 1000 );
SetDlgItemText( window_handle, TIMER_BOX, (LPSTR)textbuffer );
return( TRUE );
}
case WM_HSCROLL:
case WM_VSCROLL:
{
char *buff1;
char *buff2;
WORD code;
if( msg == WM_HSCROLL ) {
buff1 = "WM_HSCROLL";
code = GET_WM_HSCROLL_CODE( wparam, lparam );
} else {
buff1 = "WM_VSCROLL";
code = GET_WM_VSCROLL_CODE( wparam, lparam );
}
switch( code ){
case SB_LINEUP:
buff2 = "SB_LINEUP";
break;
case SB_LINEDOWN:
buff2 = "SB_LINEDOWN";
break;
case SB_PAGEUP:
buff2 = "SB_PAGEUP";
break;
case SB_PAGEDOWN:
buff2 = "SB_PAGEDOWN";
break;
case SB_THUMBPOSITION:
buff2 = "SB_THUMBPOSITION";
break;
case SB_THUMBTRACK:
buff2 = "SB_THUMBTRACK";
break;
case SB_ENDSCROLL:
buff2 = "SB_ENDSCROLL";
break;
default :
buff2 = "unknown";
break;
}
wsprintf(textbuffer, "%s: %s, %x, %x",
(LPSTR)buff1, (LPSTR)buff2, (int)(short)LOWORD(lparam ),
(int)(short)HIWORD(lparam ));
SetDlgItemText( window_handle, SCROLL_BOX, (LPSTR)textbuffer );
return( TRUE );
}
}
return ( FALSE );
} /* MessageWindowProc */
/*
* calculate where on the target the bolt hit
* this is based on the colours of the target rings
*/
static void CheckHit( HDC hdc, POINT hit_point )
/**********************************************/
{
DWORD colour;
unsigned short points;
unsigned short dialog_item;
BOOL translated;
colour = GetPixel( hdc, hit_point.x, hit_point.y );
switch( colour ) {
case RING1:
dialog_item = YELLOW;
break;
case RING2:
dialog_item = RED;
break;
case RING3:
dialog_item = BLUE;
break;
case RING4:
dialog_item = BLACK;
break;
case RING5:
dialog_item = WHITE;
break;
case BACKGROUND:
dialog_item = MISSED;
break;
}
/*
* increment # of hits on location
*/
points = GetDlgItemInt( ScoreWnd, dialog_item, &translated, FALSE );
points++;
SetDlgItemInt( ScoreWnd, dialog_item, points, FALSE );
/*
* increment # of shots
*/
points = GetDlgItemInt( ScoreWnd, SHOTS, &translated, FALSE );
points++;
SetDlgItemInt( ScoreWnd, SHOTS, points, FALSE );
return;
} /* CheckHit */
/*
* display a bitmap on the given DC, at device coordinates x,y
* make the bitmap the same size as the source bitmap
*/
static void DrawBitmap( HDC hdc, HBITMAP bitmap, int x, int y )
/*****************************************************************/
{
BITMAP bitmapbuff;
HDC memorydc;
POINT origin;
POINT size;
memorydc = CreateCompatibleDC( hdc );
SelectObject( memorydc, bitmap );
SetMapMode( memorydc, GetMapMode( hdc ) );
GetObject( bitmap, sizeof( BITMAP ), (LPSTR) &bitmapbuff );
origin.x = x;
origin.y = y;
size.x = bitmapbuff.bmWidth;
size.y = bitmapbuff.bmHeight;
DPtoLP( hdc, &origin, 1 );
DPtoLP( memorydc, &size, 1 );
BitBlt( hdc, origin.x, origin.y, size.x, size.y, memorydc, 0, 0, SRCCOPY);
DeleteDC( memorydc );
} /* DrawBitmap */
/*
* pick a random point so that a bitmap with width & height specified by
* the second parameter will fit inside the given rectangle
*/
POINT RandPoint( RECT rect, POINT size )
/**************************************/
{
POINT random_point;
short width; /* width of the area to pick from */
short height; /* height of the area to pick from */
width = rect.right - rect.left - size.x;
height = rect.bottom - rect.top - size.y;
random_point.x = rand() % width + rect.left;
random_point.y = rand() % height + rect.top;
return( random_point );
} /* RandPoint */
/*
* Draws an icon at the coordinates x,y, after copying a saved bitmap back
* onto the screen at the coordinates where the last icon was drawn and
* saving the area under the icon to a DC in memory
*/
void DoDrawBolt( int x, int y, icon_mover * mover)
/************************************************/
{
/*
* to make this look fast, even on slow machines, only redraw the icon
* when the x coordinate is a multiple of the bolt speed
* thus if speed = 5, the icon will be redrawn every 5th pixel it moves
*/
if( x % mover->speed != 0 ) return;
/* if it is not the first iteration */
if( mover->last.x != -1 || mover->last.y != -1 ) {
/* redraw the area that the last icon covered */
BitBlt( mover->screen_dc, mover->last.x, mover->last.y, mover->size.x,
mover->size.y, mover->storage_dc, 0, 0, SRCCOPY);
}
/* save the area that will be under the icon to a DC in memory */
BitBlt( mover->storage_dc, 0, 0, mover->size.x, mover->size.y,
mover->screen_dc, x, y, SRCCOPY);
DrawIcon( mover->screen_dc, x, y, mover->icon );
/* save the coordinates for next time */
mover->last.x = x;
mover->last.y = y;
} /* DoDrawBolt */
/*
* called by windows from LineDDA funcion
*/
void _EXPORT FAR PASCAL DrawBolt( int x, int y, LPSTR dataptr )
/*************************************************************/
{
DoDrawBolt( x, y, (icon_mover *) dataptr );
} /* DrawBolt */
/*
* "shoot" a bolt from the current bolt location to the "aim" location
*/
static void ShootBolt( HWND window_handle )
/*****************************************/
{
extra_data *edata_ptr;
HDC hdc;
HBITMAP screensavebmp;
MSG msg;
FARPROC proc;
HANDLE inst_handle;
icon_mover mover;
edata_ptr = (extra_data *) GetWindowLong( window_handle,
EXTRA_DATA_OFFSET );
hdc = GetDC( window_handle );
inst_handle = GET_HINST( window_handle );
/* set up an "icon_mover" struct to give all needed data to DrawBolt */
mover.icon = edata_ptr->bolt_icon;
mover.size.x = BOLTWIDTH;
mover.size.y = BOLTHEIGHT;
mover.last.x = -1;
mover.last.y = -1;
mover.screen_dc = hdc;
mover.storage_dc = CreateCompatibleDC( hdc );
mover.speed = edata_ptr->bolt_speed;
screensavebmp = CreateCompatibleBitmap( hdc, mover.size.x, mover.size.y );
SelectObject( mover.storage_dc, screensavebmp );
if( edata_ptr->sound_on ) {
BoltSound();
}
/*
* for each point on the line between the points BOLT and AIM,
* call DrawBolt
* use aim - boltheight so that the bottom left corner of the bolt icon
* stops at the point AIM
*/
proc = MakeProcInstance( (FARPROC)DrawBolt, inst_handle );
LineDDA( edata_ptr->bolt.x, edata_ptr->bolt.y, edata_ptr->aim.x,
edata_ptr->aim.y - BOLTHEIGHT, (LINEDDAPROC)proc, (LPARAM)(LPVOID)&mover );
FreeProcInstance( proc );
/*
* remove all WM_LBUTTONDOWN messages from the application queue which
* occured while the bolt was "in the air"
* this prevents the shots from building up - only 1 can happen at a time
*/
while( PeekMessage( &msg, window_handle, WM_LBUTTONDOWN, WM_LBUTTONDOWN,
PM_REMOVE ) );
/* make sure the bolt is drawn at the final location regardless of speed */
mover.speed = 1;
DoDrawBolt( edata_ptr->aim.x, edata_ptr->aim.y - BOLTHEIGHT, &mover );
if( edata_ptr->sound_on ) {
BoomSound();
}
/* redraw the background behind the icon */
BitBlt( mover.screen_dc, mover.last.x, mover.last.y, mover.size.x,
mover.size.y, mover.storage_dc, 0, 0, SRCCOPY);
CheckHit( hdc, edata_ptr->aim );
DeleteDC( mover.storage_dc );
DeleteObject( screensavebmp );
ReleaseDC(window_handle, hdc);
} /* ShootBolt */
/*
* make a sound like thunder
* this function is called after each time BoltSound is called
* Sound is not implemented for the NT version
*/
static void BoomSound( void )
/***************************/
{
#ifndef __NT__
short i;
short low;
short high;
StopSound();
SetVoiceQueueSize( 1, 600 );
SetVoiceAccent( 1, 120, 50, S_STACCATO, 0 );
for( i=0; i < 1000; i++ ) {
/*
* create a random low-pitched sound
*/
high = rand() % 200 + 1;
low = rand() % high + 1;
SetVoiceSound( 1, MAKELONG( low, high ), 1 );
}
StartSound();
WaitSoundState( S_QUEUEEMPTY ); /* wait for the sound to finish */
StopSound();
CloseSound();
#endif
} /* BoomSound */
/*
* create a tone that goes from high-pitched to low-pitched
* Sound is not implemented for the NT version
*/
static void BoltSound( void )
/***************************/
{
#ifndef __NT__
short i;
OpenSound();
SetVoiceAccent( 1, 120, 50, S_LEGATO, 0 );
for( i=84; i > 0; i-- ) {
SetVoiceNote( 1, i, 128, 1 );
/* place a 128th note of value i into voice queue 1 */
}
StartSound();
#endif
} /* BoltSound */