home *** CD-ROM | disk | FTP | other *** search
/ NEXT Generation 27 / NEXT27.iso / pc / demos / emperor / dx3.exe / SDK / SAMPLES / IKLOWNS / IKLOWNS.CPP < prev    next >
C/C++ Source or Header  |  1996-08-28  |  23KB  |  804 lines

  1. /*===========================================================================*\
  2. |
  3. |  File:        iklowns.cpp
  4. |
  5. |  Description:    
  6. |        
  7. |-----------------------------------------------------------------------------
  8. |
  9. |  Copyright (C) 1995-1996 Microsoft Corporation.  All Rights Reserved.
  10. |
  11. |  Written by Moss Bay Engineering, Inc. under contract to Microsoft Corporation
  12. |
  13. \*===========================================================================*/
  14.  
  15. /**************************************************************************
  16.  
  17.     (C) Copyright 1995-1996 Microsoft Corp.  All rights reserved.
  18.  
  19.     You have a royalty-free right to use, modify, reproduce and 
  20.     distribute the Sample Files (and/or any modified version) in 
  21.     any way you find useful, provided that you agree that 
  22.     Microsoft has no warranty obligations or liability for any 
  23.     Sample Application Files which are modified. 
  24.  
  25.     we do not recomend you base your game on IKlowns, start with one of
  26.     the other simpler sample apps in the GDK
  27.  
  28.  **************************************************************************/
  29.  
  30. #define INITGUID
  31. #include <windows.h>
  32. #include <windowsx.h>
  33. #include <mmsystem.h>
  34. #include <stdio.h>
  35. #include <stdarg.h>
  36. #include <eh.h>
  37. #include "strrec.h"
  38. #include "cgglobl.h"
  39. #include "cgrsrce.h"  // Windows resource IDs
  40. #include "cgexcpt.h"
  41. #include "cgimage.h"
  42. #include "cgdib.h"
  43. #include "cgchar.h"
  44. #include "cglevel.h"
  45. #include "cgtimer.h"
  46. #include "cginput.h"
  47. #include "cgmidi.h"
  48. #include "cgoption.h"
  49. #include "cgload.h"
  50. #include "iklowns.h"   // specific to this program
  51.  
  52. #define WPM_ANIMATE (WM_USER+1)
  53.  
  54. #define CHOICE_SOLO    0
  55. #define CHOICE_TWO    1
  56. #define CHOICE_NET    2
  57. #define CHOICE_QUIT    3
  58.  
  59. #define FIVE_SECONDS    5000
  60.  
  61. //** local definitions **
  62. // ImmortalKlowns 279afa8b-4981-11ce-a521-0020af0be560
  63. DEFINE_GUID(IMMORTALKLOWNS_GUID,0x279AFA8B,0x4981,0x11CE,0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60);
  64.  
  65. char szAppName[] = "IKlowns";   // The name of this application
  66. char szTitle[]   = "Immortal Klowns"; // The title bar text
  67.  
  68. CGameScreen* pGameScreen = NULL;
  69. CGameLevel* pRumbleLevel = NULL;
  70.  
  71. CGameTimer* Timer = NULL;
  72. CGameInput* Input = NULL;
  73. CLoadingScreen* gLoadingScreen = NULL;
  74. static COptionScreen* pOptionScreen = NULL;
  75. int gGameMode = 0;
  76.  
  77. void ShutDownApp(void);
  78. void GetMachineCaps();
  79.  
  80. #ifdef ONLY_ONE_INSTANCE
  81. HANDLE    hMutex = 0;
  82. #endif
  83.  
  84. // unhandled exception handler
  85. #if defined(__BORLANDC__) || defined(__WATCOMC__)
  86. void _cdecl UnHandler(void);
  87. #else
  88. void UnHandler(void);
  89. #endif
  90. void dbgprintf(char *fmt,...)
  91. {
  92.    char    out [ 256 ];
  93.    va_list vlist;
  94.    va_start(vlist, fmt);
  95.    wvsprintf(out, fmt, vlist);
  96.    OutputDebugString(out);        
  97. }
  98.  
  99. /****************************************************************************
  100.  
  101.         FUNCTION: WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
  102.  
  103.         PURPOSE: calls initialization function, processes message loop
  104.  
  105.         COMMENTS:
  106.  
  107.                 Windows recognizes this function by name as the initial entry point
  108.                 for the program.  This function calls the application initialization
  109.                 routine, if no other instance of the program is running, and always
  110.                 calls the instance initialization routine.  It then executes a message
  111.                 retrieval and dispatch loop that is the top-level control structure
  112.                 for the remainder of execution.  The loop is terminated when a WM_QUIT
  113.                 message is received, at which time this function exits the application
  114.                 instance by returning the value passed by PostQuitMessage().
  115.  
  116.                 If this function must abort before entering the message loop, it
  117.                 returns the conventional value NULL.
  118.  
  119. ****************************************************************************/
  120. int CALLBACK WinMain(
  121.         HINSTANCE hInstance,
  122.         HINSTANCE hPrevInstance,
  123.         LPSTR lpCmdLine,
  124.         int nCmdShow)
  125. {
  126.     MSG msg;
  127.     HACCEL hAccelTable;
  128.     int result = NULL;
  129.  
  130.     // only allow 1 instance
  131.     if (hPrevInstance)
  132.       return NULL;
  133.  
  134.     // install default exception handler
  135.     set_terminate( UnHandler );
  136.  
  137.     ghInst = hInstance;
  138.  
  139.     if (InitInstance(hInstance, nCmdShow))
  140.     {
  141.         hAccelTable = LoadAccelerators (hInstance,
  142.         MAKEINTRESOURCE(IDR_ACCELERATOR1));
  143.  
  144.         /* Acquire and dispatch messages until a WM_QUIT message is
  145.         received.
  146.         */
  147.  
  148.         while (GetMessage(&msg, // message structure
  149.           NULL,   // handle of window receiving the message
  150.           0,      // lowest message to examine
  151.           0))     // highest message to examine
  152.         {
  153.             if (!TranslateAccelerator (msg.hwnd, hAccelTable, &msg))
  154.             {
  155.                 TranslateMessage(&msg);// Translates virtual key codes
  156.                 DispatchMessage(&msg); // Dispatches message to window
  157.             }
  158.         }
  159.  
  160.         ShutDownApp();    // call de-init code
  161.         result = msg.wParam;
  162.  
  163. #ifdef ONLY_ONE_INSTANCE
  164.         CloseHandle(hMutex);
  165. #endif
  166.     }
  167.     return (result);
  168. }
  169.  
  170. // ----------------------------------------------------------
  171. // GetSoundFromProfile - description
  172. // ----------------------------------------------------------
  173. CSoundEffect *GetSoundFromProfile(
  174.     LPSTR    SectionName,
  175.     LPSTR    TopicName,
  176.     LPSTR    ProfileName
  177. )
  178. {
  179.     char    dataBuf[256];
  180.  
  181.     // Load any sound effects to be played
  182.     GetPrivateProfileString(SectionName, TopicName, ""
  183.     , dataBuf, sizeof(dataBuf), ProfileName);
  184.  
  185.     CStringRecord fields( dataBuf, "," );
  186.     BOOL fLoop=FALSE;
  187.  
  188.     // See if the sound is to be looped when it is played
  189.     if ((fields.GetNumFields() > 2) && (toupper(*fields[2]) == 'L'))
  190.     {
  191.         fLoop = TRUE;
  192.     }
  193.  
  194.     // Create sound effect object based on WAV file
  195.     CSoundEffect *pSound = new CSoundEffect(fields[0], 0, fLoop, gSoundMode);
  196.  
  197.     // If a volume was specified and sound got created ok,
  198.     // set the defaul volume
  199.     if (pSound != NULL) 
  200.     {
  201.         if (fields.GetNumFields() > 1)
  202.             pSound->SetVolume(atoi(fields[1]));
  203.     }
  204.  
  205.     return(pSound);
  206.         
  207. }
  208.  
  209. // ----------------------------------------------------------
  210. // GetRectFromProfile - description
  211. // ----------------------------------------------------------
  212. void GetRectFromProfile(
  213.     RECT    &rect,
  214.     LPSTR    SectionName,
  215.     LPSTR    EntryName,
  216.     LPSTR    ProfileName
  217. )
  218. {
  219.     char    dataBuf[256];
  220.  
  221.     GetPrivateProfileString(SectionName, EntryName, ""
  222.     , dataBuf, sizeof(dataBuf), ProfileName);
  223.     {
  224.         CStringRecord fields( dataBuf, "," );
  225.         if (fields.GetNumFields() == 4)
  226.         {
  227.             rect.left = atoi(fields[0]);
  228.             rect.top = atoi(fields[1]);
  229.             rect.right = atoi(fields[2]);
  230.             rect.bottom = atoi(fields[3]);
  231.         }
  232.     }
  233. }
  234.  
  235. // ----------------------------------------------------------
  236. // GetPointFromProfile - description
  237. // ----------------------------------------------------------
  238. void GetPointFromProfile(
  239.     POINT    &pt,
  240.     LPSTR    SectionName,
  241.     LPSTR    EntryName,
  242.     LPSTR    ProfileName
  243. )
  244. {
  245.     char    dataBuf[256];
  246.  
  247.     GetPrivateProfileString(SectionName, EntryName, ""
  248.     , dataBuf, sizeof(dataBuf), ProfileName);
  249.     {
  250.         CStringRecord fields( dataBuf, "," );
  251.         if (fields.GetNumFields() == 2)
  252.         {
  253.             pt.x = atoi(fields[0]);
  254.             pt.y = atoi(fields[1]);
  255.         }
  256.     }
  257. }
  258.  
  259. // ----------------------------------------------------------
  260. // GetColorFromProfile - description
  261. // ----------------------------------------------------------
  262. COLORREF GetColorFromProfile(
  263.     LPSTR    SectionName,
  264.     LPSTR    EntryName,
  265.     LPSTR    ProfileName
  266. )
  267. {
  268.     char    dataBuf[256];
  269.     COLORREF    color=0;
  270.  
  271.     // Initialize text color
  272.     GetPrivateProfileString(SectionName, EntryName, ""
  273.     , dataBuf, sizeof(dataBuf), ProfileName);
  274.     {
  275.         CStringRecord fields( dataBuf, "," );
  276.         if (fields.GetNumFields() == 3)
  277.         {
  278.             color = PALETTERGB(atoi(fields[0])
  279.             , atoi(fields[1]), atoi(fields[2]));
  280.         }
  281.     }
  282.  
  283.     return(color);
  284.  
  285. }
  286.  
  287. /****************************************************************************
  288.  
  289.         FUNCTION:  InitInstance(HINSTANCE, int)
  290.  
  291.         PURPOSE:  Saves instance handle and creates main window
  292.  
  293.         COMMENTS:
  294.  
  295.                 This function is called at initialization time for every instance of
  296.                 this application.  This function performs initialization tasks that
  297.                 cannot be shared by multiple instances.
  298.  
  299.                 In this case, we save the instance handle in a static variable and
  300.                 create and display the main program window.
  301.  
  302. ****************************************************************************/
  303. int loading_stuff = 0;
  304. #ifdef ONLY_ONE_INSTANCE
  305. const char * MutexName = "IklownsMutex";
  306. #endif
  307.  
  308. BOOL InitInstance(
  309.         HINSTANCE          hInstance,
  310.         int             nCmdShow)
  311. {
  312.     WNDCLASS  wc;
  313.  
  314. #ifdef ONLY_ONE_INSTANCE
  315.     // first, check to see if we're the first instance
  316.     hMutex = OpenMutex( SYNCHRONIZE, FALSE, MutexName);
  317.     if (hMutex != 0)
  318.     {
  319.         // we are *not* the first instance!
  320.         CloseHandle(hMutex);
  321.         MessageBox(0, "Only one copy of IKLOWNS can run at a time!", "Immortal Klowns", MB_OK);
  322.         return(FALSE);        
  323.     }
  324.     else
  325.     {
  326.         // doesn't exist - so create it...
  327.         hMutex = CreateMutex(NULL, TRUE, MutexName);
  328.     }
  329. #endif
  330.  
  331.     // Fill in window class structure with parameters that describe the
  332.     // main window.
  333.  
  334.     wc.style         = CS_OWNDC; // Class style(s).
  335.     wc.lpfnWndProc   = (WNDPROC)WndProc;       // Window Procedure
  336.     wc.cbClsExtra    = 0;                      // No per-class extra data.
  337.     wc.cbWndExtra    = 0;                      // No per-window extra data.
  338.     wc.hInstance     = hInstance;              // Owner of this class
  339.     wc.hIcon         = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_APP)); // Icon name from .RC
  340.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);// Cursor
  341.     wc.hbrBackground = NULL;           // Default color
  342.     wc.lpszMenuName  = NULL;
  343.     wc.lpszClassName = szAppName;              // Name to register as
  344.  
  345.     // Register the window class
  346.     if (!RegisterClass(&wc))
  347.         throw CGameException(
  348.                 IDS_STARTUP_ERROR
  349.                );
  350.  
  351.     // Create a main window for this application instance.
  352.     int winx = 0;
  353.     int winy = 0;
  354.     int winw = GetSystemMetrics(SM_CXSCREEN);
  355.     int winh = GetSystemMetrics(SM_CYSCREEN);
  356.  
  357.     ghMainWnd = CreateWindow(
  358.             szAppName,           // See RegisterClass() call.
  359.             szTitle,             // Text for window title bar.
  360.             WS_POPUP,        // Window style.
  361.             winx,
  362.             winy,
  363.             winw,
  364.             winh,
  365.             NULL,                // Overlapped windows have no parent.
  366.             NULL,                // Use the window class menu.
  367.             hInstance,           // This instance owns this window.
  368.             NULL                 // We don't use any data in our WM_CREATE
  369.             );
  370.  
  371.     // If window could not be created, return "failure"
  372.     if (!ghMainWnd)
  373.         throw CGameException(
  374.                 IDS_STARTUP_ERROR
  375.                );
  376.  
  377.     ShowWindow(ghMainWnd, nCmdShow); // Show the window
  378.     UpdateWindow(ghMainWnd);         // Sends WM_PAINT message
  379.  
  380.     char dirBuf[MAX_PATH];
  381.     char dirPath[MAX_PATH];
  382.     char dataPath[MAX_PATH];
  383.     char *p;
  384.     GetModuleFileName(NULL, dirPath, sizeof(dirPath));
  385.     p = strrchr(dirPath, '\\');
  386.     *p = '\0';
  387.  
  388.     lstrcpy(dirBuf, dirPath);
  389.         lstrcat(dirBuf , "\\iklowns.gam" );
  390.  
  391.     GetPrivateProfileString("general", "datapath", ".", dataPath
  392.     , sizeof(dataPath), dirBuf);
  393.  
  394.     lstrcpy(gDataPath, dirPath);
  395.     lstrcat(gDataPath,"\\");
  396.     lstrcat(gDataPath, dataPath);
  397.     SetCurrentDirectory(gDataPath);
  398.  
  399.     Input = new CGameInput;
  400.  
  401.  
  402.     // see if lobby can connect us
  403.     BOOL    bConnected = FALSE;
  404.  
  405.     if (RemoteCreateLobby())
  406.     {
  407.         bConnected = RemoteCreate(IMMORTALKLOWNS_GUID, "Whomever", "KrustyX");
  408.  
  409.         // we are connected, so start multiplayer
  410.         if (bConnected)
  411.             gGameMode = CHOICE_NET;
  412.     }
  413.  
  414.     // let user decide how to connect
  415.     if (!bConnected)
  416.     {
  417.         pOptionScreen = new COptionScreen;
  418.         if ( ! pOptionScreen ) {
  419.             delete Input;
  420.             return( FALSE );
  421.         }
  422.         pOptionScreen->Init(NULL, OPTION_PLAY_START, CHOICE_QUIT+1, NULL
  423.                 , Input, CHOICE_SOLO, FIVE_SECONDS);
  424.         {
  425.             BOOL fReturnToOptionScreen;
  426.  
  427.             do {
  428.                 fReturnToOptionScreen = FALSE;
  429.  
  430.                 gGameMode = pOptionScreen->DoOptionScreen();
  431.  
  432.                 if ((gGameMode == -1) || (gGameMode == CHOICE_QUIT))
  433.                 {
  434.                     pOptionScreen->Shutdown();
  435.                     delete pOptionScreen;
  436.                     delete Input;
  437.                     PostQuitMessage(0); 
  438.                     return (FALSE);
  439.                 }
  440.  
  441.                 if (gGameMode == CHOICE_NET)
  442.                 {
  443.                     if ( ! RemoteCreate(IMMORTALKLOWNS_GUID, "Whomever", "KrustyX") )
  444.                     {
  445.                         fReturnToOptionScreen = TRUE;
  446.                     }
  447.                 }
  448.             } while ( fReturnToOptionScreen );
  449.         }
  450.         pOptionScreen->Shutdown();
  451.         delete pOptionScreen;
  452.         pOptionScreen = NULL;
  453.     }
  454.  
  455.     Timer = new CGameTimer;
  456.  
  457.     gUse_DDraw = (GetPrivateProfileInt("general", "useddraw", 0, dirBuf) == 1);
  458.     gDoubleBuffer = (GetPrivateProfileInt("general", "doublebuffer", 1, dirBuf));
  459.  
  460.     if (gUse_DDraw)
  461.     {
  462.             //
  463.         // temp hack - verify DirectDraw object can be created
  464.         // before we do our construction, and if it cann't we
  465.         // punt to GDI
  466.         //
  467.         LPDIRECTDRAW    pdd;
  468.         HRESULT        result;
  469.         result = DirectDrawCreate( NULL, &pdd, NULL );
  470.         if( result == DD_OK )
  471.         {
  472.             pdd->Release();
  473.             pGameScreen = new CGameDDrawScreen(ghMainWnd, 0, 0);
  474.         }
  475.         else
  476.         {
  477.             gUse_DDraw = 0;
  478.         }
  479.     }
  480.     if (!gUse_DDraw)
  481.     {
  482.         pGameScreen = new CGameDSScreen(ghMainWnd, SCREEN_WIDTH,
  483.                         SCREEN_HEIGHT);
  484.     }
  485.  
  486.     // determine machine capabilities & store in gMachineCaps
  487.     GetMachineCaps();
  488.  
  489.     gSoundMode = GetPrivateProfileInt("general", "SoundMode", 2, dirBuf);
  490.     if( gSoundMode == 0 )
  491.     {
  492.         LPDIRECTSOUND    pds;
  493.         HRESULT        result;
  494.                 result = DirectSoundCreate( NULL, &pds, NULL );
  495.         if( result == 0 )
  496.         {
  497.             pds->Release();
  498.         }
  499.         else
  500.         {
  501.             gSoundMode = 1;
  502.         }
  503.     }
  504.  
  505.  
  506.     {
  507.         char        BitmapFile[MAX_PATH];
  508.         char        MidiFile[MAX_PATH];
  509.         POINT        origin;
  510.         TXTCOLOR    color;
  511.         RECT        rect;
  512.  
  513.         GetPrivateProfileString("LoadingScreens", "Bitmap", "load.bmp"
  514.         , BitmapFile, sizeof(BitmapFile), dirBuf);
  515.  
  516.         color.main = COLOR_RED;
  517.         color.shadow = GetColorFromProfile("LoadingScreens", "DefaultShadow"
  518.         , dirBuf);
  519.         GetPointFromProfile(origin, "LoadingScreens", "HotSpot", dirBuf);
  520.         GetRectFromProfile(rect, "LoadingScreens", "TextRect", dirBuf);
  521.  
  522.         CSoundEffect *pSoundStart = GetSoundFromProfile("LoadingScreens", "SoundStart", dirBuf);
  523.         CSoundEffect *pSoundUpdate = GetSoundFromProfile("LoadingScreens", "SoundUpdate", dirBuf);
  524.         CSoundEffect *pSoundEnd = GetSoundFromProfile("LoadingScreens", "SoundEnd", dirBuf);
  525.  
  526.         GetPrivateProfileString("LoadingScreens", "Music", ""
  527.         , MidiFile, sizeof(MidiFile), dirBuf);
  528.  
  529.         gLoadingScreen = new CLoadingScreen(pGameScreen, BitmapFile, IDS_LOAD_MSG, origin
  530.         , color, rect, pSoundStart, pSoundUpdate, pSoundEnd, MidiFile);
  531.     }
  532.  
  533.     pRumbleLevel = new CGameLevel( dirBuf, "Rumble", Timer, Input, pGameScreen ); 
  534.  
  535.       delete gLoadingScreen;
  536.     gLoadingScreen = NULL;
  537.  
  538.     char MidiFile[255];
  539.     GetPrivateProfileString(pRumbleLevel->GetSectionName(), "Music", "", MidiFile
  540.     , sizeof(MidiFile), dirBuf);
  541.  
  542.     if (gMusicOn)
  543.     {
  544.         playMusic(MidiFile, FALSE);
  545.     }
  546.  
  547.     // prime the animation loop
  548.     PostMessage( ghMainWnd, WPM_ANIMATE, 0, 0 );
  549.  
  550.     return (TRUE);              // We succeeded...
  551. }
  552.  
  553. /****************************************************************************
  554.  
  555.         FUNCTION:  ShutDownApp()
  556.  
  557.         PURPOSE:  un-initialize the app as needed
  558.  
  559.         COMMENTS:
  560.  
  561. ****************************************************************************/
  562. void ShutDownApp()
  563. {
  564.     closeMusic();
  565.  
  566.     SetSilence( TRUE );
  567.     ((CGameDDrawScreen*) pGameScreen)->ShowGDIPage();
  568.  
  569.     delete pRumbleLevel;
  570.     delete pGameScreen;
  571.  
  572.     delete Input;
  573.     delete Timer;
  574.  
  575.     // force redraw of entire screen
  576.     InvalidateRect( HWND_DESKTOP, NULL, TRUE );
  577. }
  578.  
  579. /****************************************************************************
  580.  
  581.         FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
  582.  
  583.         PURPOSE:  Processes messages
  584.  
  585.         MESSAGES:
  586.  
  587.         WM_COMMAND    - application menu (About dialog box)
  588.         WM_DESTROY    - destroy window
  589.  
  590.         COMMENTS:
  591.  
  592.         To process the IDM_ABOUT message, call MakeProcInstance() to get the
  593.         current instance address of the About() function.  Then call Dialog
  594.         box which will create the box according to the information in your
  595.         generic.rc file and turn control over to the About() function.  When
  596.         it returns, free the intance address.
  597.  
  598. ****************************************************************************/
  599.  
  600. LRESULT CALLBACK WndProc(
  601.                 HWND hWnd,         // window handle
  602.                 UINT message,      // type of message
  603.                 WPARAM uParam,     // additional information
  604.                 LPARAM lParam)     // additional information
  605. {
  606.     int wmId, wmEvent;
  607.  
  608.     switch (message) {
  609.     case WM_ACTIVATEAPP:
  610.         gActive = (BOOL)uParam;        
  611.  
  612.         // hook here for min on leaving ...
  613.         if (Timer)
  614.         {
  615.             switch (LOWORD(uParam))
  616.             {
  617.             case WA_INACTIVE:
  618.                 if (pRumbleLevel != NULL)
  619.                 {
  620.                     pRumbleLevel->StopAnimating();
  621.                 }
  622.                 break;
  623.  
  624.             default:
  625.                 if (pGameScreen != NULL)
  626.                 {
  627.                     pGameScreen->Refresh();
  628.                 }
  629.  
  630.                 // restart the animation
  631.                   PostMessage( hWnd, WPM_ANIMATE, 0, 0 );
  632.                 break;
  633.             } 
  634.             return(0);    
  635.         }
  636.         break;
  637.  
  638.     case WM_COMMAND:  // message: command from application menu
  639.  
  640.         wmId    = LOWORD(uParam);
  641.         wmEvent = HIWORD(uParam);
  642.  
  643.         switch (wmId) {
  644.         case IDM_EXIT:
  645.             DestroyWindow (hWnd);
  646.             break;
  647.  
  648.         default:
  649.             return (DefWindowProc(hWnd, message, uParam, lParam));
  650.         }
  651.         break;
  652.  
  653.     case WM_PAINT:
  654.     {
  655.         PAINTSTRUCT ps;
  656.         HDC hdc;
  657.  
  658.         hdc = BeginPaint(hWnd, &ps);
  659.  
  660.         if (gLoadingScreen)
  661.             gLoadingScreen->Paint();
  662.         else if ( pOptionScreen ) {
  663.             pOptionScreen->Paint();
  664.         }
  665.         EndPaint(hWnd, &ps);
  666.         return(0);
  667.         break;
  668.     }
  669.  
  670.     case WM_ERASEBKGND:
  671.         // no need for erasing
  672.         if (pOptionScreen)
  673.             return (DefWindowProc(hWnd, message, uParam, lParam));
  674.         else
  675.             return(1);
  676.  
  677.     case WPM_ANIMATE:
  678.         // won't return til finished with animation
  679.         if (gActive && (pRumbleLevel != NULL))
  680.         {
  681.             // flush input...
  682.             if (Input)
  683.                 Input->Flush();
  684.             pRumbleLevel->Animate( hWnd, pGameScreen );
  685.         }
  686.         return TRUE;
  687.         break;
  688.  
  689.     case WM_DESTROY:  // message: window being destroyed
  690.         closeMusic();
  691.         PostQuitMessage(0);
  692.         break;
  693.  
  694.     default:          // Passes it on if unproccessed
  695.         return (DefWindowProc(hWnd, message, uParam, lParam));
  696.     }
  697.     return (0);
  698. }
  699.  
  700. /*---------------------------------------------------------------------------*\
  701. |
  702. |        UnHandler
  703. |
  704. |  DESCRIPTION:
  705. |        
  706. |
  707. |
  708. \*---------------------------------------------------------------------------*/
  709. #if defined(__BORLANDC__) || defined(__WATCOMC__)
  710. void _cdecl UnHandler(void)
  711. #else
  712. void UnHandler(void)
  713. #endif
  714. {
  715.  
  716.     ShutDownApp();
  717.     MessageBox(
  718.             HWND_DESKTOP,
  719.             "Unhandled exception in Immortal Klowns.",
  720.             "Exception",
  721.             MB_ICONSTOP | MB_OK
  722.             );
  723.     abort();
  724. }
  725.  
  726.  
  727. /*---------------------------------------------------------------------------*\
  728. |
  729. |        GetMachineProfile
  730. |
  731. |  DESCRIPTION:
  732. |        determine various performance parameters for current machine
  733. |
  734. |
  735. \*---------------------------------------------------------------------------*/
  736. void
  737. GetMachineCaps()
  738. {
  739.     // processor type
  740.     SYSTEM_INFO info;
  741.  
  742.     GetSystemInfo( &info );
  743.     switch (info.dwProcessorType)
  744.     {
  745.         case PROCESSOR_INTEL_PENTIUM:
  746.             gMachineCaps.processor = MCP_PENTIUM;
  747.             break;
  748.  
  749.         case PROCESSOR_INTEL_486:
  750.             gMachineCaps.processor = MCP_486;
  751.             break;
  752.  
  753.         case PROCESSOR_INTEL_386:
  754.             gMachineCaps.processor = MCP_386;
  755.             break;
  756.  
  757.         default:
  758.             gMachineCaps.processor = MCP_UNKNOWN;
  759.             break;
  760.     }
  761.  
  762.     // bus type
  763.     HKEY hPCI;
  764.     if (RegOpenKeyEx(
  765.                     HKEY_LOCAL_MACHINE,
  766.                     "Enum\\PCI",
  767.                     0,    // reserved
  768.                     KEY_READ,
  769.                     &hPCI
  770.                     ) == ERROR_SUCCESS)
  771.     {
  772.         gMachineCaps.bus = MCB_PCI;
  773.         RegCloseKey( hPCI );
  774.     }
  775.     else
  776.     {
  777.         gMachineCaps.bus = MCB_ISA;
  778.     }
  779.  
  780.     // system memory
  781.     MEMORYSTATUS memStat;
  782.  
  783.     GlobalMemoryStatus( &memStat );
  784.     gMachineCaps.sysMemory = memStat.dwTotalPhys;
  785.     // video memory & vid system
  786.     if (pGameScreen && (pGameScreen->TypeID() == ST_DDraw))        // info only available through ddraw
  787.     {
  788.         gMachineCaps.vidMemory = ((CGameDDrawScreen*) pGameScreen)->GetVideoMemory();
  789.         if (gMachineCaps.vidMemory != 0)
  790.         {
  791.             gMachineCaps.vidSystem = MCV_DDRAW;
  792.         }
  793.         else
  794.         {
  795.             gMachineCaps.vidSystem = MCV_UNKNOWN;
  796.         }
  797.     }
  798.     else
  799.     {
  800.         gMachineCaps.vidMemory = 0;
  801.         gMachineCaps.vidSystem = MCV_UNKNOWN;
  802.     }
  803. }
  804.