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