DUEL.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:15k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  4.  *
  5.  *  File:       duel.c
  6.  *  Content:    Multi-player duel
  7.  *
  8.  *
  9.  ***************************************************************************/
  10. #define INITGUID
  11. #include "duel.h"
  12. #include "gameproc.h"
  13. #include "gfx.h"
  14. #include "comm.h"
  15. #include "input.h"
  16. #include "lobby.h"
  17. #include "wizard.h"
  18. #include "util.h"
  19. #include "sfx.h"
  20. // {33925241-05F8-11d0-8063-00A0C90AE891}
  21. DEFINE_GUID(DUEL_GUID, 
  22. 0x33925241, 0x5f8, 0x11d0, 0x80, 0x63, 0x0, 0xa0, 0xc9, 0xa, 0xe8, 0x91);
  23. /*
  24.  * Externals
  25.  */
  26. extern DWORD gdwFrameCount;
  27. extern DWORD gdwFrameTime;
  28. extern int gnProgramState;
  29. extern SHIP gOurShip;
  30. extern LPDPLCONNECTION glpdplConnection;
  31. extern DPID gOurID;
  32. extern BOOL             gbNoField;
  33. /*
  34.  * Globals
  35.  */
  36. LPGUID                  glpGuid; // Duel's GUID
  37. HWND                    ghWndMain; // Main application window handle
  38. HINSTANCE ghinst; // Application instance handle
  39. BOOL                    gbShowFrameCount=TRUE; // Show FPS ?
  40. BOOL                    gbIsActive; // Is the application active ?
  41. BOOL                    gbUseEmulation; // DDHEL or DDHAL for Graphics
  42. BOOL gbIsHost; // Are we hosting or joining a game
  43. DWORD                   gdwKeys; // User keyboard input
  44. DWORD                   gdwOldKeys;             // Last frame's keyboard input
  45. BOOL gbFullscreen=FALSE; // Window or FullScreen mode ?
  46. RECT grcWindow; // client rectangle of main window
  47. HANDLE ghThread; // handle to wizard thread
  48. TCHAR gtszClassName[MAX_CLASSNAME]; // Duel's class name
  49. BOOL                    gbReliable;             // sends are reliable
  50. /*
  51.  * Statics
  52.  */
  53. static BOOL gbReinitialize; // used for switching display modes
  54. /*
  55.  * WinMain
  56.  */
  57. int WINAPI WinMain( HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
  58.                         int nCmdShow )
  59. {
  60. BOOL bHelp=FALSE;
  61.     MSG     msg;
  62. ghinst = hinstance;
  63. CoInitialize( NULL );
  64. // Parse command line
  65.     while( lpCmdLine[0] == '-' )
  66.     {
  67.         lpCmdLine++;
  68.         switch (*lpCmdLine++)
  69.         {
  70.         case 'e':
  71.             gbUseEmulation = TRUE;
  72.             break;
  73.         case 'd':
  74.             gbNoField = TRUE;
  75.             break;
  76.         case '?':
  77. default:
  78.             bHelp= TRUE;
  79.             gbFullscreen= FALSE;  // give help in windowed mode
  80.             break;
  81.         }
  82.         while( isspace(*lpCmdLine) )
  83. {
  84. lpCmdLine++;
  85. }
  86.     }
  87.     /*
  88.      * Give user help if asked for
  89.      */
  90.     if( bHelp )
  91.     {
  92. TCHAR tszHelpMsg[MAX_HELPMSG];
  93. TCHAR tszTitle[MAX_WINDOWTITLE];
  94. LoadString(ghinst, IDS_DUEL_HELP, tszHelpMsg, MAX_HELPMSG);
  95. LoadString(ghinst, IDS_DUEL_TITLE, tszTitle, MAX_WINDOWTITLE);
  96.         MessageBox(ghWndMain, tszHelpMsg, tszTitle, MB_OK );
  97. return TRUE;
  98.     }
  99.     if( !InitApplication(hinstance) )
  100.     {
  101.         return FALSE;
  102.     }
  103. // were we launched by a lobby ?
  104.     if (LaunchedByLobby())
  105.     {
  106. // start game
  107. PostMessage(ghWndMain, UM_LAUNCH, 0, 0);
  108.         gbIsActive = TRUE;
  109.     }
  110.     gdwFrameTime = timeGetTime();
  111. while( TRUE )
  112.     {
  113.         if (gbIsActive)
  114.         {
  115.             // any windows messages ? (returns immediately)
  116.             if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  117.             {
  118.                 if( !GetMessage( &msg, NULL, 0, 0 ) )
  119.                 {
  120.                     return msg.wParam;
  121.                 }
  122.                 TranslateMessage(&msg);
  123.                 DispatchMessage(&msg);
  124.             }
  125.             else
  126.             {
  127.                 // Poll our receive queue. Polling is used in the sample only for simplicity.
  128.                 // Receiving messages using an event is the recommended way.
  129.         if (gnProgramState != PS_SPLASH)
  130.                 {
  131.                     ReceiveMessages();
  132.                 }
  133.                 // update screen
  134.      if (!UpdateFrame())
  135.                 {
  136.                     ExitGame();
  137.                 }
  138.     }
  139.         }
  140.         else
  141.         {
  142.             // any windows messages ? (blocks until a message arrives)
  143.             if( !GetMessage( &msg, NULL, 0, 0 ) )
  144.             {
  145.                 return msg.wParam;
  146.             }
  147.             TranslateMessage(&msg);
  148.             DispatchMessage(&msg);
  149.         }
  150.     }
  151. CoUninitialize();
  152. } /* WinMain */
  153. /*
  154.  * MainWndproc
  155.  *
  156.  * Callback for all Windows messages
  157.  */
  158. long WINAPI MainWndproc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  159. {
  160.     PAINTSTRUCT ps;
  161.     HDC         hdc;
  162. DWORD dwRetCode;
  163. DWORD dwTid;
  164.     switch( message )
  165.     {
  166.     case WM_SIZE:
  167.     case WM_MOVE:
  168. // get the client rectangle
  169.         if (gbFullscreen)
  170.         {
  171.             SetRect(&grcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
  172.         }
  173.         else
  174.         {
  175.             GetClientRect(hWnd, &grcWindow);
  176.             ClientToScreen(hWnd, (LPPOINT)&grcWindow);
  177.             ClientToScreen(hWnd, (LPPOINT)&grcWindow+1);
  178.         }
  179. break;
  180.     case WM_ACTIVATE:
  181. // ignore this message during reinitializing graphics
  182. if (gbReinitialize) return 0;
  183.         // When we are deactivated, although we don't update our screen, we still need to
  184.         // to empty our receive queue periodically as messages will pile up otherwise. 
  185.         // Polling the receive queue continuously even when we are deactivated causes our app
  186.         // to consume all the CPU time. To avoid hogging the CPU, we block on GetMessage() WIN API
  187.         // and setup a timer to wake ourselves up at regular intervals to process our messages.
  188.         if (LOWORD(wParam) == WA_INACTIVE)
  189.         {
  190.             // deactivated
  191.             gbIsActive = FALSE;
  192.             if (PS_ACTIVE == gnProgramState)
  193.             {
  194.                 SetTimer(hWnd, RECEIVE_TIMER_ID, RECEIVE_TIMEOUT, NULL);
  195.             }
  196.         }
  197.         else
  198.         {
  199.             // activated
  200.             gbIsActive = TRUE;
  201.             if (PS_ACTIVE == gnProgramState)
  202.             {
  203.                 KillTimer(hWnd, RECEIVE_TIMER_ID);
  204.             }
  205.         }
  206.         // set game palette, if activated in game mode
  207.         if (gbIsActive && (gnProgramState != PS_SPLASH))
  208. SetGamePalette();
  209.         ReacquireInputDevices();
  210.         return 0;
  211.     case WM_CREATE:
  212.         break;
  213.     case WM_SYSKEYUP:
  214. switch( wParam )
  215.         {
  216.         // handle ALT+ENTER (fullscreen/window mode)
  217.         case VK_RETURN:
  218. // mode switch is allowed only during the game
  219. if (gnProgramState == PS_ACTIVE)
  220. {
  221. gbReinitialize = TRUE;
  222.                 ReleaseLocalData();  //only sound buffers have to be rels'd anyway.
  223.                 CleanupSfx();
  224.                 CleanupInput();
  225. CleanupGraphics();
  226. DestroyWindow(ghWndMain);
  227. gbFullscreen = !gbFullscreen;
  228. InitGraphics();
  229.                 InitInput();
  230.                 InitSfx();
  231.                 InitLocalSoundData();
  232. gbReinitialize = FALSE;
  233.             }
  234.             break;
  235.         }
  236.         break;
  237.     case WM_KEYDOWN:
  238.         switch( wParam )
  239.         {
  240.         case 'r':
  241.         case 'R':
  242. // toggle reliable status
  243. gbReliable = !gbReliable;
  244. UpdateTitle();
  245.             break;
  246. case VK_F1:
  247. {
  248. TCHAR tszHelpMsg[MAX_HELPMSG];
  249. TCHAR tszTitle[MAX_WINDOWTITLE];
  250. LoadString(ghinst, IDS_DUEL_HELP, tszHelpMsg, MAX_HELPMSG);
  251. LoadString(ghinst, IDS_DUEL_TITLE, tszTitle, MAX_WINDOWTITLE);
  252. MessageBox(ghWndMain, tszHelpMsg, tszTitle, MB_OK );
  253. }
  254. break;
  255.         case VK_F5:
  256.             gbShowFrameCount = !gbShowFrameCount;
  257.             if( gbShowFrameCount )
  258.             {
  259.                 gdwFrameCount = 0;
  260.                 gdwFrameTime = timeGetTime();
  261.             }
  262.             break;
  263.         case VK_RETURN:
  264.             if( (gnProgramState == PS_SPLASH) && !gbFullscreen)
  265. {
  266. // get connection settings from user
  267. ghThread = CreateThread(NULL, 0, (LPVOID)DoWizard, 0, 0, &dwTid);
  268. }
  269.             break;
  270.         case VK_ESCAPE:
  271.         case VK_F12:
  272. // adios
  273. ExitGame();
  274.             return 0;
  275.         }
  276.         break;
  277.     case WM_ERASEBKGND:
  278.      return 1;
  279.     case WM_PAINT:
  280.         hdc = BeginPaint( hWnd, &ps );
  281. if (gnProgramState == PS_SPLASH)
  282. {
  283.             // display the splash screen
  284.             bltSplash(NULL);
  285. }
  286.         EndPaint( hWnd, &ps );
  287.         return 1;
  288. case UM_LAUNCH:
  289. // cleanup the wizard thread
  290. if (ghThread)
  291. {
  292. // wait for thread to exit
  293. while (!GetExitCodeThread(ghThread, &dwRetCode));
  294. CloseHandle(ghThread);
  295. }
  296. // start the game in rest mode
  297. gnProgramState = PS_REST;
  298. LaunchGame();
  299. return 1;
  300. case UM_ABORT:
  301. // cleanup the wizard thread
  302. if (ghThread)
  303. {
  304. // wait for thread to exit
  305. while (!GetExitCodeThread(ghThread, &dwRetCode));
  306. CloseHandle(ghThread);
  307. }
  308.         ExitGame();
  309. return 1;
  310.     case WM_TIMER:
  311.         ReceiveMessages();
  312.         break;
  313.     case WM_DESTROY:
  314. // if gbReinitialize is TRUE don't quit, we are just switching display modes
  315. if (!gbReinitialize)
  316. {
  317. CleanupApplication();
  318.         PostQuitMessage( 0 );
  319. }
  320.         return 0;
  321.     default:
  322.         break;
  323.     }
  324.     return DefWindowProc(hWnd, message, wParam, lParam);
  325. } /* MainWndproc */
  326. /*
  327.  * InitApplication
  328.  *
  329.  * Do that initialization stuff...
  330.  */
  331. BOOL InitApplication( HINSTANCE hinst )
  332. {
  333.     WNDCLASS    wc;
  334.     BOOL        rc;
  335.     glpGuid = (LPGUID) &DUEL_GUID;
  336. LoadString(ghinst, IDS_DUEL_CLASSNAME, gtszClassName, MAX_CLASSNAME);
  337.     wc.style = CS_DBLCLKS;
  338.     wc.lpfnWndProc = MainWndproc;
  339.     wc.cbClsExtra = 0;
  340.     wc.cbWndExtra = 0;
  341.     wc.hInstance = hinst;
  342.     wc.hIcon = LoadIcon( hinst, MAKEINTRESOURCE(DUEL_ICON));
  343.     wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  344.     wc.hbrBackground = GetStockObject( BLACK_BRUSH );
  345.     wc.lpszMenuName =  NULL;
  346.     wc.lpszClassName = gtszClassName;
  347.     rc = RegisterClass( &wc );
  348.     if( !rc )
  349.     {
  350.         return FALSE;
  351.     }
  352. // Initialize all components
  353. if ((!InitGraphics()) || (!InitInput()) || (!InitSfx()))
  354. {
  355. return FALSE;
  356. }
  357. // start in splash mode
  358.     gnProgramState = PS_SPLASH;
  359.     return TRUE;
  360. } /* initApplication */
  361. /*
  362.  * CleanupApplication
  363.  *
  364.  * Calls clean up on all components
  365.  */
  366. void CleanupApplication( void )
  367. {
  368. CleanupComm();
  369.     CleanupSfx();
  370. CleanupGraphics();
  371. CleanupInput();
  372. }
  373. /*
  374.  * LaunchedByLobby
  375.  *
  376.  * Determines if we were launched by a lobby. If so, gets the connection settings
  377.  * and creates our player using the information from the lobby
  378.  */
  379. BOOL LaunchedByLobby(void)
  380. {
  381.     HRESULT hr;
  382.     HWND    hwndStatus;
  383.     // create a lobby object
  384.     hr = DPLobbyCreate();
  385.     if (FAILED(hr))
  386.     {
  387.         ShowError(IDS_DPLOBBY_ERROR_C);
  388.         return FALSE;
  389.     }
  390.     // get connection settings from the lobby (into glpdplConnection)
  391.     hr = DPLobbyGetConnectionSettings();
  392.     if (FAILED(hr))
  393.     {
  394.         if (DPERR_NOTLOBBIED == hr)
  395.         {
  396.             // we were not lobbied - start up game normally
  397.             hr = DPLobbyRelease();
  398.             if (FAILED(hr))
  399.             {
  400.                 ShowError(IDS_DPLOBBY_ERROR_R);
  401.                 goto FAIL;
  402.             }
  403.             // move on
  404.             return FALSE;
  405.         }
  406.         else
  407.         {
  408.             ShowError(IDS_DPLOBBY_ERROR_GCS);
  409.             goto FAIL;
  410.         }
  411.     }
  412. // are we hosting or joining ?
  413. if (glpdplConnection->dwFlags & DPLCONNECTION_CREATESESSION)
  414. {
  415. gbIsHost = TRUE;
  416. }
  417.     // set our session flags
  418.     glpdplConnection->lpSessionDesc->dwFlags = DPSESSION_MIGRATEHOST | 
  419.                                                  DPSESSION_KEEPALIVE;
  420.     // let lobby know our connection flags
  421.     hr = DPLobbySetConnectionSettings();
  422.     if (FAILED(hr))
  423.     {
  424.         ShowError(IDS_DPLOBBY_ERROR_SCS);
  425.         goto FAIL;
  426.     }
  427.     if ( !gbIsHost ) 
  428.     {
  429.         // show splash screen and 
  430.         // connection status if we are joining a game
  431.         UpdateWindow(ghWndMain);
  432.         hwndStatus = ShowConnectStatus();
  433.     }
  434.     else
  435.     {
  436.         // we are hosting, don't need connection status
  437.         hwndStatus = NULL;
  438.     }
  439.     // connect to the lobby
  440.     hr = DPLobbyConnect();
  441.     if ( hwndStatus )
  442.     {
  443.         // get rid of the connectino status window
  444.         DestroyWindow(hwndStatus);
  445.     }
  446.     if (FAILED(hr))
  447.     {
  448.         ShowError(IDS_DPLOBBY_ERROR_CONNECT);
  449.         goto FAIL;
  450.     }
  451.     // create our player
  452.     hr = DPlayCreatePlayer(
  453.                             &gOurID,
  454. #ifdef UNICODE
  455. glpdplConnection->lpPlayerName->lpszShortName,
  456. #else
  457. glpdplConnection->lpPlayerName->lpszShortNameA,
  458. #endif
  459. NULL,
  460. NULL,
  461. 0
  462.                           );
  463.     if (FAILED(hr))
  464.     {
  465. ShowError(IDS_DPLAY_ERROR_CP);
  466.         goto FAIL;
  467.     }
  468.     // cleanup
  469.     hr = DPLobbyRelease();
  470.     if (FAILED(hr))
  471.     {
  472.         ShowError(IDS_DPLOBBY_ERROR_R);
  473.         goto FAIL;
  474.     }
  475.     // we were lobbied
  476.     return TRUE;
  477. FAIL:
  478. // cleanup and exit
  479. DPLobbyRelease();
  480.     ExitGame();
  481.     return FALSE;
  482. }
  483. /*
  484.  * Displays error to the user
  485.  */
  486. BOOL ShowError( int iStrID )
  487. {
  488. TCHAR tszMsg[MAX_ERRORMSG];
  489. TCHAR tszTitle[MAX_WINDOWTITLE];
  490. LoadString(ghinst, iStrID, tszMsg, MAX_ERRORMSG);
  491. LoadString(ghinst, IDS_DUEL_ERROR_TITLE, tszTitle, MAX_WINDOWTITLE);
  492.     MessageBox( ghWndMain, tszMsg, tszTitle, MB_OK );
  493.     return FALSE;
  494. }
  495. /*
  496.  * Displays connection status to the user
  497.  */
  498. HWND ShowConnectStatus(void)
  499. {
  500.     HWND hwnd;
  501.     hwnd = CreateDialog( ghinst, MAKEINTRESOURCE(IDD_CONNECT_STATUS), ghWndMain, NULL);
  502.     return hwnd;
  503. }
  504. /*
  505.  * UpdateTitle
  506.  *
  507.  * Updates the window title based on application status
  508.  */
  509. void UpdateTitle(void)
  510. {
  511. DWORD dwFeatures;
  512.    TCHAR tszTitle[MAX_WINDOWTITLE];
  513. UINT iStringID;
  514. // calculate title features
  515. dwFeatures = 0;
  516. if (gbReliable)
  517. dwFeatures |= 1;
  518. if (gbIsHost)
  519. dwFeatures |= 2;
  520. switch (dwFeatures)
  521. {
  522. case 0:
  523. iStringID = IDS_DUEL_TITLE;
  524. break;
  525. case 1:
  526. iStringID = IDS_DUEL_RELIABLE_TITLE;
  527. break;
  528. case 2:
  529. iStringID = IDS_DUEL_HOST_TITLE;
  530. break;
  531. case 3:
  532. iStringID = IDS_DUEL_HOST_RELIABLE_TITLE;
  533. break;
  534. }
  535. // get appropriate window title for these features
  536. LoadString(ghinst, iStringID, tszTitle, MAX_WINDOWTITLE);
  537.     // change window title
  538.     SetWindowText(ghWndMain, tszTitle);               
  539. }