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

  1. /*===========================================================================*\
  2. |
  3. |  File:        cglevel.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. #include <windows.h>
  31. #include <linklist.h>
  32.  
  33. #include "cggraph.h"
  34. #include "cglevel.h"
  35. #include "cgtimer.h"
  36. #include "cgchdll.h"
  37. #include "cgchrint.h"
  38. #include "strrec.h"
  39. #include "cginput.h"
  40. #include "cgchar.h"
  41. #include "cgimage.h"
  42. #include "cgmidi.h"
  43. #include "cgremote.h"
  44. #include "cgsound.h"
  45. #include "cgglobl.h"
  46. #include "cgtext.h"
  47. #include "cgrsrce.h"
  48.  
  49. void dbgprintf(char *fmt,...);
  50.  
  51. extern LPSTR NewStringResource(
  52.     HINSTANCE   hInst,
  53.     int     idString
  54. );
  55. extern void GetRectFromProfile(RECT &, LPSTR, LPSTR, LPSTR);
  56.  
  57. extern CGameTimer * Timer;
  58. static RECT WholeScreen = { 0,0,SCREEN_WIDTH,SCREEN_HEIGHT };
  59. HDC LoadBitmapFile (
  60.     LPSTR   pBitmapFile
  61. );
  62. #define BASE_HWND   ghMainWnd
  63.  
  64. /*---------------------------------------------------------------------------*\
  65. |
  66. |       Class CGameLevel
  67. |
  68. |  DESCRIPTION:
  69. |
  70. |
  71. |
  72. \*---------------------------------------------------------------------------*/
  73.  
  74. // this is ONLY for the Klown; it must match the corresponding entry in cgkrusty.cpp
  75. typedef struct
  76. {
  77.     int curState;
  78.     int LastMouseX;
  79.     int LastMouseY;
  80.     DWORD   timeLastUpdate;
  81.     int HitsLeft;
  82.     int pushedState;
  83.     CGameCharacter * myPie;
  84.     int type;           // 0 = main; 1=computer; 2= second;
  85.     int IGotKilled;
  86. } KLOWN_DATA;
  87. extern int gGameMode;
  88. CGameLevel::CGameLevel( 
  89.     char *pFileName,
  90.     TCHAR * pLevelName,
  91.     CGameTimer* pTimer,
  92.     CGameInput* pInput,
  93.     CGameScreen* pScreen
  94.  ) : mpGraphics( NULL ),
  95.     mpTimer( pTimer ),
  96.     mpInput( pInput ),
  97.     mpScreen( pScreen ),
  98.     mOffsetX( 0 ),
  99.     mOffsetY( 0 ),
  100.     mFrameTime( 0 ),
  101.     mpGraphicsKey( NULL ),
  102.     mFastKlown( FALSE ),
  103.     mpProfile( NULL )
  104. {
  105.     char DllList[256];
  106.  
  107.     mMainKlown = NULL;
  108.     // first scan internal table of characters:
  109.     LoadCharInfo( NULL );
  110.     // Grab info from the GAM file; look for character DLLs and load them...
  111.     lstrcpy(DllList, "");
  112.     GetPrivateProfileString("General", "DLLS", "", DllList, 255, pFileName);
  113.     if (strlen(DllList) > 0)
  114.     {
  115.         CStringRecord crec(DllList, ",");
  116.         int x;
  117.         char    dlldir[260];
  118.         char   *p;
  119.  
  120.         lstrcpy( dlldir, pFileName );
  121.         p = strrchr( dlldir, '/' );
  122.         if ( p == NULL )
  123.             p = strrchr( dlldir, '\\' );
  124.         if ( p != NULL )
  125.             lstrcpy( p + 1, "*.dll" );
  126.  
  127.  
  128.         for (x=0; x<crec.GetNumFields(); x++)
  129.         {
  130.             LoadMyDLL(dlldir, crec[x]);
  131.         }
  132.     }
  133.  
  134.     MatchProfile(pFileName);
  135.  
  136.     char prof[256];
  137.  
  138.     GetPrivateProfileString(
  139.             pLevelName,
  140.             mpProfile,
  141.             pLevelName,     // default to level name
  142.             prof,
  143.             sizeof(prof),
  144.             pFileName
  145.             );
  146.  
  147.     pLevName = new char [lstrlen(prof)+1];
  148.     lstrcpy(pLevName, prof);
  149.  
  150.     pFilName = new char [lstrlen(pFileName)+1];
  151.     lstrcpy(pFilName, pFileName);
  152.  
  153.     // Load up any sound effects that are designated as preload.
  154.     char    SoundList[255];
  155.     GetPrivateProfileString(pLevName, "PreloadSounds", "", SoundList, sizeof(SoundList)
  156.     , pFileName);
  157.     if (strlen(SoundList) > 0)
  158.     {
  159.         CStringRecord crec(SoundList, ",");
  160.         for (int x=0; x<crec.GetNumFields(); x++)
  161.         {
  162.             new CSoundEffect(crec[x], 0, FALSE, gSoundMode);
  163.         }
  164.     }
  165.  
  166.     // init
  167.     mMaxWorldX = GetPrivateProfileInt(pLevName, "WorldX", SCREEN_HEIGHT, pFileName) / 2;
  168.     mMaxWorldY = GetPrivateProfileInt(pLevName, "WorldY", SCREEN_WIDTH, pFileName) / 2;
  169.  
  170.     mOffsetX = GetPrivateProfileInt(pLevName, "StartX", 0, pFileName);
  171.     mOffsetY = GetPrivateProfileInt(pLevName, "StartY", 0, pFileName);
  172.  
  173.     // now create the characters as needed
  174.     SetCurrentLevel(this);
  175.  
  176.     {
  177.         
  178.         // set the screen's palette
  179.         char paletteFile[256];
  180.         GetPrivateProfileString(
  181.             pLevName,
  182.             "Palette",
  183.             "",
  184.             paletteFile,
  185.             sizeof( paletteFile ),
  186.             pFileName
  187.             );
  188.         pScreen->SetPalette( paletteFile );
  189.     }   
  190.  
  191.     char graphicsName[256];
  192.     GetPrivateProfileString(
  193.         pLevName,
  194.         "Graphics",
  195.         "",
  196.         graphicsName,
  197.         sizeof( graphicsName ),
  198.         pFileName
  199.         );
  200.  
  201.     // keep a copy of the section name
  202.     mpGraphicsKey = new char[lstrlen(graphicsName)+1];
  203.     lstrcpy( mpGraphicsKey, graphicsName );
  204.  
  205.     mpGraphics = new CGameDisplayList(pFileName, graphicsName, this);
  206.  
  207.     // Add computer opponent(s), second klown, if needed:
  208.     mGameType = gGameMode;
  209.     mNumComputerKlowns =
  210.         mGameType == 0 ?
  211.             1 :
  212.             0 ;
  213.     memset(&mComputerKlowns[0], 0, sizeof(mComputerKlowns));
  214.     GetPrivateProfileString("General", "RoboKlown", "", DllList, sizeof(DllList), pFileName);
  215.     int posx, posy;
  216.     mMainKlown->GetXY(&posx, &posy);
  217.     for (int x=0; x<mNumComputerKlowns; x++)
  218.     {
  219.         // create new klown, computer generated
  220.         mComputerKlowns[x] = new CGameCharacter(pFileName, DllList, graphicsName, this, 
  221.             mMainKlown->GetMinZ(), 
  222.             mMainKlown->GetMaxZ(), posx + mMainKlown->GetCurWidth() * 2, 
  223.             posy, NULL);
  224.  
  225.         if (mComputerKlowns[x])
  226.         {
  227.             mpGraphics->Insert(mComputerKlowns[x]);
  228.             KLOWN_DATA *data = (KLOWN_DATA *) mComputerKlowns[x]->mpPrivateData;
  229.             if (data)
  230.                 data->type = 1; // computer opponent;
  231.         }
  232.     }
  233.  
  234.     // if playing other person on same machine, create opponent;
  235.     if (mGameType == 1)
  236.     {
  237.         // create second klown
  238.         GetPrivateProfileString("General", "SecondKlown", "", DllList, sizeof(DllList), pFileName);
  239.         mSecondKlown = new CGameCharacter(pFileName, DllList, graphicsName, this, 
  240.             mMainKlown->GetMinZ(), 
  241.             mMainKlown->GetMaxZ(), posx + mMainKlown->GetCurWidth() * 2 , posy, NULL);
  242.  
  243.         if (mSecondKlown)
  244.         {
  245.             mpGraphics->Insert(mSecondKlown);
  246.             KLOWN_DATA *data = (KLOWN_DATA *) mSecondKlown->mpPrivateData;
  247.             if (data)
  248.                 data->type = 2; // second (human) opponent;         
  249.         }
  250.  
  251.     }
  252.     else
  253.         mSecondKlown = NULL;
  254.  
  255.     mpUpdateList = new CGameUpdateList;
  256.     mpUpdateList->AddRect(WholeScreen);
  257. }
  258.  
  259. CGameCharacter * CGameLevel::Add (
  260.                 char *name, 
  261.                 int curz, 
  262.                 int curx, 
  263.                 int  cury,
  264.                 void *pNewObjID)
  265. {
  266.     CGameCharacter * newchar;
  267.  
  268.     if (mpGraphics == NULL)
  269.         return(NULL);
  270.  
  271.     newchar = new CGameCharacter(pFilName, name, mpGraphicsKey, this, curz, curz, curx, cury, pNewObjID);
  272.     if (newchar)
  273.     {
  274.         mpGraphics->Insert(newchar);
  275.     }
  276.     return(newchar);    
  277. }
  278.  
  279. CGameLevel::~CGameLevel(  )
  280. {
  281.     delete[] mpProfile;
  282.     delete mpGraphics;
  283.     delete pLevName;
  284.     delete pFilName;
  285.     delete mpGraphicsKey;
  286.     delete mpUpdateList;
  287. }
  288.  
  289. BOOL gameover = FALSE;
  290. BOOL quit = FALSE;
  291. BOOL showing = FALSE;
  292. BOOL showFrameRate = FALSE;
  293. void CGameLevel::GameOver()
  294. {
  295.     gameover = TRUE;
  296. }
  297.  
  298. void
  299. CGameLevel::StopAnimating()
  300. {
  301.     showing = FALSE;
  302. }
  303.  
  304. void    CGameLevel::Animate( 
  305.             HWND hwndParent,
  306.             CGameScreen * pScreen
  307.  )
  308. {
  309.     SetCapture( hwndParent );   // so we get mouse clicks
  310.  
  311.     // turn off the cursor
  312.     HCURSOR hOldCursor = SetCursor( NULL );
  313.  
  314. //  pScreen->SetMode( SCREEN_WIDTH, SCREEN_HEIGHT, 8 );
  315.  
  316.     showing = TRUE;
  317.     MSG     msg;
  318.  
  319.     Timer->Time = timeGetTime(); // * 60 / 1000;
  320.  
  321.     UINT    lastTime = Timer->Time;
  322.     mFrameTime = lastTime;
  323.     UINT elapsed = 0;
  324.  
  325. #define DEBOUNCE_FRAMES 12
  326.     static int debounceF2 = 0;
  327.     static int debounceF3 = 0;
  328.     static int debounceF5 = 0;
  329.     static int debounceF9 = 0;
  330.  
  331. #define FRAMERATE
  332.  
  333. #define SCORE_WIDTH 64
  334. #define SCORE_HEIGHT 64
  335.  
  336.     CGameDSBitBuffer* pScoreFrameBufferLeft;
  337.     CGameDSBitBuffer* pScoreFrameBufferRight;
  338.  
  339.     HDC hdcWindow = GetDC(hwndParent);
  340.     HDC hdcScoreLeft = CreateCompatibleDC(hdcWindow);
  341.     HDC hdcScoreRight = CreateCompatibleDC(hdcWindow);
  342.     ReleaseDC(hwndParent, hdcWindow);
  343.  
  344.     pScoreFrameBufferLeft = new CGameDSBitBuffer( SCORE_WIDTH, SCORE_HEIGHT);
  345.     pScoreFrameBufferRight = new CGameDSBitBuffer( SCORE_WIDTH, SCORE_HEIGHT);
  346.     SelectObject(hdcScoreLeft, pScoreFrameBufferLeft->GetHBitmap());
  347.     SelectObject(hdcScoreRight, pScoreFrameBufferRight->GetHBitmap());
  348.     SetBkMode(hdcScoreLeft, TRANSPARENT);
  349.     SetBkMode(hdcScoreRight, TRANSPARENT);
  350.  
  351.     //    set up  our cool font
  352.     LOGFONT logFont;
  353.     HANDLE hFont;
  354.     memset(&logFont, 0, sizeof(LOGFONT));
  355.     logFont.lfHeight = SCORE_HEIGHT; //maxHeight;
  356.     logFont.lfPitchAndFamily = FF_ROMAN;
  357.     hFont = CreateFontIndirect(&logFont);
  358.     SelectObject(hdcScoreLeft, hFont);
  359.     SetTextColor(hdcScoreLeft, PALETTEINDEX(4));
  360.  
  361.     SelectObject(hdcScoreRight, hFont);
  362.     SetTextColor(hdcScoreRight, PALETTEINDEX(4));
  363.  
  364.     int lastScoreLeft = -1;
  365.     int lastScoreRight = -1;
  366.  
  367. #ifdef FRAMERATE
  368. #define FR_WIDTH 32
  369. #define FR_HEIGHT 32
  370.  
  371.     UINT frames = 0;
  372.     UINT frameTime = timeGetTime();
  373.  
  374.     // create a memory bitmap for our frame text
  375.     CGameDSBitBuffer* pFrameBuffer;
  376.  
  377.     HDC hdc = GetDC( hwndParent );
  378.     HDC hdcFrame = CreateCompatibleDC( hdc );
  379.  
  380.     pFrameBuffer = new CGameDSBitBuffer( FR_WIDTH, FR_HEIGHT);
  381.     SelectObject( hdcFrame, pFrameBuffer->GetHBitmap() );
  382.     //    set up  our cool font
  383.     LOGFONT logFont2;
  384.     HANDLE hFont2;
  385.     memset(&logFont2, 0, sizeof(LOGFONT));
  386.     logFont2.lfHeight = FR_HEIGHT; //maxHeight;
  387.     logFont2.lfPitchAndFamily = FF_ROMAN;
  388.     hFont2 = CreateFontIndirect(&logFont2);
  389.     SelectObject(hdcFrame, hFont2);
  390.     SetTextColor(hdcFrame, COLOR_RED);
  391.     SetBkMode(hdcFrame, TRANSPARENT);
  392.  
  393.     memset(pFrameBuffer->GetBits(), 1, FR_WIDTH * FR_HEIGHT);
  394.     TextOut( hdcFrame, 0,0, "30", 2 );
  395.  
  396.     frames = 0;
  397. #endif // FRAMERATE
  398.  
  399.     Timer->Resume();
  400.     if (gMusicOn)
  401.     {
  402.         resumeMusic();
  403.     }
  404. #ifndef DEBUG
  405.     HANDLE hprocess;
  406.     hprocess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
  407.     SetPriorityClass(hprocess, HIGH_PRIORITY_CLASS );
  408.     CloseHandle(hprocess);
  409. #endif
  410.  
  411.     while ( showing ) {
  412.         Timer->Time = timeGetTime();
  413.         UINT    time = Timer->Time;
  414.  
  415.         if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD ) ) {
  416.             TranslateMessage(&msg);
  417.  
  418.             if ((msg.message == WM_ACTIVATEAPP) &&
  419.                 (LOWORD(msg.wParam) == WA_INACTIVE))
  420.             {
  421.                 showing = FALSE;
  422.                 DispatchMessage(&msg);
  423.                 continue;
  424.             }
  425.             else
  426.                 DispatchMessage(&msg);
  427.         }
  428.  
  429.         if (mpInput->GetKeyboard(VK_ESCAPE) ||
  430.             mpInput->GetKeyboard(VK_F12))
  431.         {
  432.             showing = FALSE;
  433.             if (!mpInput->GetKeyboard(VK_CONTROL))
  434.             {
  435.                 quit = TRUE;
  436.             }
  437.             continue;               
  438.         }
  439.  
  440.         // toggles need to be debounced
  441.         if (mpInput->GetKeyboard(VK_F2) && (debounceF2 == 0))
  442.         {
  443.             // mute!
  444.             gMusicOn = !gMusicOn;
  445.             if (gMusicOn)
  446.             {
  447.                 resumeMusic();
  448.             } else {
  449.                 pauseMusic();
  450.             }
  451.             debounceF2 = DEBOUNCE_FRAMES;
  452.         }
  453.  
  454.         if (debounceF2)
  455.             --debounceF2;
  456.  
  457.         if (mpInput->GetKeyboard(VK_F3) && (debounceF3 == 0))
  458.         {
  459.             extern BOOL gbQuiet;
  460.             SetSilence(!gbQuiet);
  461.             debounceF3 = DEBOUNCE_FRAMES;
  462.         }
  463.         if (debounceF3)
  464.             --debounceF3;
  465.  
  466.         if (mpInput->GetKeyboard(VK_F9) && (debounceF9 == 0)) 
  467.         {
  468.             mFastKlown = !mFastKlown;
  469.             debounceF9 = DEBOUNCE_FRAMES;
  470.         }
  471.  
  472.         if (debounceF9)
  473.             --debounceF9;
  474.  
  475. #ifdef FRAMERATE
  476.         if (mpInput->GetKeyboard(VK_F5) && (debounceF5 == 0)) 
  477.         {
  478.             showFrameRate = !showFrameRate;
  479.             debounceF5 = DEBOUNCE_FRAMES;
  480.         }
  481.  
  482.         if (debounceF5)
  483.             --debounceF5;
  484. #endif
  485.  
  486.         lastTime = time;
  487.  
  488.         // If we are playing a network game, we
  489.         // poll here synchronously for the remote network activity
  490.         {
  491.             extern void PollForRemoteReceive( void );
  492.  
  493.             if ( mGameType > 1 ) {
  494.                 PollForRemoteReceive();
  495.             }
  496.         }
  497.  
  498.         // !!! if we want to limit our framerate, put a check here for elapsed time
  499.         {
  500.             mFrameTime = time;
  501.  
  502.             // let each object update position, get input, etc
  503.             mpGraphics->Update(this, mpUpdateList);
  504.  
  505.             // let each object render its graphical image
  506.             mpGraphics->Render(this, pScreen, mpUpdateList);
  507.             mpUpdateList->Clear();
  508.  
  509.             // get the correct score to show... there is always at least *one*
  510.             KLOWN_DATA * pKlown;
  511.             RECT score_rect;
  512.             char    scorebuf[5];
  513.             pKlown = (KLOWN_DATA *) mMainKlown->mpPrivateData;
  514.  
  515.             score_rect.left = 10;
  516.             score_rect.right = 10+SCORE_WIDTH;
  517.             score_rect.top = 10;
  518.             score_rect.bottom = 10+SCORE_HEIGHT;
  519.             mpUpdateList->AddRect(score_rect);
  520.  
  521.             if (pKlown->HitsLeft != lastScoreLeft)
  522.             {
  523.                 lastScoreLeft = pKlown->HitsLeft;
  524.  
  525.                                 wsprintf(scorebuf, "%d", pKlown->HitsLeft);
  526.  
  527.                 memset(pScoreFrameBufferLeft->GetBits(), 1, SCORE_WIDTH * SCORE_HEIGHT);
  528.  
  529.                 TextOut(hdcScoreLeft, 0, 0, scorebuf, lstrlen(scorebuf));
  530.             }
  531.             pScreen->TransRender(10,10,SCORE_WIDTH, SCORE_HEIGHT,
  532.                 pScoreFrameBufferLeft,0,0);     
  533.  
  534.             switch (mGameType)
  535.             {
  536.                 case 0: // against computer
  537.                     pKlown = (KLOWN_DATA *) mComputerKlowns[0]->mpPrivateData;
  538.                     break;
  539.  
  540.                 case 1:
  541.                     pKlown = (KLOWN_DATA *) mSecondKlown->mpPrivateData;
  542.                     break;
  543.  
  544.                 default:
  545.                     pKlown = NULL;
  546.                     break;
  547.             }
  548.             if (pKlown != NULL) 
  549.             {
  550.                 score_rect.left = SCREEN_WIDTH -10 - SCORE_WIDTH;
  551.                 score_rect.right = SCREEN_WIDTH -10;
  552.                 mpUpdateList->AddRect(score_rect);
  553.  
  554.                 if (pKlown->HitsLeft != lastScoreRight)
  555.                 {
  556.                     lastScoreRight = pKlown->HitsLeft;
  557.                                         wsprintf(scorebuf, "%d", pKlown->HitsLeft);
  558.                     memset(pScoreFrameBufferRight->GetBits(), 1,
  559.                                         SCORE_WIDTH * SCORE_HEIGHT);
  560.                     TextOut(hdcScoreRight, 0, 0, scorebuf, lstrlen(scorebuf));
  561.                 }
  562.                 pScreen->TransRender(SCREEN_WIDTH -10-SCORE_WIDTH,10,
  563.                         SCORE_WIDTH, SCORE_HEIGHT,
  564.                 pScoreFrameBufferRight,0,0);
  565.             }
  566.  
  567. #ifdef FRAMERATE
  568.             if (showFrameRate)
  569.             {
  570.                 ++frames;
  571.                 UINT newTime = timeGetTime();
  572.                 UINT dTime = newTime - frameTime;
  573.                 if (dTime >= 1000 )
  574.                 {
  575.                     char buf[4];
  576.  
  577.                     memset(pFrameBuffer->GetBits(), 1, FR_WIDTH * FR_HEIGHT);
  578.                                         wsprintf(buf, "%d",  frames / (dTime / 1000) );
  579.                     TextOut( hdcFrame, 0,0, buf, lstrlen(buf) );
  580.  
  581.                     frames = 0;
  582.                     frameTime = newTime;
  583.                 }
  584.                 pScreen->TransRender(
  585.                         320 - (FR_WIDTH >> 1),
  586.                         10,
  587.                         FR_WIDTH,
  588.                         FR_HEIGHT,
  589.                         pFrameBuffer,
  590.                         0,
  591.                         0
  592.                         );
  593.             }
  594.             else
  595.             {
  596.                 // keep frametime updated
  597.                 frameTime = time;
  598.             }
  599. #endif // FRAMERATE
  600.  
  601.             // update the screen
  602.             pScreen->PageFlip();
  603.             mpInput->UpdateJoystick();
  604.  
  605.             if (gameover)
  606.             {
  607.                 RECT rect;
  608.                 char tempstring[20];
  609.                 pKlown = (KLOWN_DATA *) mMainKlown->mpPrivateData;
  610.  
  611.                 Sleep(2000);
  612.  
  613.                 GetPrivateProfileString( pLevName, "WinLose", "end.bmp", tempstring, 19, pFilName);
  614.  
  615.                 CGameDIB * myDib = new CGameDIB(tempstring);
  616.                 CGameDSBitBuffer * myBuf = new CGameDSBitBuffer(myDib);
  617.  
  618.                 if (myBuf)
  619.                 {
  620.                     RECT rectdtop;
  621.  
  622.                     HDC hdcWindow = GetDC(hwndParent);
  623.                     HDC hdc = CreateCompatibleDC(hdcWindow);
  624.                     ReleaseDC(hwndParent, hdcWindow);
  625.  
  626.                     rectdtop.left = 0;
  627.                     rectdtop.right = SCREEN_WIDTH;
  628.                     rectdtop.top = 0;
  629.                     rectdtop.bottom = SCREEN_HEIGHT;
  630.                     mpUpdateList->AddRect(rectdtop);
  631.  
  632.                     SelectObject(hdc, myBuf->GetHBitmap());
  633.                     // make the gameover bitmap fill current screen
  634.                     rect = rectdtop;
  635.  
  636.                     CGameText * pCtext = new CGameText (hdc, &rect, 12,1);
  637.  
  638.                     if (pCtext)
  639.                     {
  640.                         int ix, ixend;
  641.                         pKlown = (KLOWN_DATA *) mMainKlown->mpPrivateData;
  642.                         pKlown->curState = 0;
  643.  
  644.                         ix = pKlown->IGotKilled ? IDS_LOSE_START : IDS_WIN_START;
  645.                         ixend = pKlown->IGotKilled ? IDS_LOSE_END : IDS_WIN_END;
  646.                         // load strings...
  647.                         while (ix <= ixend)
  648.                         {
  649.                             char *pChoice = NewStringResource(ghInst, ix);
  650.                             pCtext->AddLine(pChoice, COLOR_YELLOW);
  651.                             ++ix;
  652.                         }
  653.  
  654.                         // Overlay text on bitmap
  655.                         pCtext->TextBlt();
  656.                         delete pCtext;
  657.                     }
  658.  
  659.                     //
  660.                     // Display option screen!
  661.                     pScreen->Render(
  662.                         0,
  663.                         0,
  664.                         SCREEN_WIDTH,
  665.                         SCREEN_HEIGHT,
  666.                         myBuf,
  667.                         0,
  668.                         0,
  669.                         SRCCOPY
  670.                         );
  671.  
  672.                     pScreen->PageFlip();
  673.                     Sleep(5000);
  674.                     pScreen->PageFlip();
  675.                     DeleteDC(hdc);
  676.                     delete myBuf;
  677.                 }
  678.                 delete myDib;
  679.  
  680.                 // reset igotkilled flag...
  681.                 pKlown->IGotKilled = 0;
  682.                 if (mComputerKlowns[0])
  683.                 {
  684.                     pKlown = (KLOWN_DATA *) mComputerKlowns[0]->mpPrivateData;
  685.                     if (pKlown) 
  686.                     {
  687.                         pKlown->curState = 0;                           
  688.                         pKlown->IGotKilled = 0;
  689.                     }
  690.  
  691.                 }
  692.                 if (mSecondKlown)
  693.                 {
  694.                     pKlown = (KLOWN_DATA *) mSecondKlown->mpPrivateData;
  695.                     if (pKlown) 
  696.                     {
  697.                         pKlown->curState = 0;                           
  698.                         pKlown->IGotKilled = 0;
  699.                     }
  700.                 }
  701.  
  702.                 gameover = FALSE;
  703.                 lastScoreLeft = lastScoreRight = -1;
  704.             } // if (gameover)
  705.         } // limit block
  706.     } // while
  707.  
  708.     Timer->Pause();
  709.     SetCursor( hOldCursor );
  710.     ReleaseCapture(  );
  711.  
  712.     if (gMusicOn)
  713.     {
  714.         pauseMusic();
  715.     }
  716. #ifndef DEBUG
  717.     hprocess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
  718.     SetPriorityClass(hprocess, IDLE_PRIORITY_CLASS );
  719.     CloseHandle(hprocess);
  720. #endif
  721.  
  722. #ifdef FRAMERATE
  723.     DeleteDC( hdcFrame );
  724.     DeleteObject(hFont2);
  725.     delete pFrameBuffer;
  726. #endif
  727.  
  728.     DeleteDC( hdcScoreLeft );
  729.     DeleteDC( hdcScoreRight );
  730.  
  731.     DeleteObject(hFont);
  732.     delete pScoreFrameBufferLeft;
  733.     delete pScoreFrameBufferRight;
  734.  
  735.     ReleaseDC( hwndParent, hdc );
  736.  
  737.     if (quit)
  738.         PostQuitMessage(0);
  739. }
  740.  
  741. void CGameLevel::ForceOnScreen(int *x, int *y, int wide, int high, BOOL primary)
  742. {
  743.     // if the x or y coords are off screen:
  744.     // 1) force screen to be there - unless
  745.     // 2) the coords are impossible, then adjust them!
  746.  
  747. #define ROUGH_WIDTH 96
  748.     // keep main char in center of screen
  749.     static RECT center = 
  750.     {
  751.         SCREEN_WIDTH / 4,
  752.         0,
  753.         SCREEN_WIDTH - (SCREEN_WIDTH / 4) - ROUGH_WIDTH,
  754.         SCREEN_HEIGHT
  755.  
  756.     };
  757.  
  758.     if (*x < -mMaxWorldX)
  759.         *x = -mMaxWorldX;
  760.     else
  761.     {
  762.         if (*x > (mMaxWorldX-wide))
  763.             *x = mMaxWorldX-wide;
  764.     }
  765.  
  766.     if (*y < -mMaxWorldY)
  767.         *y = -mMaxWorldY;
  768.     else
  769.     {
  770.         if (*y > (mMaxWorldY-wide))
  771.             *y = mMaxWorldY-wide;
  772.     }
  773.  
  774.     if (primary)
  775.     {
  776.         if ((*x < Screen2WorldX(center.left)) && (mOffsetX > -mMaxWorldX))
  777.         {
  778.             mOffsetX = max(-mMaxWorldX, mOffsetX - (Screen2WorldX(center.left) - *x));
  779.             mpUpdateList->AddRect(WholeScreen);
  780.         }
  781.         else
  782.         {
  783.             if ((*x > Screen2WorldX(center.right)) && (mOffsetX < (mMaxWorldX-SCREEN_WIDTH)))
  784.             {
  785.                 mOffsetX = min((mMaxWorldX-SCREEN_WIDTH), mOffsetX + (*x - Screen2WorldX(center.right)));           
  786.                 mpUpdateList->AddRect(WholeScreen);
  787.             }
  788.         }
  789.  
  790.         if ((*y < Screen2WorldY(center.top)) && (mOffsetY > -mMaxWorldY))
  791.         {       
  792.             mOffsetY = max(-mMaxWorldY, mOffsetY - (Screen2WorldY(center.top) - *y));
  793.             mpUpdateList->AddRect(WholeScreen);
  794.         }
  795.         else
  796.         {
  797.             if ((*y > Screen2WorldY(center.bottom)) && (mOffsetY < (mMaxWorldY-SCREEN_HEIGHT)))
  798.             {           
  799.                 mOffsetY = min((mMaxWorldY-SCREEN_HEIGHT), mOffsetY + (*y - Screen2WorldY(center.bottom)));
  800.                 mpUpdateList->AddRect(WholeScreen);
  801.             }
  802.         }       
  803.     }
  804. }
  805.  
  806. void
  807. CGameLevel::MatchProfile(
  808.     char* pGamFile
  809.     )
  810. {
  811.     static char* pDefault = "Default";
  812.     char profBuf[256];
  813.     char dataBuf[256];
  814.  
  815.     // first check to see if we need to force a given profile
  816.     GetPrivateProfileString(
  817.         "General",
  818.         "ForceProfile",
  819.         "",     // no default
  820.         profBuf,
  821.         sizeof( profBuf ),
  822.         pGamFile
  823.         );
  824.  
  825.     if (lstrlen(profBuf) >0)
  826.     {
  827.          mpProfile = new char[lstrlen(profBuf)+1];
  828.          lstrcpy( mpProfile, profBuf );
  829.     }
  830.     else
  831.     {
  832.         GetPrivateProfileString(
  833.             "Profiles",
  834.             NULL,   // get all
  835.             "",     // no default
  836.             profBuf,
  837.             sizeof( profBuf ),
  838.             pGamFile
  839.             );
  840.  
  841.  
  842.         for (char *pChar = profBuf; *pChar; pChar++)
  843.         {
  844.             GetPrivateProfileString(
  845.                 "Profiles",
  846.                 pChar,
  847.                 "",
  848.                 dataBuf,
  849.                 sizeof( dataBuf ),
  850.                 pGamFile
  851.                 );
  852.  
  853.             // parse the data string into fields
  854.             CStringRecord fields( dataBuf, "," );
  855.  
  856.             MC_PROCESSOR processor = (MC_PROCESSOR) atoi(fields[0]);
  857.             MC_BUSTYPE bus = (MC_BUSTYPE) atoi(fields[1]);
  858.  
  859.             // memory fields are in megabytes
  860.             DWORD sysMem = atoi(fields[2]) * 1024 * 1024;
  861.             DWORD vidMem = atoi(fields[3]) * 1024 * 1024;
  862.  
  863.             MC_VIDSYS vidSys = (MC_VIDSYS) atoi(fields[4]);
  864.  
  865.             if ((gMachineCaps.processor >= processor) &&
  866.                 (gMachineCaps.bus >= bus) &&
  867.                 (gMachineCaps.sysMemory >= sysMem) &&
  868.                 (gMachineCaps.vidMemory >= vidMem) &&
  869.                 (gMachineCaps.vidSystem >= vidSys))
  870.             {
  871.                 mpProfile = new char[lstrlen(pChar)+1];
  872.                 lstrcpy( mpProfile, pChar );
  873.                 break;
  874.             }
  875.  
  876.             pChar += lstrlen( pChar );  // move beyond terminator
  877.         }
  878.  
  879.         // if we didn't find it, use default
  880.         if (mpProfile == NULL)
  881.         {
  882.             mpProfile = new char[lstrlen(pDefault)+1];
  883.             lstrcpy( mpProfile, pDefault );
  884.         }
  885.     }
  886. }
  887.