/*========================================================================== * * Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved. * * File: roids.c * Content: Shoot-em-up game * * @@BEGIN_MSINTERNAL * History: * Date By Reason * ==== == ====== * 17-jul-95 kylej initial * * @@END_MSINTERNAL * ***************************************************************************/ #include "roids.h" LPDIRECTDRAWSURFACE lpFrontBuffer; LPDIRECTDRAWSURFACE lpBackBuffer; LPDIRECTDRAWSURFACE lpDonut; LPDIRECTDRAWSURFACE lpPyramid; LPDIRECTDRAWSURFACE lpCube; LPDIRECTDRAWSURFACE lpSphere; LPDIRECTDRAWSURFACE lpShip; LPDIRECTDRAWSURFACE lpNum; LPDIRECTDRAW lpDD; LPDIRECTDRAWPALETTE lpArtPalette; LPDIRECTDRAWPALETTE lpSplashPalette; BOOL bSoundEnabled = FALSE; BOOL bPlayIdle = FALSE; BOOL bPlayBuzz = FALSE; BOOL bPlayRev = FALSE; DWORD lastInput = 0; BOOL lastThrust = FALSE; BOOL lastShield = FALSE; int showDelay = 0; HWND hWndMain; BOOL bShowFrameCount=TRUE; BOOL bIsActive; BOOL bMouseVisible; DWORD dwFrameCount; DWORD dwFrameTime; DWORD dwFrames; DWORD dwFramesLast; BOOL bUseEmulation; BOOL bTest=FALSE; BOOL bStress=FALSE; DWORD dwTransType; RGBQUAD SPalette[256]; DWORD lastTickCount; int score; int ProgramState; int level; int restCount; DWORD dwFillColor; BOOL bSpecialEffects = FALSE; DWORD ShowLevelCount = 3000; DWORD ScreenX; DWORD ScreenY; DWORD ScreenBpp; BOOL bWantSound = TRUE; //global hack to turn off sound int getint(char**p, int def); #ifdef DEBUG char DebugBuf[256]; BOOL bHELBlt = FALSE; #endif DBLNODE DL; // Display List #ifdef USE_DSOUND LPDIRECTSOUND lpDS; HSNDOBJ hsoBeginLevel = NULL; HSNDOBJ hsoEngineIdle = NULL; HSNDOBJ hsoEngineRev = NULL; HSNDOBJ hsoSkidToStop = NULL; HSNDOBJ hsoShieldBuzz = NULL; HSNDOBJ hsoShipExplode = NULL; HSNDOBJ hsoFireBullet = NULL; HSNDOBJ hsoShipBounce = NULL; HSNDOBJ hsoDonutExplode = NULL; HSNDOBJ hsoPyramidExplode = NULL; HSNDOBJ hsoCubeExplode = NULL; HSNDOBJ hsoSphereExplode = NULL; #endif void setup_game(void) { restCount = GetTickCount(); initLevel( ++level ); // set the palette lpFrontBuffer->lpVtbl->SetPalette( lpFrontBuffer, lpArtPalette ); } /* * MainWndproc * * Callback for all Windows messages */ long FAR PASCAL MainWndproc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { PAINTSTRUCT ps; HDC hdc; switch( message ) { case WM_ACTIVATEAPP: bIsActive = (BOOL) wParam; if( bIsActive ) { bMouseVisible = FALSE; lastTickCount = GetTickCount(); bSpecialEffects = FALSE; } else { bMouseVisible = TRUE; } break; case WM_CREATE: break; case WM_SETCURSOR: if( !bMouseVisible ) { SetCursor(NULL); } else { SetCursor(LoadCursor( NULL, IDC_ARROW )); } return TRUE; case WM_KEYDOWN: switch( wParam ) { case VK_NUMPAD7: lastInput |= KEY_SHIELD; break; case VK_NUMPAD5: lastInput |= KEY_STOP; break; case VK_DOWN: case VK_NUMPAD2: lastInput |= KEY_DOWN; break; case VK_LEFT: case VK_NUMPAD4: lastInput |= KEY_LEFT; break; case VK_RIGHT: case VK_NUMPAD6: lastInput |= KEY_RIGHT; break; case VK_UP: case VK_NUMPAD8: lastInput |= KEY_UP; break; case VK_NUMPAD3: lastInput |= KEY_THROW; break; case VK_SPACE: lastInput |= KEY_FIRE; break; case VK_F5: bShowFrameCount = !bShowFrameCount; if( bShowFrameCount ) { dwFrameCount = 0; dwFrameTime = timeGetTime(); } break; case VK_RETURN: if( ProgramState == PS_SPLASH ) { ProgramState = PS_BEGINREST; setup_game(); } break; case VK_ESCAPE: case VK_F12: PostMessage( hWnd, WM_CLOSE, 0, 0 ); return 0; case VK_F3: #ifdef USE_DSOUND if(bWantSound) { if( bSoundEnabled ) { DestroySound(); } else { InitializeSound(); } } #endif break; case VK_F1: bSpecialEffects = !bSpecialEffects; break; } break; case WM_KEYUP: switch( wParam ) { case VK_NUMPAD7: lastInput &= ~KEY_SHIELD; break; case VK_NUMPAD5: lastInput &= ~KEY_STOP; break; case VK_DOWN: case VK_NUMPAD2: lastInput &= ~KEY_DOWN; break; case VK_LEFT: case VK_NUMPAD4: lastInput &= ~KEY_LEFT; break; case VK_RIGHT: case VK_NUMPAD6: lastInput &= ~KEY_RIGHT; break; case VK_UP: case VK_NUMPAD8: lastInput &= ~KEY_UP; break; case VK_NUMPAD3: lastInput &= ~KEY_THROW; break; case VK_SPACE: lastInput &= ~KEY_FIRE; break; } break; case WM_ERASEBKGND: return 1; case WM_PAINT: hdc = BeginPaint( hWnd, &ps ); EndPaint( hWnd, &ps ); return 1; case WM_DESTROY: lastInput=0; DestroyGame(); PostQuitMessage( 0 ); break; default: break; } return DefWindowProc(hWnd, message, wParam, lParam); } /* MainWndproc */ /* * initApplication * * Do that Windows initialization stuff... */ static BOOL initApplication( HANDLE hInstance, int nCmdShow ) { WNDCLASS wc; BOOL rc; wc.style = CS_DBLCLKS; wc.lpfnWndProc = MainWndproc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon( hInstance, "ROIDS_ICON"); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = GetStockObject( BLACK_BRUSH ); wc.lpszMenuName = NULL; wc.lpszClassName = "RoidClass"; rc = RegisterClass( &wc ); if( !rc ) { return FALSE; } hWndMain = CreateWindowEx(0, // WS_EX_TOPMOST, "RoidClass", "Roids", WS_VISIBLE | // so we don't have to call ShowWindow WS_POPUP | // non-app window WS_SYSMENU, // so we get an icon in the tray 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL ); if( !hWndMain ) { return FALSE; } UpdateWindow( hWndMain ); return TRUE; } /* initApplication */ /* * WinMain */ int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { MSG msg; while( lpCmdLine[0] == '-' ) { lpCmdLine++; switch (*lpCmdLine++) { case 'e': bUseEmulation = TRUE; break; case 't': bTest = TRUE; break; case 'S': bWantSound = FALSE; break; case 'x': bStress= TRUE; bTest = TRUE; break; } while( IS_SPACE(*lpCmdLine) ) { lpCmdLine++; } } ScreenX = getint(&lpCmdLine, 640); ScreenY = getint(&lpCmdLine, 480); ScreenBpp = getint(&lpCmdLine, 8); if( !initApplication(hInstance, nCmdShow) ) { return FALSE; } if( !InitializeGame() ) { DestroyWindow( hWndMain ); return FALSE; } dwFrameTime = timeGetTime(); while( 1 ) { if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) { if( !GetMessage( &msg, NULL, 0, 0 ) ) { return msg.wParam; } TranslateMessage(&msg); DispatchMessage(&msg); } else if ( bIsActive ) { UpdateFrame(); } else { WaitMessage(); } } } /* WinMain */ void DestroyGame( void ) { } BOOL InitializeGame( void ) { DDCAPS ddcaps; HRESULT ddrval; DDSURFACEDESC ddsd; DDSCAPS ddscaps; #ifdef NT_HACK DDSURFACEDESC DDSurfDesc; #endif score = 0; if( bTest ) ShowLevelCount = 1000; if( bUseEmulation ) ddrval = DirectDrawCreate( (LPVOID) DDCREATE_EMULATIONONLY, &lpDD, NULL ); else ddrval = DirectDrawCreate( NULL, &lpDD, NULL ); if( ddrval != DD_OK ) return CleanupAndExit("DirectDrawCreate Failed!"); ddrval = lpDD->lpVtbl->SetCooperativeLevel( lpDD, hWndMain, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ); if( ddrval != DD_OK ) return CleanupAndExit("SetCooperativeLevel Failed"); #ifdef NT_HACK DDSurfDesc.dwSize = sizeof(DDSurfDesc); ddrval = lpDD->lpVtbl->GetDisplayMode(lpDD,&DDSurfDesc); if(ddrval == DD_OK) ScreenBpp = DDSurfDesc.ddpfPixelFormat.dwRGBBitCount; #endif // set the mode ddrval = lpDD->lpVtbl->SetDisplayMode( lpDD, ScreenX, ScreenY, ScreenBpp ); if( ddrval != DD_OK ) return CleanupAndExit("SetDisplayMode Failed!"); // check the color key hardware capabilities dwTransType = DDBLTFAST_SRCCOLORKEY; ddcaps.dwSize = sizeof( ddcaps ); #ifdef DEBUG if( GetProfileInt( "Roids", "force_dest_blt", 0) ) { dwTransType = DDBLTFAST_DESTCOLORKEY; } bHELBlt = GetProfileInt( "Roids", "force_HEL_blt", bHELBlt ); #endif // Create surfaces memset( &ddsd, 0, sizeof( ddsd ) ); ddsd.dwSize = sizeof( ddsd ); ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddsd.dwBackBufferCount = 1; ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpFrontBuffer, NULL ); if( ddrval != DD_OK ) return CleanupAndExit("CreateSurface FrontBuffer Failed!"); // get a pointer to the back buffer ddscaps.dwCaps = DDSCAPS_BACKBUFFER; ddrval = lpFrontBuffer->lpVtbl->GetAttachedSurface( lpFrontBuffer, &ddscaps, &lpBackBuffer ); if( ddrval != DD_OK ) return CleanupAndExit("GetAttachedDurface Failed!"); ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; #ifdef DEBUG if( bHELBlt ) ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; #endif ddsd.dwWidth = 320; ddsd.dwHeight = 384; ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpDonut, NULL ); if( ddrval != DD_OK ) return CleanupAndExit("CreateSurface lpDonut Failed!"); ddsd.dwHeight = 128; ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpPyramid, NULL ); if( ddrval != DD_OK ) return CleanupAndExit("CreateSurface lpPyramid Failed!"); ddsd.dwHeight = 32; ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpCube, NULL ); if( ddrval != DD_OK ) return CleanupAndExit("CreateSurface lpCube Failed!"); ddsd.dwHeight = 32; ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpSphere, NULL ); if( ddrval != DD_OK ) return CleanupAndExit("CreateSurface lpSphere Failed!"); // Set the background color fill color ddsd.dwHeight = 256; ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpShip, NULL ); if( ddrval != DD_OK ) return CleanupAndExit("CreateSurface lpShip Failed!"); ddsd.dwHeight = 16; ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpNum, NULL ); if( ddrval != DD_OK ) return CleanupAndExit("CreateSurface lpNum Failed!"); if( !RestoreSurfaces() ) return CleanupAndExit("RestoreSurfaces Failed!"); DL.next = DL.prev = &DL; // null display list DL.type = OBJ_SHIP; DL.surf = lpShip; lastTickCount = GetTickCount(); #ifdef USE_DSOUND if(bWantSound) { InitializeSound(); } #endif if(bTest) { ProgramState = PS_ACTIVE; setup_game(); } else { ProgramState = PS_SPLASH; } return TRUE; } BOOL CleanupAndExit( char *err) { #ifdef DEBUG wsprintf(DebugBuf, "___CleanupAndExit err = %s\n", err ); OutputDebugString( DebugBuf ); #endif // make the cursor visible SetCursor(LoadCursor( NULL, IDC_ARROW )); bMouseVisible = TRUE; if( lpDonut != NULL ) lpDonut->lpVtbl->Release( lpDonut ); if( lpPyramid != NULL ) lpPyramid->lpVtbl->Release( lpPyramid ); if( lpCube != NULL ) lpCube->lpVtbl->Release( lpCube ); if( lpSphere != NULL ) lpSphere->lpVtbl->Release( lpSphere ); if( lpShip != NULL ) lpShip->lpVtbl->Release( lpShip ); if( lpNum != NULL ) lpNum->lpVtbl->Release( lpNum ); if( lpFrontBuffer != NULL ) lpFrontBuffer->lpVtbl->Release( lpFrontBuffer ); if( lpArtPalette != NULL ) lpArtPalette->lpVtbl->Release( lpArtPalette ); if( lpSplashPalette != NULL ) lpSplashPalette->lpVtbl->Release( lpSplashPalette ); if( lpDD != NULL ) lpDD->lpVtbl->Release( lpDD ); // // warn user if there is one // if( !bStress ) { MessageBox( hWndMain, err, "ERROR", MB_OK ); } return FALSE; } void bltSplash( void ) { HRESULT ddrval; HBITMAP hbm; // set the palette before loading the splash screen lpFrontBuffer->lpVtbl->SetPalette( lpFrontBuffer, lpSplashPalette ); hbm = (HBITMAP)LoadImage( GetModuleHandle( NULL ), "SPLASH", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ); if ( NULL == hbm ) return; // if the surface is lost, DDCopyBitmap will fail and the surface will // be restored in FlipScreen. ddrval = DDCopyBitmap( lpBackBuffer, hbm, 0, 0, 0, 0 ); DeleteObject( hbm ); FlipScreen(); } #ifdef USE_DSOUND // // play a sound, but first set the panning according to where the // object is on the screen. fake 3D sound. // void playPanned(HSNDOBJ hSO, DBLNODE *object) { IDirectSoundBuffer *pDSB = SndObjGetFreeBuffer(hSO); if(!bWantSound) return; // No sound our Work is done if (pDSB) { switch(ScreenX) { case 320: IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 * ((object->dst.right + object->dst.left) / 2) / 320.0) - 10000.0)); break; case 640: IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 * ((object->dst.right + object->dst.left) / 2) / 640.0) - 10000.0)); break; case 1024: IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 * ((object->dst.right + object->dst.left) / 2) / 1024.0) - 10000.0)); break; case 1280: IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 * ((object->dst.right + object->dst.left) / 2) / 1280.0) - 10000.0)); break; } IDirectSoundBuffer_Play(pDSB, 0, 0, 0); } } #endif void UpdateFrame( void ) { switch( ProgramState ) { case PS_SPLASH: // display the splash screen bltSplash(); return; case PS_ACTIVE: UpdateDisplayList(); CheckForHits(); DrawDisplayList(); if ( isDisplayListEmpty() ) { #ifdef USE_DSOUND if(bWantSound) { SndObjStop(hsoEngineIdle); SndObjStop(hsoEngineRev); } #endif bPlayIdle = FALSE; bPlayRev = FALSE; lastThrust = lastShield = FALSE; ProgramState = PS_BEGINREST; restCount = GetTickCount(); initLevel( ++level ); } return; case PS_BEGINREST: #ifdef USE_DSOUND if(bWantSound) { SndObjPlay(hsoBeginLevel, 0); } #endif ProgramState = PS_REST; // // FALLTHRU // case PS_REST: if( ( GetTickCount() - restCount ) > ShowLevelCount ) { #ifdef USE_DSOUND if(bWantSound) { SndObjPlay(hsoEngineIdle, DSBPLAY_LOOPING); } #endif bPlayIdle = TRUE; lastTickCount = GetTickCount(); ProgramState = PS_ACTIVE; } else { DisplayLevel(); } return; } } void DisplayLevel( void ) { char buf[10]; EraseScreen(); buf[0] = 10 + '0'; buf[1] = 11 + '0'; buf[2] = 12 + '0'; buf[3] = 11 + '0'; buf[4] = 10 + '0'; buf[5] = '\0'; bltScore( buf, ScreenX/2-64, ScreenY/2-8 ); buf[0] = level / 100 + '0'; buf[1] = level / 10 + '0'; buf[2] = level % 10 + '0'; buf[3] = '\0'; bltScore( buf, ScreenX/2+22, ScreenY/2-8 ); FlipScreen(); } void bltScore( char *num, int x, int y ) { char *c; RECT src; int i; HRESULT ddrval; for(c=num; *c != '\0'; c++) { while( 1 ) { i = *c - '0'; src.left = i*16; src.top = 0; src.right = src.left + 16; src.bottom = src.top + 16; ddrval = lpBackBuffer->lpVtbl->BltFast( lpBackBuffer, x, y, lpNum, &src, dwTransType ); if( ddrval == DD_OK ) { break; } if( ddrval == DDERR_SURFACELOST ) { if( !RestoreSurfaces() ) return; } if( ddrval != DDERR_WASSTILLDRAWING ) { return; } } x += 16; } } void CheckForHits( void ) { LPDBLNODE bullet, target, save; int frame, x, y, l, t; BOOL hit; // update screen rects target = &DL; do { frame = (DWORD)target->frame; switch( target->type ) { case OBJ_DONUT: target->dst.left = (DWORD)target->posx; target->dst.top = (DWORD)target->posy; target->dst.right = target->dst.left + 64; target->dst.bottom = target->dst.top + 64; target->src.left = 64 * (frame % 5); target->src.top = 64 * (frame /5); target->src.right = target->src.left + 64; target->src.bottom = target->src.top + 64; break; case OBJ_PYRAMID: target->dst.left = (DWORD)target->posx; target->dst.top = (DWORD)target->posy; target->dst.right = target->dst.left + 32; target->dst.bottom = target->dst.top + 32; target->src.left = 32 * (frame % 10); target->src.top = 32 * (frame /10); target->src.right = target->src.left + 32; target->src.bottom = target->src.top + 32; break; case OBJ_SPHERE: target->dst.left = (DWORD)target->posx; target->dst.top = (DWORD)target->posy; target->dst.right = target->dst.left + 16; target->dst.bottom = target->dst.top + 16; target->src.left = 16 * (frame % 20); target->src.top = 16 * (frame /20); target->src.right = target->src.left + 16; target->src.bottom = target->src.top + 16; break; case OBJ_CUBE: target->dst.left = (DWORD)target->posx; target->dst.top = (DWORD)target->posy; target->dst.right = target->dst.left + 16; target->dst.bottom = target->dst.top + 16; target->src.left = 16 * (frame % 20); target->src.top = 16 * (frame /20); target->src.right = target->src.left + 16; target->src.bottom = target->src.top + 16; break; case OBJ_SHIP: target->dst.left = (DWORD)target->posx; target->dst.top = (DWORD)target->posy; target->dst.right = target->dst.left + 32; target->dst.bottom = target->dst.top + 32; if( lastShield ) target->src.top = 32 * (frame / 10) + 128; else target->src.top = 32 * (frame /10); target->src.left = 32 * (frame % 10); target->src.right = target->src.left + 32; target->src.bottom = target->src.top + 32; break; case OBJ_BULLET: frame = (DWORD)target->frame/20 % 4; target->dst.left = (DWORD)target->posx; target->dst.top = (DWORD)target->posy; target->dst.right = target->dst.left + 3; target->dst.bottom = target->dst.top + 3; target->src.left = BULLET_X + frame*4; target->src.top = BULLET_Y; target->src.right = target->src.left + 3; target->src.bottom = target->src.top + 3; break; } target = target->next; } while( target != &DL ); bullet=&DL; do { hit = FALSE; if((bullet->type != OBJ_BULLET) && (bullet != &DL)) { bullet = bullet->next; continue; } x = (bullet->dst.left + bullet->dst.right) / 2; y = (bullet->dst.top + bullet->dst.bottom) / 2; for(target=DL.next; target != &DL; target = target->next) { if( ( target->type != OBJ_DONUT ) && ( target->type != OBJ_PYRAMID ) && ( target->type != OBJ_SPHERE ) && ( target->type != OBJ_CUBE ) ) continue; if( (x >= target->dst.left) && (x < target->dst.right) && (y >= target->dst.top) && (y < target->dst.bottom) ) { if ((bullet != &DL) || !lastShield) { // the bullet hit the target switch( target->type ) { case OBJ_DONUT: #ifdef USE_DSOUND if(bWantSound) { playPanned(hsoDonutExplode, target); } #endif addObject( OBJ_PYRAMID, target->dst.left, target->dst.top, -1.0, -1.0 ); addObject( OBJ_PYRAMID, target->dst.left, target->dst.top, -1.0, -1.0 ); addObject( OBJ_PYRAMID, target->dst.left, target->dst.top, -1.0, -1.0 ); score += 10; break; case OBJ_PYRAMID: #ifdef USE_DSOUND if(bWantSound) { playPanned(hsoPyramidExplode, target); } #endif addObject( OBJ_SPHERE, target->dst.left, target->dst.top, -1.0, -1.0 ); addObject( OBJ_CUBE, target->dst.left, target->dst.top, -1.0, -1.0 ); addObject( OBJ_CUBE, target->dst.left, target->dst.top, -1.0, -1.0 ); score += 20; break; case OBJ_CUBE: #ifdef USE_DSOUND if(bWantSound) { playPanned(hsoCubeExplode, target); } #endif addObject( OBJ_SPHERE, target->dst.left, target->dst.top, -1.0, -1.0 ); addObject( OBJ_SPHERE, target->dst.left, target->dst.top, -1.0, -1.0 ); break; score += 40; case OBJ_SPHERE: #ifdef USE_DSOUND if(bWantSound) { playPanned(hsoSphereExplode, target); } #endif score += 20; } l = target->dst.left; t = target->dst.top; DeleteFromList( target ); } hit = TRUE; } if( hit ) { if( bullet == &DL ) { hit = FALSE; if (!lastShield && !showDelay && !bTest) { #ifdef USE_DSOUND if(bWantSound) { playPanned(hsoShipExplode, bullet); } #endif score -= 150; if (score < 0) score = 0; addObject( OBJ_SPHERE, l, t, -1.0, -1.0 ); addObject( OBJ_SPHERE, l, t, -1.0, -1.0 ); addObject( OBJ_SPHERE, l, t, -1.0, -1.0 ); addObject( OBJ_SPHERE, l, t, -1.0, -1.0 ); addObject( OBJ_BULLET, l, t, randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) ); addObject( OBJ_BULLET, l, t, randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) ); addObject( OBJ_BULLET, l, t, randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) ); addObject( OBJ_BULLET, l, t, randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) ); addObject( OBJ_BULLET, l, t, randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) ); addObject( OBJ_BULLET, l, t, randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) ); addObject( OBJ_BULLET, l, t, randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) ); addObject( OBJ_BULLET, l, t, randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) ); addObject( OBJ_BULLET, l, t, randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) ); addObject( OBJ_BULLET, l, t, randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) ); initShip(TRUE); } } break; } } if( hit ) { save = bullet; bullet = bullet->next; DeleteFromList( save ); } else { bullet = bullet->next; } } while (bullet != &DL); } void EraseScreen( void ) { DDBLTFX ddbltfx; HRESULT ddrval; if( bSpecialEffects ) // cool looking screen with no colorfill return; // Erase the background ddbltfx.dwSize = sizeof( ddbltfx ); ddbltfx.dwFillColor = dwFillColor; while( 1 ) { ddrval = lpBackBuffer->lpVtbl->Blt( lpBackBuffer, NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx ); if( ddrval == DD_OK ) { break; } if( ddrval == DDERR_SURFACELOST ) { if( !RestoreSurfaces() ) return; } if( ddrval != DDERR_WASSTILLDRAWING ) { return; } } } void FlipScreen( void ) { HRESULT ddrval; // Flip the surfaces while( 1 ) { ddrval = lpFrontBuffer->lpVtbl->Flip( lpFrontBuffer, NULL, 0 ); if( ddrval == DD_OK ) { break; } if( ddrval == DDERR_SURFACELOST ) { if( !RestoreSurfaces() ) { return; } } if( ddrval != DDERR_WASSTILLDRAWING ) { break; } } } void DrawDisplayList( void ) { LPDBLNODE this; LPDBLNODE last; HRESULT ddrval; char scorebuf[11]; int rem; // blt everything in reverse order if we are doing destination transparency // calculate score string scorebuf[0] = score/10000000 + '0'; rem = score % 10000000; scorebuf[1] = rem/1000000 + '0'; rem = score % 1000000; scorebuf[2] = rem/100000 + '0'; rem = score % 100000; scorebuf[3] = rem/10000 + '0'; rem = score % 10000; scorebuf[4] = rem/1000 + '0'; rem = score % 1000; scorebuf[5] = rem/100 + '0'; rem = score % 100; scorebuf[6] = rem/10 + '0'; rem = score % 10; scorebuf[7] = rem + '0'; #ifdef USE_DSOUND if( bSoundEnabled ) { scorebuf[8] = 14 + '0'; scorebuf[9] = 13 + '0'; scorebuf[10] = '\0'; } else #endif { scorebuf[8] = '\0'; } EraseScreen(); if( dwTransType == DDBLTFAST_DESTCOLORKEY ) { bltScore(scorebuf, 10, ScreenY-26); if( bShowFrameCount ) DisplayFrameRate(); this = DL.next; // start with the topmost bitmap last = DL.next; // don't blt it twice if (showDelay) last = &DL; } else { this = &DL; // start with the bottommost bitmap (the ship) last = &DL; // don't blt it twice if (showDelay) this = this->prev; } do { while( 1 ) { ddrval = lpBackBuffer->lpVtbl->BltFast( lpBackBuffer, this->dst.left, this->dst.top, this->surf, &(this->src), dwTransType ); if( ddrval == DD_OK ) { break; } if( ddrval == DDERR_SURFACELOST ) { if( !RestoreSurfaces() ) return; } if( ddrval != DDERR_WASSTILLDRAWING ) { return; } } if( dwTransType != DDBLTFAST_DESTCOLORKEY ) { this = this->prev; } else { this = this->next; } } while( this != last ); if( dwTransType != DDBLTFAST_DESTCOLORKEY ) { bltScore(scorebuf, 10, ScreenY-26); if( bShowFrameCount ) DisplayFrameRate(); } FlipScreen(); } void DisplayFrameRate( void ) { DWORD time2; char buff[256]; dwFrameCount++; time2 = timeGetTime() - dwFrameTime; if( time2 > 1000 ) { dwFrames = (dwFrameCount*1000)/time2; dwFrameTime = timeGetTime(); dwFrameCount = 0; } if( dwFrames == 0 ) { return; } if (dwFrames != dwFramesLast) { dwFramesLast = dwFrames; } if( dwFrames > 99 ) { dwFrames = 99; } buff[0] = (char)((dwFrames / 10) + '0'); buff[1] = (char)((dwFrames % 10) + '0'); buff[2] = '\0'; bltScore(buff, ScreenX/2-25, 10); } void DeleteFromList( LPDBLNODE this ) { this->next->prev = this->prev; this->prev->next = this->next; LocalFree( this ); } void UpdateDisplayList( void ) { LPDBLNODE this; LPDBLNODE save; DWORD thisTickCount = GetTickCount(); DWORD tickDiff = thisTickCount - lastTickCount; double maxx, maxy; double maxframe; DWORD input = lastInput; BOOL event = FALSE; if( bTest ) { input |= (KEY_RIGHT | KEY_FIRE); } lastTickCount = thisTickCount; if (showDelay) { showDelay -= (int)tickDiff; if (showDelay < 0) { showDelay = 0; lastShield = FALSE; initShip( FALSE ); } } // update the ship if( !showDelay ) { DL.posx += DL.velx * (double)tickDiff; DL.posy += DL.vely * (double)tickDiff; } if( DL.posx > MAX_SHIP_X ) { DL.posx = MAX_SHIP_X; DL.velx = -DL.velx; event = TRUE; } else if ( DL.posx < 0 ) { DL.posx =0; DL.velx = -DL.velx; event = TRUE; } if( DL.posy > MAX_SHIP_Y ) { DL.posy = MAX_SHIP_Y; DL.vely = -DL.vely; event = TRUE; } else if ( DL.posy < 0 ) { DL.posy =0; DL.vely = -DL.vely; event = TRUE; } if (event) { #ifdef USE_DSOUND if(bWantSound) { playPanned(hsoShipBounce, &DL); } #endif event = FALSE; } if ((event = (showDelay || ((input & KEY_SHIELD) == KEY_SHIELD))) != lastShield) { if (event && !showDelay) { #ifdef USE_DSOUND if(bWantSound) { SndObjPlay(hsoShieldBuzz, DSBPLAY_LOOPING); } #endif bPlayBuzz = TRUE; } else { #ifdef USE_DSOUND if(bWantSound) { SndObjStop(hsoShieldBuzz); } #endif bPlayBuzz = FALSE; } lastShield = event; } if (event) { input &= ~(KEY_FIRE); } if (input & KEY_FIRE) { if( !showDelay ) { // add a bullet to the scene score--; if(score < 0) score = 0; #ifdef USE_DSOUND if(bWantSound) { SndObjPlay(hsoFireBullet, 0); } #endif addObject( OBJ_BULLET, Dirx[(int)DL.frame]*6.0 + 16.0 + DL.posx, Diry[(int)DL.frame]*6.0 + 16.0 + DL.posy, Dirx[(int)DL.frame]*500.0/1000.0, Diry[(int)DL.frame]*500.0/1000.0 ); } } event = FALSE; if( input & KEY_LEFT ) { DL.frame -= 1.0; if( DL.frame < 0.0 ) DL.frame += MAX_SHIP_FRAME; } if( input & KEY_RIGHT ) { DL.frame += 1.0; if( DL.frame >= MAX_SHIP_FRAME) DL.frame -= MAX_SHIP_FRAME; } if( input & KEY_UP ) { DL.velx += Dirx[(int)DL.frame] * 10.0/1000.0; DL.vely += Diry[(int)DL.frame] * 10.0/1000.0; event = TRUE; } if( input & KEY_DOWN ) { DL.velx -= Dirx[(int)DL.frame] * 10.0/1000.0; DL.vely -= Diry[(int)DL.frame] * 10.0/1000.0; event = TRUE; } if (event != lastThrust) { if (event) { input &= ~KEY_STOP; #ifdef USE_DSOUND if(bWantSound) { SndObjStop(hsoSkidToStop); SndObjPlay(hsoEngineRev, DSBPLAY_LOOPING); } #endif bPlayRev = TRUE; } else { #ifdef USE_DSOUND if(bWantSound) { SndObjStop(hsoEngineRev); } #endif bPlayRev = FALSE; } lastThrust = event; } if( input & KEY_STOP ) { #ifdef USE_DSOUND if(bWantSound) { if (DL.velx || DL.vely) playPanned(hsoSkidToStop, &DL); } #endif DL.velx = 0; DL.vely = 0; } this = DL.next; do { this->posx += this->velx * (double)tickDiff; this->posy += this->vely * (double)tickDiff; this->frame += this->delay * (double)tickDiff; switch( this->type ) { case OBJ_DONUT: maxx = (double)MAX_DONUT_X; maxy = (double)MAX_DONUT_Y; maxframe = (double)MAX_DONUT_FRAME; break; case OBJ_PYRAMID: maxx = (double)MAX_PYRAMID_X; maxy = (double)MAX_PYRAMID_Y; maxframe = (double)MAX_PYRAMID_FRAME; break; case OBJ_SPHERE: maxx = (double)MAX_SPHERE_X; maxy = (double)MAX_SPHERE_Y; maxframe = (double)MAX_SPHERE_FRAME; break; case OBJ_CUBE: maxx = (double)MAX_CUBE_X; maxy = (double)MAX_CUBE_Y; maxframe = (double)MAX_CUBE_FRAME; break; case OBJ_BULLET: maxx = (double)MAX_BULLET_X; maxy = (double)MAX_BULLET_Y; maxframe = (double)MAX_BULLET_FRAME; if( this->frame >= (double)MAX_BULLET_FRAME ) { save = this; this = this->next; DeleteFromList( save ); continue; } break; } if( this != &DL ) { if( this->posx > maxx ) { this->posx = maxx; this->velx = -this->velx; } else if ( this->posx < 0 ) { this->posx =0; this->velx = -this->velx; } if( this->posy > maxy ) { this->posy = maxy; this->vely = -this->vely; } else if ( this->posy < 0 ) { this->posy =0; this->vely = -this->vely; } if( this->frame >= maxframe ) { this->frame -= maxframe; } this = this->next; } } while( this != &DL ); } BOOL isDisplayListEmpty( void ) { LPDBLNODE ptr; for(ptr=DL.next; ptr != &DL; ptr = ptr->next) { if(ptr->type != OBJ_BULLET) return FALSE; } return TRUE; } void initShip( BOOL delay ) { DL.posx = (double)(ScreenX/2-16); // center the ship DL.posy = (double)(ScreenY/2-16); DL.frame = 0.0; if( bTest ) { DL.velx = 0.25; DL.vely = 0.5; } else { DL.velx = DL.vely = 0.0; // not moving } if( !bTest && delay ) showDelay = DEF_SHOW_DELAY; } void initLevel( int level ) { int i; // clear any stray bullets out of the display list while( DL.next != &DL ) { DeleteFromList( DL.next ); } for(i=0; i<(2*level-1); i++) { addObject( OBJ_DONUT, -1.0, -1.0, -1.0, -1.0 ); } initShip(TRUE); } void addObject( SHORT type, double x, double y, double vx, double vy ) { LPDBLNODE new; new = (LPDBLNODE) LocalAlloc( LPTR, sizeof( DBLNODE ) ); if( new == NULL) return; new->type = type; switch( type ) { case OBJ_DONUT: if( x < 0.0) // no position specified? { new->posx = randDouble( 0.0, (double)MAX_DONUT_X ); new->posy = randDouble( 0.0, (double)MAX_DONUT_Y ); } else { new->posx = x; new->posy = y; } new->velx = randDouble( -50.0/1000.0, 50.0/1000.0 ); new->vely = randDouble( -50.0/1000.0, 50.0/1000.0 ); new->frame = randDouble( 0, 30 ); new->delay = 30.0*randDouble( 0.1, 0.4 )/1000.0; new->surf = lpDonut; linkObject( new ); break; case OBJ_PYRAMID: if( x < 0) // no position specified? { new->posx = randDouble( 0.0, (double)MAX_PYRAMID_X ); new->posy = randDouble( 0.0, (double)MAX_PYRAMID_Y ); } else { new->posx = x; new->posy = y; } new->velx = 1.5*randDouble( -50.0/1000.0, 50.0/1000.0 ); new->vely = 1.5*randDouble( -50.0/1000.0, 50.0/1000.0 ); new->frame = randDouble( 0, 30 ); new->delay = 40.0*randDouble( 0.3, 1.0 )/1000.0; new->surf = lpPyramid; linkObject( new ); break; case OBJ_SPHERE: if( x < 0) // no position specified? { new->posx = randDouble( 0.0, (double)MAX_SPHERE_X ); new->posy = randDouble( 0.0, (double)MAX_SPHERE_Y ); } else { new->posx = x; new->posy = y; } new->velx = 3.0*randDouble( -50.0/1000.0, 50.0/1000.0 ); new->vely = 3.0*randDouble( -50.0/1000.0, 50.0/1000.0 ); new->frame = randDouble( 0, 30 ); new->delay = 40.0*randDouble( 1.5, 2.0 )/1000.0; new->surf = lpSphere; linkObject( new ); break; case OBJ_CUBE: if( x < 0) // no position specified? { new->posx = randDouble( 0.0, (double)MAX_CUBE_X ); new->posy = randDouble( 0.0, (double)MAX_CUBE_Y ); } else { new->posx = x; new->posy = y; } new->velx = 4.0*randDouble( -50.0/1000.0, 50.0/1000.0 ); new->vely = 4.0*randDouble( -50.0/1000.0, 50.0/1000.0 ); new->frame = randDouble( 0, 30 ); new->delay = 40.0*randDouble( 0.8, 2.0 )/1000.0; new->surf = lpCube; linkObject( new ); break; case OBJ_BULLET: new->posx = x; new->posy = y; new->velx = vx; new->vely = vy; new->frame = 0.0; new->delay = 1.0; new->surf = lpNum; linkObject( new ); break; } } void linkObject( LPDBLNODE new ) { new->next = DL.next; new->prev = &DL; DL.next->prev = new; DL.next = new; } void linkLastObject( LPDBLNODE new ) { new->prev = DL.prev; new->next = &DL; DL.prev->next = new; DL.prev = new; } BOOL RestoreSurfaces( void ) { HRESULT ddrval; HBITMAP hbm; ddrval = lpFrontBuffer->lpVtbl->Restore(lpFrontBuffer); if( ddrval != DD_OK ) return FALSE; ddrval = lpDonut->lpVtbl->Restore(lpDonut); if( ddrval != DD_OK ) return FALSE; ddrval = lpPyramid->lpVtbl->Restore(lpPyramid); if( ddrval != DD_OK ) return FALSE; ddrval = lpCube->lpVtbl->Restore(lpCube); if( ddrval != DD_OK ) return FALSE; ddrval = lpSphere->lpVtbl->Restore(lpSphere); if( ddrval != DD_OK ) return FALSE; ddrval = lpShip->lpVtbl->Restore(lpShip); if( ddrval != DD_OK ) return FALSE; ddrval = lpNum->lpVtbl->Restore(lpNum); if( ddrval != DD_OK ) return FALSE; // Create and set the palette for the splash bitmap lpSplashPalette = DDLoadPalette( lpDD, "SPLASH" ); if( NULL == lpSplashPalette ) return CleanupAndExit("DDLoadPalette SPLASH"); // Create and set the palette for the art bitmap lpArtPalette = DDLoadPalette( lpDD, "ROIDS8" ); if( NULL == lpArtPalette ) return CleanupAndExit("DDLoadPalette ROIDS"); // set the palette before loading the art lpFrontBuffer->lpVtbl->SetPalette( lpFrontBuffer, lpArtPalette ); hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "ROIDS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ); if( NULL == hbm ) return FALSE; ddrval = DDCopyBitmap( lpDonut, hbm, 0, 0, 320, 384 ); if( ddrval != DD_OK ) { DeleteObject( hbm ); return FALSE; } // NOTE: Why are we calling LoadImage again? StretchBlt (which is // called in DDCopyBitmap) does not work properly when performing // an 8-bpp to 24- or 32-bpp blt multiple times from the same // bitmap. The workaround is to call LoadImage before each // StretchBlt because the first StretchBlt after a LoadImage will // work. if(ScreenBpp >= 24) { DeleteObject( hbm ); hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "ROIDS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ); if( NULL == hbm ) return FALSE; } ddrval = DDCopyBitmap( lpPyramid, hbm, 0, 384, 320, 128 ); if( ddrval != DD_OK ) { DeleteObject( hbm ); return FALSE; } if(ScreenBpp >= 24) { DeleteObject( hbm ); hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "ROIDS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ); if( NULL == hbm ) return FALSE; } ddrval = DDCopyBitmap( lpSphere, hbm, 0, 512, 320, 32 ); if( ddrval != DD_OK ) { DeleteObject( hbm ); return FALSE; } if(ScreenBpp >= 24) { DeleteObject( hbm ); hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "ROIDS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ); if( NULL == hbm ) return FALSE; } ddrval = DDCopyBitmap( lpCube, hbm, 0, 544, 320, 32 ); if( ddrval != DD_OK ) { DeleteObject( hbm ); return FALSE; } if(ScreenBpp >= 24) { DeleteObject( hbm ); hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "ROIDS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ); if( NULL == hbm ) return FALSE; } ddrval = DDCopyBitmap( lpShip, hbm, 0, 576, 320, 256 ); if( ddrval != DD_OK ) { DeleteObject( hbm ); return FALSE; } if(ScreenBpp >= 24) { DeleteObject( hbm ); hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "ROIDS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ); if( NULL == hbm ) return FALSE; } ddrval = DDCopyBitmap( lpNum, hbm, 0, 832, 320, 16 ); if( ddrval != DD_OK ) { DeleteObject( hbm ); return FALSE; } DeleteObject( hbm ); // set colorfill colors and color keys according to bitmap contents dwFillColor = DDColorMatch( lpDonut, CLR_INVALID ); DDSetColorKey( lpDonut, CLR_INVALID ); DDSetColorKey( lpPyramid, CLR_INVALID ); DDSetColorKey( lpCube, CLR_INVALID ); DDSetColorKey( lpSphere, CLR_INVALID ); DDSetColorKey( lpShip, CLR_INVALID ); DDSetColorKey( lpNum, CLR_INVALID ); return TRUE; } int randInt( int low, int high ) { int range = high - low; int num = rand() % range; return( num + low ); } double randDouble( double low, double high ) { double range = high - low; double num = range * (double)rand()/(double)RAND_MAX; return( num + low ); } #ifdef USE_DSOUND void InitializeSound( void ) { if(!bWantSound) return; // out of here bSoundEnabled = FALSE; if (SUCCEEDED(DirectSoundCreate(NULL, &lpDS, NULL))) { if (SUCCEEDED(lpDS->lpVtbl->SetCooperativeLevel(lpDS, hWndMain, DSSCL_NORMAL))) { hsoBeginLevel = SndObjCreate(lpDS, "BeginLevel", 1); hsoEngineIdle = SndObjCreate(lpDS, "EngineIdle", 1); hsoEngineRev = SndObjCreate(lpDS, "EngineRev", 1); hsoSkidToStop = SndObjCreate(lpDS, "SkidToStop", 1); hsoShieldBuzz = SndObjCreate(lpDS, "ShieldBuzz", 1); hsoShipExplode = SndObjCreate(lpDS, "ShipExplode", 1); hsoFireBullet = SndObjCreate(lpDS, "Gunfire", 25); hsoShipBounce = SndObjCreate(lpDS, "ShipBounce", 4); hsoDonutExplode = SndObjCreate(lpDS, "DonutExplode", 10); hsoPyramidExplode = SndObjCreate(lpDS, "PyramidExplode", 12); hsoCubeExplode = SndObjCreate(lpDS, "CubeExplode", 15); hsoSphereExplode = SndObjCreate(lpDS, "SphereExplode", 10); bSoundEnabled = TRUE; //#ifdef USE_DSOUND this should be dead code Josephc if( bPlayIdle ) SndObjPlay(hsoEngineIdle, DSBPLAY_LOOPING); if( bPlayBuzz ) SndObjPlay(hsoShieldBuzz, DSBPLAY_LOOPING); if( bPlayRev ) SndObjPlay(hsoEngineRev, DSBPLAY_LOOPING); //#endif } else { lpDS->lpVtbl->Release(lpDS); lpDS = NULL; } } } void DestroySound( void ) { if(!bWantSound) return; //No work to be done bSoundEnabled = FALSE; if (lpDS) { SndObjDestroy(hsoBeginLevel); hsoBeginLevel = NULL; SndObjDestroy(hsoEngineIdle); hsoEngineIdle = NULL; SndObjDestroy(hsoEngineRev); hsoEngineRev = NULL; SndObjDestroy(hsoSkidToStop); hsoSkidToStop = NULL; SndObjDestroy(hsoShieldBuzz); hsoShieldBuzz = NULL; SndObjDestroy(hsoShipExplode); hsoShipExplode = NULL; SndObjDestroy(hsoFireBullet); hsoFireBullet = NULL; SndObjDestroy(hsoShipBounce); hsoShipBounce = NULL; SndObjDestroy(hsoDonutExplode); hsoDonutExplode = NULL; SndObjDestroy(hsoPyramidExplode); hsoPyramidExplode = NULL; SndObjDestroy(hsoCubeExplode); hsoCubeExplode = NULL; SndObjDestroy(hsoSphereExplode); hsoSphereExplode = NULL; lpDS->lpVtbl->Release(lpDS); lpDS = NULL; } } #endif int getint(char**p, int def) { int i=0; while (IS_SPACE(**p)) (*p)++; if (!IS_NUM(**p)) return def; while (IS_NUM(**p)) i = i*10 + *(*p)++ - '0'; while (IS_SPACE(**p)) (*p)++; return i; }