#include #include #include #include #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 */