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

  1. /*===========================================================================*\
  2. |
  3. |  File:        cgremote.cpp
  4. |
  5. |  Description:
  6. |   Routines to send and receive remote actions for controlling objects
  7. |   on remote machines.  Uses DirectPlay for transferring data.
  8. |       
  9. |-----------------------------------------------------------------------------
  10. |
  11. |  Copyright (C) 1995-1996 Microsoft Corporation.  All Rights Reserved.
  12. |
  13. |  Written by Moss Bay Engineering, Inc. under contract to Microsoft Corporation
  14. |
  15. \*===========================================================================*/
  16.  
  17. /**************************************************************************
  18.  
  19.     (C) Copyright 1995-1996 Microsoft Corp.  All rights reserved.
  20.  
  21.     You have a royalty-free right to use, modify, reproduce and 
  22.     distribute the Sample Files (and/or any modified version) in 
  23.     any way you find useful, provided that you agree that 
  24.     Microsoft has no warranty obligations or liability for any 
  25.     Sample Application Files which are modified. 
  26.  
  27.     we do not recomend you base your game on IKlowns, start with one of
  28.     the other simpler sample apps in the GDK
  29.  
  30.  **************************************************************************/
  31.  
  32. //** include files **
  33. #include <stdlib.h>
  34. #ifndef __WATCOMC__
  35. #define WIN32_LEAN_AND_MEAN
  36. #endif
  37. #include <windows.h>
  38. #include <windowsx.h>
  39. #include <mmsystem.h>
  40. #include "cgglobl.h" // For ghInst for dialog box
  41. #include "cgrsrce.h"
  42. #include "dplay.h"
  43. #include "dplobby.h"
  44. #include "cglevel.h"
  45. #include "cgremote.h"
  46. #include "strrec.h"
  47.  
  48. #include <stdarg.h>
  49. #include <stdio.h>
  50.  
  51. static void InitReceivePoll( void );
  52.  
  53. // [johnhall]
  54. // hack -- get GENERIC_CHAR_INFO from cgkrusty.cpp
  55. typedef signed char SCHAR;
  56.  
  57. typedef struct 
  58. {
  59.     LONG    posx;
  60.     LONG    posy;
  61.     SCHAR   state;
  62.     SCHAR   velx;
  63.     SCHAR   vely;
  64.     SCHAR   curZ;
  65. } GENERIC_CHAR_INFO;
  66.  
  67. //** local definitions **
  68. // structure to be used to pass remote actions across the link
  69. typedef struct _GAMEMESSAGE {
  70.     BYTE                    Action;     // action code
  71.     BYTE            NumBytes;   // size of data 
  72.     REMOTE_OBJECT       RemObj;     // unique object id
  73.     char            Data[1];    // action specific data
  74. } GAMEMESSAGE, *PGAMEMESSAGE;
  75.  
  76.  
  77. //** external functions **
  78.  
  79. //** external data **
  80. // KLUDGE:
  81. CGameLevel  *gCurLevel=NULL;
  82.  
  83. //** public data **
  84. //** private data **
  85. static  IDirectPlay *lpIDC=NULL;    // DirectPlay Object
  86. static  DPID    dcoID=0;        // our DirectPlay ID
  87. static  HANDLE  dphEvent = NULL;
  88.  
  89. static BOOL fAbort = FALSE; // Abort flag for RemoteConnect()
  90.  
  91. //** public functions **
  92. //** private functions **
  93. static DWORD RequestThreadProc(void *Dummy);
  94. static BOOL CALLBACK AbortDlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  95.  
  96.  
  97. #define DP_BROADCAST_ID  0
  98.  
  99. // ----------------------------------------------------------
  100. // CreateRemotePeer - create a new character across all peers
  101. // ----------------------------------------------------------
  102. REMOTE_OBJECT *CreateRemotePeers(
  103.     char    *name,      // name of object as per level->Add() 
  104.     DWORD   InstanceID  // unique instance ID of object type
  105. )
  106. {
  107.     // Gotta have a DCO object to do this!
  108.     if (lpIDC == NULL)
  109.     {
  110.         return(NULL);
  111.     }
  112.  
  113.     // Setup a message and an unique obect id
  114.     char *pBuffer = NULL;
  115.     DWORD lenBuff;
  116.     PGAMEMESSAGE    pGameMsg;
  117.     REMOTE_OBJECT *pObj = new REMOTE_OBJECT;
  118.     memset(pObj, 0, sizeof(REMOTE_OBJECT));
  119.  
  120.     // Make buffer big enough to hold game message plus
  121.     // leading non-system-char byte
  122.     lenBuff = sizeof(GAMEMESSAGE);
  123.     pBuffer = new char[lenBuff];
  124.     pGameMsg = (PGAMEMESSAGE)&pBuffer[0];
  125.  
  126.     // Fill in object id info so that this object is unique across
  127.     // all machines
  128.     pObj->OwnerID = (BYTE) dcoID;
  129.     pObj->InstanceID = (BYTE) InstanceID;
  130.     lstrcpyn(pObj->ObjectID, name, MAX_OBJ_NAME);
  131.     memcpy(&pGameMsg->RemObj, pObj, sizeof(REMOTE_OBJECT));
  132.  
  133.     pGameMsg->Action = (BYTE) CREATE_OBJECT;
  134.  
  135.     // Broadcast it to everyone in the group.
  136.     lpIDC->Send( dcoID,  // From
  137.                  DP_BROADCAST_ID,
  138.                  0,
  139.                  (LPSTR)pBuffer,
  140.                  lenBuff);  
  141.  
  142.     // Delete buffer, once sent
  143.     delete []pBuffer;
  144.  
  145.     return(pObj);
  146. }   
  147.  
  148.  
  149.  
  150.  
  151.  
  152. // ----------------------------------------------------------
  153. // SendRemoteAction - broadcast an action to remote peers
  154. // ----------------------------------------------------------
  155. BOOL SendRemoteAction(
  156.     REMOTE_OBJECT   *pObj,      // unique object id
  157.     ACTION      Action,     // action code 
  158.     void        *Data,      // action data
  159.     DWORD       nDataSize   // size of action data
  160. )
  161. {
  162.     PGAMEMESSAGE    gameMsg;
  163.     char *pBuffer;
  164.     DWORD lenBuff;
  165.       //   char chBuffer[128];
  166.  
  167.  
  168.  
  169.     // Gotta have a valid DirectPlay object
  170.     if (lpIDC == NULL)
  171.     {
  172.         return(NULL);
  173.     }
  174.  
  175.     // Allocate the GAME buffer with room for data,
  176.     // plus room at the beginning for a non-sytem-message char
  177.     lenBuff = sizeof(GAMEMESSAGE) + nDataSize; 
  178.     pBuffer = new char [lenBuff]; 
  179.     // Now point gameMsg at the rest of the buffer
  180.     gameMsg = (PGAMEMESSAGE)&pBuffer[0];
  181.  
  182.     // Copy the action code and data to message buffer
  183.     gameMsg->Action = Action;
  184.     memcpy(&gameMsg->RemObj, pObj, sizeof(REMOTE_OBJECT));
  185.     gameMsg->NumBytes = (BYTE) nDataSize;
  186.     memcpy(gameMsg->Data, Data, nDataSize);
  187. #if 0
  188.         wsprintf( chBuffer, "%d (10%s) %d %d %d",
  189.             gameMsg->Action,
  190.             gameMsg->RemObj.ObjectID,
  191.             gameMsg->RemObj.InstanceID,
  192.             gameMsg->RemObj.OwnerID,
  193.             gameMsg->NumBytes);
  194.         OutputDebugString(chBuffer);
  195.         if (nDataSize == sizeof(GENERIC_CHAR_INFO))
  196.         {
  197.             GENERIC_CHAR_INFO *pci;
  198.             pci = (GENERIC_CHAR_INFO *) Data;
  199.             wsprintf( chBuffer,"; %d %d %d %d %d %d",
  200.                 pci->state,
  201.                 pci->posx,
  202.                 pci->posy,
  203.                 pci->velx,
  204.                 pci->vely,
  205.                 pci->curZ);
  206.             OutputDebugString(chBuffer);
  207.         }
  208.         OutputDebugString("\r\n");
  209. #endif
  210.  
  211.     // Broadcast the action to all peers
  212.     lpIDC->Send(dcoID, // from
  213.                 DP_BROADCAST_ID, // to
  214.                 0,
  215.                 pBuffer,
  216.                 lenBuff);   
  217.     delete []pBuffer;
  218.     return(TRUE);
  219. }   
  220.  
  221. // ----------------------------------------------------------
  222. // DestroyRemotePeer - Tell remote peers to kill an object
  223. // ----------------------------------------------------------
  224. BOOL DestroyRemotePeer(
  225.     REMOTE_OBJECT *pObj     // unique object id
  226. )
  227. {
  228.     PGAMEMESSAGE    gameMsg;
  229.     char *pBuffer = NULL;
  230.     DWORD lenBuff;
  231.  
  232.     if (pObj == NULL)
  233.         return(TRUE);
  234.  
  235.     // Allocate a buffer for the GAME buffer with roon for data,
  236.     // plus an extra character at the beginning to be the non-system
  237.     // message char.
  238.     lenBuff = sizeof(GAMEMESSAGE)+1; 
  239.     pBuffer = new char [lenBuff];
  240.  
  241.     // Point the game message pointer at the rest of the buffer
  242.     gameMsg = (PGAMEMESSAGE)&pBuffer[0];
  243.  
  244.     // Format a destroy message
  245.     memcpy(&gameMsg->RemObj, pObj, sizeof(REMOTE_OBJECT));
  246.     gameMsg->RemObj.OwnerID = (BYTE) dcoID;
  247.     gameMsg->NumBytes = 0;
  248.     gameMsg->Action = (BYTE) DESTROY_OBJECT;
  249.  
  250.     // Broadcast the destroy message to all peers
  251.     lpIDC->Send( dcoID, 
  252.                  DP_BROADCAST_ID,
  253.                  0,
  254.                  pBuffer,
  255.                  lenBuff);  
  256.     // Delete buffer
  257.     delete []pBuffer;
  258.  
  259.     // Don't need the object id anymore
  260.     delete pObj;
  261.     return(TRUE);
  262. }   
  263.  
  264. // -----------------------------------------------------------------
  265. // RemoteConnect - establish an active connection with remotes
  266. // -----------------------------------------------------------------
  267.  
  268. BOOL FAR PASCAL EnumSession(
  269.         LPDPSESSIONDESC lpDPGameDesc,
  270.         LPVOID pContext,
  271.         LPDWORD pTimeOut,
  272.         DWORD dwFlags )
  273. {
  274.     LONG iIndex;
  275.     HWND hWnd = (HWND) pContext;
  276.  
  277.     if( dwFlags == DPESC_TIMEDOUT )
  278.     {
  279.     return FALSE;
  280.     }
  281.  
  282.     iIndex = SendMessage(hWnd, LB_ADDSTRING, 0, (LPARAM) lpDPGameDesc->szSessionName);
  283.     if (iIndex != LB_ERR)
  284.         SendMessage(hWnd, LB_SETITEMDATA, iIndex, (LPARAM) lpDPGameDesc->dwSession);
  285.  
  286.     SetFocus(hWnd);
  287.     SendMessage(hWnd, LB_SETCURSEL, 0, 0);
  288.     return(TRUE);
  289.  
  290. }
  291.  
  292. BOOL FAR PASCAL EnumSP(LPGUID lpGuid, LPSTR lpDesc,
  293.             DWORD dwMajor, DWORD dwMinor, LPVOID lpv)
  294. {
  295.     LONG iIndex;
  296.     HWND hWnd = (HWND) lpv;
  297.  
  298.     iIndex = SendMessage(hWnd, LB_ADDSTRING, 0, (LPARAM) lpDesc);
  299.     if (iIndex != LB_ERR)
  300.         SendMessage(hWnd, LB_SETITEMDATA, iIndex, (LPARAM) lpGuid);
  301.  
  302.     SetFocus(hWnd);
  303.     SendMessage(hWnd, LB_SETCURSEL, 0, 0);
  304.     return(TRUE);
  305. }
  306.  
  307.  
  308.  
  309. BOOL CALLBACK DlgProcQCreate (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  310. {
  311.     switch (msg)
  312.     {
  313.     case WM_COMMAND:
  314.         switch(wParam)
  315.         {
  316.         case IDC_CREATE:
  317.             EndDialog(hDlg, 1);
  318.             return(TRUE);
  319.  
  320.         case IDC_CONNECT:
  321.             EndDialog(hDlg, 2);
  322.             return(TRUE);
  323.  
  324.         case IDCANCEL:
  325.             EndDialog(hDlg, -1);
  326.             return(TRUE);
  327.         }
  328.         break;
  329.  
  330.     }
  331.     return(FALSE);
  332. }
  333. BOOL CALLBACK DlgProcChooseProvider (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  334. {
  335.     LPGUID  lpGuid;
  336.     static  LONG    iIndex;
  337.     static  HWND hWndCtl;
  338.  
  339.     switch (msg)
  340.     {
  341.     case WM_INITDIALOG:
  342.  
  343.         hWndCtl = GetDlgItem(hDlg, IDC_LIST1);
  344.         if (hWndCtl == NULL)
  345.         {
  346.             EndDialog(hDlg, TRUE);
  347.             return(TRUE);
  348.         }
  349.         DirectPlayEnumerate(EnumSP, (LPVOID) hWndCtl);
  350.         SetFocus(hWndCtl);
  351.         SendMessage(hWndCtl, LB_SETCURSEL, 0, 0);
  352.         return(FALSE);
  353.  
  354.     case WM_COMMAND:
  355.  
  356.         switch( HIWORD(wParam))
  357.         {
  358.         case LBN_SELCHANGE:
  359.             iIndex = SendMessage((HWND) lParam, LB_GETCURSEL, 0, 0);
  360.             hWndCtl = (HWND) lParam;
  361.             return(FALSE);
  362.  
  363.         case LBN_DBLCLK:
  364.             iIndex = SendMessage((HWND) lParam, LB_GETCURSEL, 0, 0);
  365.             if (iIndex != LB_ERR)
  366.             {
  367.                 lpGuid = (LPGUID) SendMessage((HWND) lParam, LB_GETITEMDATA, iIndex, 0);
  368.                 DirectPlayCreate(lpGuid, &lpIDC, NULL);
  369.                 EndDialog(hDlg, TRUE);
  370.                 return(TRUE);
  371.             }
  372.             break;
  373.  
  374.         case 0:
  375.             if (LOWORD(wParam) == IDOK)
  376.             {
  377.                 if (iIndex != LB_ERR)
  378.                 {
  379.                     lpGuid = (LPGUID) SendMessage(hWndCtl, LB_GETITEMDATA, iIndex, 0);
  380.                     if (lpGuid)
  381.                     {
  382.                         DirectPlayCreate(lpGuid, &lpIDC, NULL);
  383.                         EndDialog(hDlg, TRUE);
  384.                     }
  385.                     else
  386.                         EndDialog(hDlg, FALSE);
  387.                     return(TRUE);
  388.                 }
  389.             }
  390.             else if (LOWORD(wParam) == IDCANCEL)
  391.             {
  392.                 EndDialog(hDlg, FALSE);
  393.                 return(TRUE);
  394.             }
  395.             break;
  396.  
  397.         }
  398.     }
  399.     return (FALSE);
  400. }
  401.  
  402. LPGUID g_lpGuid;
  403.  
  404. BOOL CALLBACK DlgProcSelSession (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  405. {
  406.     static  LONG    iIndex;
  407.     static  HWND hWndCtl;
  408.     DPSESSIONDESC dpDesc;
  409.     HRESULT hr = DP_OK + 10;
  410.  
  411.     switch (msg)
  412.     {
  413.     case WM_INITDIALOG:
  414.  
  415.         hWndCtl = GetDlgItem(hDlg, IDC_LB_SESSION);
  416.         if (hWndCtl == NULL)
  417.         {
  418.             EndDialog(hDlg, TRUE);
  419.             return(TRUE);
  420.         }
  421.         memset(&dpDesc, 0x00, sizeof(DPSESSIONDESC));
  422.         dpDesc.dwSize = sizeof(dpDesc);
  423.         dpDesc.guidSession = *g_lpGuid;
  424.         lpIDC->EnumSessions(&dpDesc, 5000, EnumSession, (LPVOID) hWndCtl, 0 );
  425.  
  426.         SetFocus(hWndCtl);
  427.         return(FALSE);
  428.  
  429.     case WM_COMMAND:
  430.  
  431.         switch( HIWORD(wParam))
  432.         {
  433.         case LBN_SELCHANGE:
  434.             iIndex = SendMessage((HWND) lParam, LB_GETCURSEL, 0, 0);
  435.             hWndCtl = (HWND) lParam;
  436.             return(FALSE);
  437.  
  438.         case 0:
  439.             if (LOWORD(wParam) == IDCANCEL)
  440.             {
  441.                 lpIDC->Close();
  442.                 lpIDC->Release();
  443.                 lpIDC = NULL;
  444.                 EndDialog(hDlg, FALSE);
  445.                 return(TRUE);
  446.             }
  447.             //
  448.             // Fall Through.
  449.             //
  450.         case LBN_DBLCLK:
  451.             if (HIWORD(wParam) == LBN_DBLCLK)
  452.             {
  453.                 hWndCtl = (HWND) lParam;
  454.                 iIndex = SendMessage(hWndCtl, LB_GETCURSEL, 0, 0);
  455.             }
  456.  
  457.             if (iIndex != LB_ERR)
  458.             {
  459.                 memset(&dpDesc, 0x00, sizeof(DPSESSIONDESC));
  460.                 dpDesc.dwSize       = sizeof(dpDesc);
  461.                 dpDesc.guidSession  = *g_lpGuid;
  462.                 dpDesc.dwFlags      = DPOPEN_OPENSESSION;
  463.                 dpDesc.dwSession    = SendMessage((HWND) hWndCtl, LB_GETITEMDATA, iIndex, 0);
  464.                 hr = lpIDC->Open(&dpDesc);
  465.  
  466.                 if (hr != DP_OK)
  467.                 {
  468.                     lpIDC->Close();
  469.                     lpIDC->Release();
  470.                     lpIDC = NULL;
  471.                     EndDialog(hDlg, FALSE);
  472.                 }
  473.  
  474.                 EndDialog(hDlg, TRUE);
  475.                 return(TRUE);
  476.  
  477.             }
  478.         }
  479.     }
  480.     return (FALSE);
  481. }
  482.  
  483. INT GetProvider()
  484. {
  485.  
  486.   return(DialogBox (NULL, (LPCTSTR) IDD_CHOOSEPROVIDER, NULL, (DLGPROC) DlgProcChooseProvider));
  487. }
  488.  
  489. INT CreateGame()
  490. {
  491.   return(DialogBox (NULL, (LPCTSTR) IDD_Q_CREATE, NULL, (DLGPROC) DlgProcQCreate));
  492.     
  493. }
  494.  
  495. INT GetGame()
  496. {
  497.  
  498.   return(DialogBox (NULL, (LPCTSTR) IDD_SELSESSION, NULL, (DLGPROC) DlgProcSelSession));
  499. }
  500.  
  501. BOOL RemoteCreateLobby(void)
  502. {
  503.     LPDIRECTPLAY2A      lpDPlay2 = NULL;
  504.     LPDIRECTPLAYLOBBYA  lpDPLobby = NULL;
  505.     HRESULT             hr;
  506.  
  507.     // Be sure we aren't already initialized.
  508.     if (lpIDC != NULL)
  509.     {
  510.         return( FALSE );
  511.     }
  512.  
  513.     // create a lobby object
  514.     hr = DirectPlayLobbyCreate(NULL, &lpDPLobby, NULL, NULL, 0);
  515.     if FAILED(hr)
  516.         return (FALSE);
  517.  
  518.     // try to connect using the lobby
  519.     hr = lpDPLobby->Connect(0, &lpDPlay2, NULL) ;   
  520.  
  521.     // lobby launched us, so get a DirectPlay 1 interface
  522.     if SUCCEEDED(hr)
  523.     {
  524.         // query for a DirectPlay 1.0 interface
  525.         hr = lpDPlay2->QueryInterface(IID_IDirectPlay, (LPVOID *) &lpIDC);
  526.  
  527.         // release the ANSI DirectPlay2 interface
  528.         lpDPlay2->Release();
  529.     }
  530.  
  531.     // release lobby interface
  532.     lpDPLobby->Release();
  533.  
  534.     return ((BOOL)(hr == DP_OK));
  535. }
  536.  
  537. BOOL RemoteCreate(REFGUID pGuid, LPSTR FullName, LPSTR NickName)
  538. {
  539.     HRESULT hr;
  540.     DPSESSIONDESC dpDesc;
  541.  
  542.     // lobby did not launch us, so ask user for connection settings
  543.     if (lpIDC == NULL)
  544.     {
  545.         GetProvider();
  546.  
  547.         if (lpIDC == NULL)
  548.             return(FALSE);
  549.  
  550.         switch( CreateGame())
  551.         {
  552.         case 1:             // Create
  553.             memset(&dpDesc, 0x00, sizeof(DPSESSIONDESC));
  554.             dpDesc.dwSize = sizeof(dpDesc);
  555.             dpDesc.dwMaxPlayers = 10;
  556.             dpDesc.dwFlags = DPOPEN_CREATESESSION;
  557.             dpDesc.guidSession = pGuid;
  558.             strcpy( dpDesc.szSessionName, FullName);
  559.         
  560.             if ((hr = lpIDC->Open(&dpDesc)) != DP_OK)
  561.             {
  562.                 lpIDC->Release();
  563.                 lpIDC = NULL;
  564.                 return(FALSE);
  565.             }
  566.         
  567.             break;
  568.  
  569.         case 2:             // Connect
  570.             g_lpGuid = (LPGUID) &pGuid;
  571.  
  572.             GetGame();
  573.  
  574.             if (lpIDC == NULL)
  575.                 return(FALSE);
  576.  
  577.             break;
  578.  
  579.         default:
  580.             return(FALSE);
  581.         }
  582.     }
  583.  
  584.     if ((hr = lpIDC->CreatePlayer(&dcoID, NickName,
  585.                                   "IKlowns Player", &dphEvent)) != DP_OK)
  586.     {
  587.         lpIDC->Close();
  588.         lpIDC->Release();
  589.         lpIDC = NULL;
  590.         return(FALSE);
  591.     }
  592.     
  593.     
  594.     InitReceivePoll();
  595.     return(TRUE);
  596.  
  597. }
  598.  
  599.  
  600. // -----------------------------------------------------------------
  601. // SetCurrentLevel - set pointer to current level object
  602. // -----------------------------------------------------------------
  603. void SetCurrentLevel(
  604.     void    *newLevel
  605. )
  606. {
  607.     gCurLevel = (CGameLevel *)newLevel;
  608. }
  609.  
  610. // ----------------------------------------------------------
  611. // CreateNewCharacter - create a new game object!
  612. // ----------------------------------------------------------
  613. void CreateNewCharacter(
  614.     REMOTE_OBJECT *pObj // unique object id
  615. )
  616. {
  617.     char dataBuf[256];
  618.     char graphicsBuf[256];
  619.  
  620.     // Get specific data on object from profile
  621.     // NOTE: This means we hit the disk.  For performance,
  622.     // it would be better if objects could be created based
  623.     // on an in memory object so that we don't ever have to
  624.     // hit the disk!
  625.  
  626.  
  627.     GetPrivateProfileString(
  628.             gCurLevel->GetLevelName(),
  629.             "Graphics",
  630.             "",
  631.             graphicsBuf,
  632.             sizeof( graphicsBuf ),
  633.             gCurLevel->GetProfileName()
  634.             );
  635.  
  636.     GetPrivateProfileString(
  637.             graphicsBuf,
  638.             pObj->ObjectID,
  639.             "",
  640.             dataBuf,
  641.             sizeof( dataBuf ),
  642.             gCurLevel->GetProfileName()
  643.             );
  644.  
  645.     // parse the data string into fields
  646.     CStringRecord fields( dataBuf, "," );
  647.  
  648.     if (fields.GetNumFields() >= 5)
  649.     {
  650.         // Add the object to the game list!
  651.         gCurLevel->Add(pObj->ObjectID,
  652.             atoi(fields[1]), 
  653.             atoi(fields[3]),
  654.             atoi(fields[4]),
  655.             (void *)pObj);
  656.     }
  657. }
  658.  
  659. // ----------------------------------------------------------
  660. // ProcessIncomingActions - Parse received messages & queue them
  661. // ----------------------------------------------------------
  662. BOOL ProcessIncomingActions(
  663.     REMOTE_OBJECT *pObj,    // unique object id
  664.     ACTION action,      // action code
  665.     void *Data,     // action data
  666.     DWORD nDataSize     // sizeof action data
  667. )
  668. {
  669.     CLinkedList *ActionList;
  670.     BOOL        fQueuedUp = FALSE;
  671.         // char            chBuffer[128];
  672.  
  673.         // wsprintf( chBuffer, "IncomingAction %d size %d\r\n", action, nDataSize);
  674.         // OutputDebugString(chBuffer);
  675.  
  676.     // Guard against activity occurring before we are ready!
  677.     if (gCurLevel == NULL)
  678.         return(FALSE);
  679.  
  680.     // Don't do anything about our own requests
  681.     if (pObj->OwnerID == dcoID)
  682.         return(FALSE);
  683.         
  684.     // Figure out what to do with this message
  685.     switch (action) {
  686.  
  687.     // Need to create a brand new object locally
  688.         case CREATE_OBJECT: {
  689.  
  690.                 // OutputDebugString("CreateObject \r\n");
  691.         // Create a game character
  692.         if (!FindRemoteObjectEntry(pObj))
  693.         {
  694.                         // OutputDebugString("CreateNewCharacter \r\n");
  695.             CreateNewCharacter(pObj);
  696.         }
  697.                 // OutputDebugString("Leave CreateObject \r\n");
  698.         break;
  699.     }
  700.  
  701.     // Time to destroy the object!
  702.     case DESTROY_OBJECT:    {
  703.         REMOTE_DATA *pRemoteEntry = FindRemoteObjectEntry(pObj);
  704.  
  705.                 // OutputDebugString("DestroyObject \r\n");
  706.         // Need to tell level object to remove the character!
  707.         if (pRemoteEntry != NULL)
  708.             gCurLevel->Remove((CGameGraphic *)pRemoteEntry->Data);
  709.  
  710.         break;
  711.     }
  712.  
  713.     // Must be some character specific action
  714.     default:{
  715.  
  716.         // Get action list for this object
  717.         ActionList = GetRemoteObjectQueue(pObj);
  718.  
  719.         // No action list -> a new object, so try to create it.
  720.         if (ActionList == NULL)
  721.         {
  722.             CreateNewCharacter(pObj);
  723.             ActionList = GetRemoteObjectQueue(pObj);
  724.             if (ActionList == NULL)
  725.                 return(FALSE);
  726.         }
  727.  
  728.         // Place this action onto the queue
  729.                 // OutputDebugString("QueueRemoteAction \r\n");
  730.         QueueRemoteAction(ActionList, action, Data, nDataSize);
  731.         fQueuedUp = TRUE;
  732.         break;
  733.     }
  734.     }
  735.     return(fQueuedUp);
  736. }
  737.  
  738. // ----------------------------------------------------------
  739. // ReleaseRemoteData - free remote buffer
  740. // ----------------------------------------------------------
  741. void ReleaseRemoteData(
  742.     LPVOID  pData       // ptr to app data portion
  743. )
  744. {
  745.     PGAMEMESSAGE    pMsg;   // desired pointer
  746.     int     iDiff;  // difference between the two
  747.  
  748.     // Pretend we got passed in the proper ptr
  749.     pMsg = (PGAMEMESSAGE)pData;
  750.  
  751.     // Calculate the difference between what we got
  752.     // and what we need.
  753.     iDiff = (LPBYTE)(&pMsg->Data) - (LPBYTE)(pMsg);
  754.  
  755.     // Adjust accordingly and free the message!
  756.     pMsg = (PGAMEMESSAGE)((LPBYTE)pMsg - iDiff);
  757.     delete pMsg;
  758. }
  759.  
  760. #define MAX_BUFFER_SIZE (sizeof(GAMEMESSAGE)+512)
  761.  
  762.  
  763.  
  764.  
  765. static char *pBuffer = NULL;
  766. static DWORD lenBuff = MAX_BUFFER_SIZE; 
  767.  
  768. static void InitReceivePoll( void )
  769. {
  770.     // We allocate a buffer to receive into first,
  771.     // which may have to cope with system messages,
  772.     // before copying the real message to the buffer to pass
  773.     // to the game
  774.     pBuffer = new char[ lenBuff ];
  775.  
  776. }
  777.  
  778. void PollForRemoteReceive( void )
  779. {
  780.     DPID        fromID, dcoReceiveID;
  781.     DWORD       nBytes;
  782.     PGAMEMESSAGE    pMsg;
  783.     int         i;
  784.     const       int MAX_MESSAGES = 16;
  785.     BOOL        fCheckForMore = TRUE;
  786.  
  787.     // Paranoia check
  788.     if ( lpIDC )
  789.     {
  790.         // We try to receive MAX_MESSAGES at a time so that
  791.         // a backlog doesn't build up.  If we run out of messages,
  792.         // we stop looking for them.
  793.  
  794.         for( i = 0; i < MAX_MESSAGES && fCheckForMore ; i++ )
  795.         {
  796.             HRESULT status;
  797.             nBytes = lenBuff;
  798.             status = lpIDC->Receive(
  799.                         &fromID,
  800.                         &dcoReceiveID,
  801.                         DPRECEIVE_ALL,
  802.                         pBuffer,
  803.                         &nBytes);
  804.             switch( status )
  805.             {
  806.             case DP_OK:
  807.                 if ( fromID == 0 )
  808.                 {
  809.                     // We do not in fact utilise the system
  810.                     // messages during the game.
  811.                 }
  812.                 else
  813.                 {
  814.                     // User message - we copy the buffer minus the
  815.                     // user message byte to the game buffer, then 
  816.                     // pass it on.
  817.         
  818.                     // Allocate buffer for game message
  819.                     pMsg = (PGAMEMESSAGE)new char [MAX_BUFFER_SIZE];
  820.                     memcpy( pMsg, &pBuffer[0], nBytes );
  821.         
  822.                 if (!ProcessIncomingActions(&pMsg->RemObj, pMsg->Action,
  823.                                 pMsg->Data, nBytes))
  824.                         delete pMsg;
  825.                 }
  826.             break;
  827.  
  828.             default:
  829.                 // Error condition of some kind - we just stop
  830.                 // checking for now
  831.                 fCheckForMore = FALSE;
  832.                 break;
  833.             }
  834.         }
  835.     }
  836. }
  837.  
  838.  
  839. BOOL CALLBACK AbortDlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  840. {
  841.     WORD wID, wNotifyCode;
  842.     BOOL retVal = 0;
  843.  
  844.     switch( uMsg )
  845.     {
  846.         case WM_INITDIALOG:
  847.             // We didn't set focus
  848.             retVal = 1;
  849.             break;
  850.         case WM_COMMAND:
  851.             wID = LOWORD( wParam );
  852.             wNotifyCode = HIWORD( wParam );
  853.             switch ( wID )
  854.             {
  855.                 case IDCANCEL:
  856.                     if ( BN_CLICKED == wNotifyCode ) {
  857.                         fAbort = TRUE;
  858.                         retVal = 1;
  859.                     }
  860.                     break;
  861.                 default:
  862.                     break;
  863.             }   
  864.             break;
  865.     }
  866.     return( retVal );
  867. }
  868.