home *** CD-ROM | disk | FTP | other *** search
/ The Games Machine 80 / XENIATGM80.iso / Goodies / Blood 2 / Source / data.z / BloodServerShell.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-04-02  |  52.6 KB  |  2,130 lines

  1. // ----------------------------------------------------------------------- //
  2. //
  3. // MODULE  : BloodServerShell.cpp
  4. //
  5. // PURPOSE : Blood's server shell - Implementation
  6. //
  7. // CREATED : 9/17/97
  8. //
  9. // ----------------------------------------------------------------------- //
  10.  
  11. #include "BloodServerShell.h"
  12. #include "PlayerObj.h"
  13. #include "cpp_server_de.h"
  14. #include "PathMgr.h"
  15. #include "ClientServerShared.h"
  16. #include "FileCaching.h"
  17. #include "ai_mgr.h"
  18. #include "sparam.h"
  19. #include "CameraObj.h"
  20. #include "CVarTrack.h"
  21. #include "CultistAI.h"
  22.  
  23. #include <windows.h>  // For DebugBreak
  24. #include <winbase.h>
  25. #include <stdio.h>
  26. #include <io.h>
  27. #include <fcntl.h>
  28.  
  29.  
  30. #define MAX_CLIENT_NAME_LENGTH        100
  31. #define CLIENT_PING_UPDATE_RATE        7.5f
  32. #define WAIT_TIME_FOR_LEVEL_SWITCH    7.5f
  33.  
  34. char g_szVarDoAutosave[]        = "GAME_DOAUTOSAVE";
  35. char g_szVarRevisiting[]        = "GAME_REVISITING";
  36. char g_szVarRestoring[]            = "GAME_RESTORING";
  37. char g_szVarGotoStartpoint[]    = "GAME_GOTOSTARTPOINT";
  38. char g_szVarWorldName[]            = "GAME_WORLDNAME";
  39. char g_szVarDifficulty[]        = "GAME_DIFFICULTY";
  40. char g_szVarGameType[]            = "GAME_GAMETYPE";
  41. char g_szSavePath[]                = "Save\\Current\\";
  42. char g_szAutoSaveFile[]            = "Auto.sav";
  43. char g_szCurrentSaveFile[]        = "Current.sav";
  44.  
  45. DBOOL    g_bNextLevel = DFALSE;
  46. DBOOL    g_bWaitToStartNextLevel = DFALSE;
  47. DFLOAT    g_fWaitTimeForNextLevel = 0.0f;
  48.  
  49. CVarTrack    g_SayTrack;
  50.  
  51. extern    BOOL    g_bLevelChangeCharacter;
  52. extern    int        g_nLevelChangeCharacter;
  53.  
  54.  
  55. SETUP_SERVERSHELL()
  56. DEFINE_CLASSES()
  57.  
  58. CBloodServerShell* g_pBloodServerShell = DNULL;
  59.  
  60. ServerShellDE* CreateServerShell(ServerDE *pServerDE)
  61. {
  62.     g_pServerDE = pServerDE;
  63.  
  64.     CBloodServerShell *pShell = new CBloodServerShell;
  65.  
  66.     g_pBloodServerShell = pShell;
  67.  
  68.     return (ServerShellDE*)pShell;
  69. }
  70.  
  71.  
  72. void DeleteServerShell(ServerShellDE *pInputShell)
  73. {
  74.     CBloodServerShell *pShell = (CBloodServerShell*)pInputShell;
  75.  
  76.     // Only set to NULL if we are deleting what we think is the current server shell..
  77.     // gk
  78. //    if (g_pBloodServerShell == pShell)
  79. //        g_pBloodServerShell = DNULL;
  80.  
  81.     delete pShell;
  82. }
  83.  
  84.  
  85.  
  86.  
  87. // ----------------------------------------------------------------------- //
  88. //
  89. //    ROUTINE:    CBloodServerShell::CBloodServerShell()
  90. //
  91. //    PURPOSE:    Initialize
  92. //
  93. // ----------------------------------------------------------------------- //
  94.  
  95. CBloodServerShell::CBloodServerShell()
  96. {
  97.     memset(&m_GameInfo, 0, sizeof(NetGame));
  98.  
  99.     m_hstrStartPointName = DNULL;
  100.  
  101. #ifdef _ADD_ON
  102.     m_bAddonLevel = DFALSE;
  103. #endif
  104.  
  105.     SetUpdateBlood2Serv();
  106.  
  107.     ClearClientList();
  108.  
  109.     SetupGameInfo();
  110.  
  111.     m_bBlood2ServHosted = DFALSE;
  112.     m_nCurLevel             = 0;
  113.  
  114.     if (!m_VoiceMgr.IsInited())
  115.     {
  116.         m_VoiceMgr.Init(g_pServerDE);
  117.     }
  118.  
  119.     g_SayTrack.Term();
  120.  
  121.     // Reset the goto-start-point game con var...
  122.     g_pServerDE->SetGameConVar(g_szVarGotoStartpoint, "1");
  123. }
  124.  
  125.  
  126. // ----------------------------------------------------------------------- //
  127. //
  128. //    ROUTINE:    CBloodServerShell::~CBloodServerShell()
  129. //
  130. //    PURPOSE:    Deallocate
  131. //
  132. // ----------------------------------------------------------------------- //
  133.  
  134. CBloodServerShell::~CBloodServerShell()
  135. {
  136.     if (!g_pServerDE) return;
  137.  
  138.     // Tell all clients that we are shutting down
  139.     //HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(NULL, SMSG_SERVERSHUTDOWN);
  140.     //g_pServerDE->EndMessage(hMessage);
  141.  
  142.     if (m_hstrStartPointName)
  143.         g_pServerDE->FreeString(m_hstrStartPointName);
  144.  
  145.     m_VoiceMgr.Term();
  146.  
  147.     g_SayTrack.Term();
  148. }
  149.  
  150. /*
  151. // ----------------------------------------------------------------------- //
  152. //
  153. //    ROUTINE:    CBloodServerShell::OnAddClient()
  154. //
  155. //    PURPOSE:    Add a client
  156. //
  157. // ----------------------------------------------------------------------- //
  158.  
  159. void CBloodServerShell::OnAddClient(HCLIENT hClient)
  160. {
  161. }
  162. */    
  163.  
  164. // ----------------------------------------------------------------------- //
  165. //
  166. //    ROUTINE:    CBloodServerShell::OnRemoveClient()
  167. //
  168. //    PURPOSE:    Remove a client
  169. //
  170. // ----------------------------------------------------------------------- //
  171.  
  172. void CBloodServerShell::OnRemoveClient(HCLIENT hClient)
  173. {
  174.     CPlayerObj *pPlayer;
  175.     ServerDE *pServerDE = GetServerDE();
  176.  
  177.     if(pPlayer = (CPlayerObj*)pServerDE->GetClientUserData(hClient))
  178.     {
  179.         pPlayer->SetClient(DNULL);
  180.     }
  181. }
  182.     
  183.  
  184. // ----------------------------------------------------------------------- //
  185. //
  186. //    ROUTINE:    CBloodServerShell::OnClientEnterWorld()
  187. //
  188. //    PURPOSE:    Handle client entering the world
  189. //
  190. // ----------------------------------------------------------------------- //
  191.  
  192. BaseClass* CBloodServerShell::OnClientEnterWorld(HCLIENT hClient, void* pClientData, DDWORD dwClientDataLen)
  193. {
  194.     if (!g_pServerDE || !hClient) return DNULL;
  195.  
  196.     BaseClass* pObject  = DNULL;
  197.     DBOOL bFoundClient = DFALSE;
  198.  
  199.     char szClientName[MAX_CLIENT_NAME_LENGTH];
  200.     char szClientRefName[MAX_CLIENT_NAME_LENGTH];
  201.     szClientName[0] = szClientRefName[0] = '\0';
  202.  
  203.     g_pServerDE->GetClientName(hClient, szClientName, MAX_CLIENT_NAME_LENGTH-1);
  204.  
  205.     // Search through the client refs to see if any of them match..
  206.     HCLIENTREF hClientRef = g_pServerDE->GetNextClientRef(DNULL);
  207.     while (hClientRef)
  208.     {
  209.         // See if this client reference is local or not...
  210.         if (g_pServerDE->GetClientRefInfoFlags(hClientRef) & CIF_LOCAL)
  211.         {
  212.             bFoundClient = DTRUE;
  213.         }
  214.  
  215.         // Determine if there is a reference to a client with the same name...
  216.         if (!bFoundClient && g_pServerDE->GetClientRefName(hClientRef, szClientRefName, MAX_CLIENT_NAME_LENGTH-1))
  217.         {
  218.             if (szClientName[0] && szClientRefName[0])
  219.             {
  220.                 if (_mbsicmp((const unsigned char*)szClientName, (const unsigned char*)szClientRefName) == 0)
  221.                 {
  222.                     bFoundClient = DTRUE;
  223.                 }
  224.             }
  225.         }
  226.  
  227.         // See if we found the right client...
  228.         if (bFoundClient)
  229.         {
  230.             HOBJECT    hObject = g_pServerDE->GetClientRefObject(hClientRef);
  231.             pObject = g_pServerDE->HandleToObject(hObject);
  232.  
  233.             if (pObject)
  234.                 RespawnPlayer(pObject, hClient);
  235.             break;
  236.         }
  237.  
  238.         hClientRef = g_pServerDE->GetNextClientRef(hClientRef);
  239.     }
  240.  
  241.     // Add this client to the appropriate team...
  242.     DWORD dwTeamID = TEAM_1;
  243.  
  244.     if (IsMultiplayerTeamBasedGame())
  245.     {
  246.         if (pClientData && dwClientDataLen == sizeof(NetClientData))
  247.         {
  248.             NetClientData* pNcd = (NetClientData*)pClientData;
  249.  
  250.             dwTeamID = pNcd->m_dwTeam;
  251.         }
  252.  
  253.         if (dwTeamID == TEAM_AUTO)
  254.         {
  255.             CTeam* pTeam = m_TeamMgr.GetTeamWithLeastPlayers(TRUE);
  256.             if (pTeam)
  257.             {
  258.                 dwTeamID = pTeam->GetID();
  259.             }
  260.             else
  261.             {
  262.                 if (IsRandomChance(50)) dwTeamID = TEAM_2;
  263.                 else dwTeamID = TEAM_1;
  264.             }
  265.         }
  266.  
  267.         DDWORD dwTransTeamID = m_TeamMgr.GetTeamTransID(g_pServerDE->GetClientID(hClient));
  268.         CTeam* pTeam         = m_TeamMgr.GetTeam(dwTransTeamID);
  269.  
  270.         if (dwTransTeamID != TM_ID_NULL && pTeam)
  271.         {
  272.             dwTeamID = dwTransTeamID;
  273.         }
  274.     }
  275.  
  276.     m_TeamMgr.AddPlayer(dwTeamID, g_pServerDE->GetClientID(hClient));
  277.  
  278.  
  279.     // See if we need to create a player (no matches found)...
  280.     if (!pObject)
  281.     {
  282.         pObject = CreatePlayer(hClient);
  283.         RespawnPlayer(pObject, hClient);
  284.     }
  285.  
  286.     // Add this client to our local list...
  287.     AddClientToList(hClient);
  288.  
  289.     // All done...
  290.     return pObject;
  291. }
  292.  
  293.  
  294. // ----------------------------------------------------------------------- //
  295. //
  296. //    ROUTINE:    CBloodServerShell::OnClientExitWorld()
  297. //
  298. //    PURPOSE:    Remove a client
  299. //
  300. // ----------------------------------------------------------------------- //
  301.  
  302. void CBloodServerShell::OnClientExitWorld(HCLIENT hClient)
  303. {
  304.     // Tell all clients..
  305.     RemovePlayerMessage(hClient);
  306.  
  307.     // Remove this client from the team...
  308.     m_TeamMgr.RemovePlayer(g_pServerDE->GetClientID(hClient));
  309.     
  310.     // Remove this client from our local list...
  311.     RemoveClientFromList(hClient);
  312.     SetUpdateBlood2Serv();
  313.  
  314.     // Remove the player object...
  315.     CPlayerObj* pPlayer = (CPlayerObj*)g_pServerDE->GetClientUserData(hClient);
  316.     if (pPlayer) 
  317.     {
  318.         pPlayer->DropFlag(DFALSE);
  319.         g_pServerDE->RemoveObject(pPlayer->m_hObject);
  320.     }
  321.  
  322.     g_pServerDE->SetClientUserData(hClient, DNULL);
  323. }
  324.  
  325.  
  326. // ----------------------------------------------------------------------- //
  327. //
  328. //    ROUTINE:    CBloodServerShell::OnMessage()
  329. //
  330. //    PURPOSE:    Handle messages
  331. //
  332. // ----------------------------------------------------------------------- //
  333.  
  334. void CBloodServerShell::OnMessage(HCLIENT hSender, DBYTE messageID, HMESSAGEREAD hMessage)
  335. {
  336.     if (!g_pServerDE) return;
  337.     switch(messageID)
  338.     {
  339.         case CMSG_NEXTLEVEL:
  340.         {
  341.             g_bNextLevel = DTRUE;
  342.             break;
  343.         }
  344.         case CMSG_WEAPON_FIRE:
  345.         {
  346.             void *pData = g_pServerDE->GetClientUserData(hSender);
  347.             CPlayerObj* pPlayer = (CPlayerObj*)pData;
  348.             if (pPlayer)
  349.             {
  350.                 pPlayer->HandleWeaponFireMessage(hMessage);
  351.             }
  352.         }
  353.         break;
  354.  
  355.         case CMSG_WEAPON_SOUND:
  356.         {
  357.             void *pData = g_pServerDE->GetClientUserData(hSender);
  358.             CPlayerObj* pPlayer = (CPlayerObj*)pData;
  359.             if (pPlayer)
  360.             {
  361.                 pPlayer->HandleWeaponSoundMessage(hMessage);
  362.             }
  363.         }
  364.         break;
  365.  
  366.         case CMSG_WEAPON_STATE:
  367.         {
  368.             void *pData = g_pServerDE->GetClientUserData(hSender);
  369.             CPlayerObj* pPlayer = (CPlayerObj*)pData;
  370.             if (pPlayer)
  371.             {
  372.                 pPlayer->HandleWeaponStateMessage(hMessage);
  373.             }
  374.         }
  375.         break;
  376.  
  377.         case CMSG_WEAPON_CHANGE:
  378.         {
  379.             void *pData = g_pServerDE->GetClientUserData(hSender);
  380.             CPlayerObj* pPlayer = (CPlayerObj*)pData;
  381.             if (pPlayer)
  382.             {
  383.                 DBYTE nWeaponId = g_pServerDE->ReadFromMessageByte(hMessage);
  384.                 pPlayer->DoWeaponChange(nWeaponId);
  385.             }
  386.         }
  387.         break;
  388.  
  389.         // Got a load world message
  390.         case CMSG_LOADWORLD:
  391.             {
  392.                 DBOOL bResult;
  393.                 bResult = LoadWorld(hMessage);
  394.                 // Acknowledge the load, good or bad
  395.                 HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(NULL, SMSG_LOADWORLD_ACK);
  396.                 g_pServerDE->WriteToMessageByte(hMessage, (DBYTE)bResult);
  397.                 g_pServerDE->EndMessage(hMessage);
  398.             }
  399.             break;
  400.  
  401.         case CMSG_SAVEGAME:
  402.             {
  403.                 HMESSAGEREAD hClientSaveData;
  404.                 CPlayerObj *pPlayerObj;
  405.                 char *pFilename = g_pServerDE->ReadFromMessageString(hMessage);
  406.                 DBOOL bSaveType = g_pServerDE->ReadFromMessageByte( hMessage );
  407.                 hClientSaveData = g_pServerDE->ReadFromMessageHMessageRead( hMessage );
  408.     
  409.                 pPlayerObj = ( CPlayerObj * )g_pServerDE->GetClientUserData(hSender);
  410.                 if( pPlayerObj )
  411.                     pPlayerObj->SetClientSaveData( hClientSaveData );                
  412.                 
  413.  
  414.                 if (bSaveType == SAVETYPE_CURRENT)
  415.                 {
  416.                     if (SaveGame(SAVETYPE_CURRENT, DTRUE, DTRUE))
  417.                     {    // Acknowledge a successful save
  418.                         HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(NULL, SMSG_SAVEGAME_ACK);
  419.                         g_pServerDE->EndMessage(hMessage);
  420.                     }
  421.                 }
  422.                 else    // Do autosave
  423.                 {
  424.                     if (SaveGame(SAVETYPE_AUTO, DTRUE, DTRUE))
  425.                     {
  426.                         HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(NULL, SMSG_SAVEGAME_ACK);
  427.                         g_pServerDE->EndMessage(hMessage);
  428.                     }
  429.                 }
  430.             }
  431.             break;
  432.  
  433.         case CMSG_DETACH_AI:
  434.             {
  435.                 HOBJECT hObj = g_pServerDE->ReadFromMessageObject(hMessage);
  436.             
  437.                 if(g_pServerDE->IsKindOf(g_pServerDE->GetObjectClass(hObj), g_pServerDE->GetClass("AI_Mgr")))
  438.                 {
  439.                     AI_Mgr* pAI = (AI_Mgr*)g_pServerDE->HandleToObject(hObj);
  440.                     pAI->DetachFromEnemy();
  441.                 }
  442.  
  443.                 break;
  444.             }
  445.  
  446.         case CMSG_ATTACH_ACK:
  447.             {
  448.                 HOBJECT hObj = g_pServerDE->ReadFromMessageObject(hMessage);
  449.             
  450.                 if(g_pServerDE->IsKindOf(g_pServerDE->GetObjectClass(hObj), g_pServerDE->GetClass("AI_Mgr")))
  451.                 {
  452.                     AI_Mgr* pAI = (AI_Mgr*)g_pServerDE->HandleToObject(hObj);
  453.                     pAI->ProceedToAttach();
  454.                 }
  455.  
  456.                 break;
  457.             }
  458.  
  459.         case CMSG_GAME_PAUSE:
  460.         {
  461.             DBOOL bPause = (DBOOL)g_pServerDE->ReadFromMessageByte(hMessage);
  462.  
  463.             DDWORD nFlags = g_pServerDE->GetServerFlags();
  464.             if (bPause)
  465.                 nFlags |= SS_PAUSED;
  466.             else
  467.                 nFlags &= ~SS_PAUSED;
  468.  
  469.             g_pServerDE->SetServerFlags(nFlags);
  470.         }
  471.         break;
  472.  
  473.         case CMSG_MULTIPLAYER_INIT:
  474.         {
  475.             CPlayerObj *pObj = (CPlayerObj*)g_pServerDE->GetClientUserData(hSender);
  476.             if (pObj)
  477.             {
  478.                 pObj->OnMessage(messageID, hMessage);
  479.  
  480.                 // Tell other players that he's here
  481.                 AddPlayerMessage(DNULL, hSender);
  482.  
  483.                 // tell new player about all current players (excluding himself)
  484.                 AddPlayersMessage(hSender);
  485.                 SetUpdateBlood2Serv();
  486.             }
  487.         }
  488.         break;
  489.  
  490.         case CMSG_SINGLEPLAYER_INIT:
  491.         {
  492.             CPlayerObj *pObj = (CPlayerObj*)g_pServerDE->GetClientUserData(hSender);
  493.             if (pObj)
  494.             {
  495.                 pObj->OnMessage(messageID, hMessage);
  496.             }
  497.         }
  498.         break;
  499.  
  500.         case CMSG_AUTOSAVE:
  501.         {
  502. #ifndef _DEMO
  503.             // Autosave current situation, to be able to restart the world
  504.             if (GetGameConVarValueFloat(g_szVarDoAutosave))
  505.             {
  506.                 HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(hSender, SMSG_DOAUTOSAVE);
  507.                 g_pServerDE->EndMessage(hMessage);
  508.  
  509. /*                if (SaveGame(SAVETYPE_AUTO, DTRUE, DTRUE))
  510.                 {
  511.                     HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(NULL, SMSG_SAVEGAME_ACK);
  512.                     g_pServerDE->EndMessage(hMessage);
  513.                 }
  514. */
  515.             }
  516. #endif
  517.  
  518.         }
  519.         break;
  520.  
  521.         default:    // Let the player handle it
  522.         {
  523.             CPlayerObj *pObj = (CPlayerObj*)g_pServerDE->GetClientUserData(hSender);
  524.             if (pObj)
  525.                 pObj->OnMessage(messageID, hMessage);
  526.         }
  527.     }
  528. }
  529.  
  530.             
  531. // ----------------------------------------------------------------------- //
  532. //
  533. //    ROUTINE:    CBloodServerShell::OnCommandOn()
  534. //
  535. //    PURPOSE:    Handle commands
  536. //
  537. // ----------------------------------------------------------------------- //
  538.  
  539. void CBloodServerShell::OnCommandOn(HCLIENT hClient, int command)
  540. {
  541.     CPlayerObj *pObj = (CPlayerObj*)g_pServerDE->GetClientUserData(hClient);
  542.     if (pObj)
  543.         pObj->OnCommandOn(command);
  544. }
  545.  
  546.  
  547. // ----------------------------------------------------------------------- //
  548. //
  549. //    ROUTINE:    CBloodServerShell::PreStartWorld()
  550. //
  551. //    PURPOSE:    Handle stuff that needs to happen before a world is loaded.
  552. //
  553. // ----------------------------------------------------------------------- //
  554.  
  555. void CBloodServerShell::PreStartWorld(DBOOL bSwitchingWorlds)
  556. {
  557.     // Setup the teams for multiplayer
  558.     m_TeamMgr.Term();
  559.     m_TeamMgr.Init();
  560.  
  561.     m_TeamMgr.AddTeam(TEAM_1, "TEAM1");
  562.     m_TeamMgr.AddTeam(TEAM_2, "TEAM2");
  563.  
  564.     // Setup the game info
  565.     SetupGameInfo();
  566.  
  567.     g_bNextLevel = DFALSE;
  568.  
  569.     // Reset global camera pointer
  570.     g_hActiveCamera = DNULL;
  571. }
  572.     
  573.  
  574. // ----------------------------------------------------------------------- //
  575. //
  576. //    ROUTINE:    CBloodServerShell::PostStartWorld()
  577. //
  578. //    PURPOSE:    Perform an autosave after the world is loaded
  579. //
  580. // ----------------------------------------------------------------------- //
  581.  
  582. void CBloodServerShell::PostStartWorld()
  583. {
  584.     // Build the list of AI paths for this world...
  585.     m_PathMgr.BuildPathList();
  586.  
  587.     // Init the voice manager if necessary...
  588.     if (!m_VoiceMgr.IsInited())
  589.     {
  590.         m_VoiceMgr.Init(g_pServerDE);
  591.     }
  592.  
  593.     m_VoiceMgr.StopAll();
  594. }
  595.     
  596.  
  597. // ----------------------------------------------------------------------- //
  598. //
  599. //    ROUTINE:    CBloodServerShell::ConsoleMessage()
  600. //
  601. //    PURPOSE:    Handle messages
  602. //
  603. // ----------------------------------------------------------------------- //
  604.  
  605. void CBloodServerShell::ConsoleMessage(HCLIENT hClient, char *msg)
  606. {
  607.     HMESSAGEWRITE hMsg;
  608.     
  609.     hMsg = g_pServerDE->StartMessage(hClient, SMSG_CONSOLEMESSAGE);
  610.     g_pServerDE->WriteToMessageString(hMsg, msg);
  611.     g_pServerDE->EndMessage(hMsg);
  612. }
  613.  
  614.  
  615. // ----------------------------------------------------------------------- //
  616. //
  617. //    ROUTINE:    CBloodServerShell::AddPlayerMessage()
  618. //
  619. //    PURPOSE:    Sends an AddPlayer message to all clients when a new player
  620. //                comes in.
  621. //
  622. // ----------------------------------------------------------------------- //
  623.  
  624. void CBloodServerShell::AddPlayerMessage(HCLIENT hDestClient, HCLIENT hNewPlayerClient)
  625. {
  626.     if (!hNewPlayerClient || !g_pServerDE) return;
  627.     HMESSAGEWRITE hMsg;
  628.  
  629.     CPlayerObj *pObj = (CPlayerObj*)g_pServerDE->GetClientUserData(hNewPlayerClient);
  630.     if (pObj)
  631.     {
  632.         HSTRING hstrName = pObj->GetPlayerName();
  633.  
  634.          DDWORD dwClientID = g_pServerDE->GetClientID(hNewPlayerClient);
  635.         // Send the message to hDestClient, if it's NULL, all clients get this message
  636.         hMsg = g_pServerDE->StartMessage(hDestClient, SMSG_ADDPLAYER);
  637.         g_pServerDE->WriteToMessageHString(hMsg, hstrName);
  638.         g_pServerDE->WriteToMessageDWord(hMsg, dwClientID);
  639.         g_pServerDE->WriteToMessageByte(hMsg, pObj->GetCharacter());
  640.         g_pServerDE->WriteToMessageFloat(hMsg, (DFLOAT) pObj->GetFrags());
  641.         g_pServerDE->WriteToMessageByte(hMsg, (DBYTE)pObj->GetTeamID());
  642.         g_pServerDE->EndMessage2(hMsg, MESSAGE_GUARANTEED | MESSAGE_NAGGLE);
  643.     }
  644. }
  645.  
  646.  
  647. // ----------------------------------------------------------------------- //
  648. //
  649. //    ROUTINE:    CBloodServerShell::AddPlayersMessage()
  650. //
  651. //    PURPOSE:    Iterates through the client list and sends a SMSG_ADDPLAYER
  652. //                message for each to hClient.
  653. //
  654. // ----------------------------------------------------------------------- //
  655.  
  656. void CBloodServerShell::AddPlayersMessage(HCLIENT hClient)
  657. {
  658.     if (!hClient || !g_pServerDE) return;
  659.  
  660.     for (int i = 0; i < MAX_CLIENTS; i++)
  661.     {
  662.         if (m_aClients[i] && hClient != m_aClients[i])
  663.         {
  664.             AddPlayerMessage(hClient, m_aClients[i]);
  665.         }
  666.     }
  667. }
  668.  
  669.  
  670. // ----------------------------------------------------------------------- //
  671. //
  672. //    ROUTINE:    CBloodServerShell::RemovePlayerMessage()
  673. //
  674. //    PURPOSE:    Sends an RemovePlayer message to all clients when a player
  675. //                leaves.
  676. //
  677. // ----------------------------------------------------------------------- //
  678.  
  679. void CBloodServerShell::RemovePlayerMessage(HCLIENT hClient)
  680. {
  681.     if (!hClient || !g_pServerDE) return;
  682.     
  683.     DDWORD dwClientID = g_pServerDE->GetClientID(hClient);
  684.  
  685.     // Send the message to all clients
  686.     HMESSAGEWRITE hMsg = g_pServerDE->StartMessage(DNULL, SMSG_REMOVEPLAYER);
  687.     g_pServerDE->WriteToMessageDWord(hMsg, dwClientID);
  688.     // [blg] g_pServerDE->EndMessage2(hMsg, MESSAGE_GUARANTEED | MESSAGE_NAGGLE);
  689.     g_pServerDE->EndMessage(hMsg);
  690. }
  691.  
  692. void CBloodServerShell::FragStatus()
  693. {
  694. }
  695.  
  696.  
  697. // ----------------------------------------------------------------------- //
  698. //
  699. //    ROUTINE:    CBloodServerShell::CreatePlayer()
  700. //
  701. //    PURPOSE:    Create the player object, and associate it with the client.
  702. //
  703. // ----------------------------------------------------------------------- //
  704.  
  705. BaseClass* CBloodServerShell::CreatePlayer(HCLIENT hClient)
  706. {
  707.     if (!g_pServerDE) return DNULL;
  708.  
  709.     ObjectCreateStruct ocStruct;
  710.  
  711.     INIT_OBJECTCREATESTRUCT(ocStruct);
  712.  
  713.     ROT_INIT(ocStruct.m_Rotation);
  714.     VEC_INIT(ocStruct.m_Pos);
  715.     ocStruct.m_Flags = 0;
  716.  
  717.     HCLASS hClass = g_pServerDE->GetClass("CPlayerObj");
  718.  
  719.     BaseClass* pClass = NULL;
  720.     if (hClass)
  721.     {
  722.         pClass = g_pServerDE->CreateObject(hClass, &ocStruct);
  723.         if (pClass)
  724.         {
  725.             CPlayerObj* pPlayer = (CPlayerObj*)pClass;
  726.             pPlayer->SetClient(hClient);
  727.             g_pServerDE->SetClientUserData(hClient, (void *)pClass);
  728.             pPlayer->Respawn();
  729. //            pPlayer->GoToStartPoint();
  730.             pPlayer->UpdateTeamID();
  731.         }
  732.     }
  733.  
  734.     return pClass;
  735. }
  736.  
  737.  
  738. // ----------------------------------------------------------------------- //
  739. //
  740. //    ROUTINE:    CBloodServerShell::RespawnPlayer()
  741. //
  742. //    PURPOSE:    Respawn the player object
  743. //
  744. // ----------------------------------------------------------------------- //
  745.  
  746. void CBloodServerShell::RespawnPlayer(BaseClass* pBaseObject, HCLIENT hClient)
  747. {
  748.     if (!pBaseObject || !hClient) return;
  749.  
  750.     CPlayerObj* pPlayer = (CPlayerObj*)pBaseObject;
  751.     pPlayer->SetClient(hClient);
  752.     g_pServerDE->SetClientUserData(hClient, (void *)pPlayer);
  753.  
  754.     // If this is a multiplayer game wait until MULTIPLAYER_INIT message
  755.     // to respawn the player...
  756.  
  757.     DBYTE nMessage = SMSG_PLAYERINIT_MULTIPLAYER;
  758.  
  759.     if (GetGameType() == GAMETYPE_SINGLE)
  760.     {
  761.         nMessage = SMSG_PLAYERINIT_SINGLEPLAYER;
  762.     }
  763.  
  764.     HMESSAGEWRITE hWrite = g_pServerDE->StartMessage(hClient, nMessage);
  765.  
  766.     // If this is a multiplayer game, send some game info too...
  767.     if (nMessage == SMSG_PLAYERINIT_MULTIPLAYER)
  768.     {
  769.         g_pServerDE->WriteToMessageByte(hWrite, m_GameInfo.m_byType);
  770.         g_pServerDE->WriteToMessageByte(hWrite, m_GameInfo.m_bFriendlyFire);
  771.         g_pServerDE->WriteToMessageByte(hWrite, m_GameInfo.m_bNegTeamFrags);
  772.         g_pServerDE->WriteToMessageByte(hWrite, m_GameInfo.m_bOnlyFlagScores);
  773.         g_pServerDE->WriteToMessageByte(hWrite, m_GameInfo.m_bOnlyGoalScores);
  774.     }
  775.  
  776.  
  777.     // End the message...
  778.     g_pServerDE->EndMessage2(hWrite, MESSAGE_GUARANTEED | MESSAGE_NAGGLE);
  779.  
  780.     
  781.     // Either a new level or restoring a previously visited level, so go to the startpoint
  782.     if (IsMultiplayerGame() || GetGameConVarValueFloat(g_szVarGotoStartpoint))
  783.     {
  784.         pPlayer->GoToStartPoint();
  785.     }
  786.     // Restoring a save, so don't change player and tell the client where to point the camera
  787.     else
  788.     {
  789.         pPlayer->SendMessageToClient(SMSG_FORCEROTATION);
  790.         pPlayer->SendMessageToClient(SMSG_EYELEVEL);
  791.     }
  792.  
  793.     // Reset the goto-start-point game con var...
  794.     g_pServerDE->SetGameConVar(g_szVarGotoStartpoint, "1");
  795. }
  796.  
  797.  
  798. // ----------------------------------------------------------------------- //
  799. //
  800. //    ROUTINE:    CBloodServerShell::SetStartpointName()
  801. //
  802. //    PURPOSE:    Sets the name of the next startpoint.
  803. //
  804. // ----------------------------------------------------------------------- //
  805.  
  806. void CBloodServerShell::SetStartPointName(HSTRING hString)
  807. {
  808.     if (!hString || !g_pServerDE) return;
  809.  
  810.     if (m_hstrStartPointName)
  811.     {
  812.         g_pServerDE->FreeString(m_hstrStartPointName);
  813.     }
  814.  
  815.     m_hstrStartPointName = g_pServerDE->CopyString(hString);
  816. }
  817.  
  818.  
  819.  
  820. // ----------------------------------------------------------------------- //
  821. //
  822. //    ROUTINE:    CBloodServerShell::LoadWorld()
  823. //
  824. //    PURPOSE:    handles the LOADWORLD message
  825. //
  826. // ----------------------------------------------------------------------- //
  827.  
  828. DBOOL CBloodServerShell::LoadWorld(HMESSAGEREAD hMessage)
  829. {
  830.     char szPath[MAX_PATH];
  831.     char *pFilename        = g_pServerDE->ReadFromMessageString(hMessage);
  832.     DBYTE nGameType        = g_pServerDE->ReadFromMessageByte(hMessage);
  833.     DBYTE nLoadType        = g_pServerDE->ReadFromMessageByte(hMessage);
  834.     DBYTE nDifficulty    = g_pServerDE->ReadFromMessageByte(hMessage);
  835.  
  836.     CultistAI::ResetStatics();    // fix a wierd clown animation bug
  837.  
  838.     if (!pFilename || _mbstrlen(pFilename) <= 0) return DFALSE;
  839.  
  840.     DRESULT res            = DE_OK;
  841.     DBOOL bRestoring    = DFALSE;
  842.     DBOOL bRestoringKeepAlive = DFALSE;
  843.     DBOOL bRevisiting    = DFALSE;
  844.  
  845.     // Remove leading slashes..
  846.     while(*pFilename == '\\' || *pFilename == '/')
  847.         pFilename++;
  848.  
  849.     // Init the voice manager if necessary...
  850.     if (!m_VoiceMgr.IsInited())
  851.     {
  852.         m_VoiceMgr.Init(g_pServerDE);
  853.     }
  854.  
  855.     m_VoiceMgr.StopAll();
  856.  
  857. //    // Current world name
  858. //    char *pOldWorld        = g_pServerDE->GetVarValueString(g_pServerDE->GetGameConVar(g_szVarWorldName));
  859.  
  860.     // Set console variables
  861.     // Save the filename in a console var for later use.
  862.     g_pServerDE->SetGameConVar(g_szVarWorldName, szPath);
  863.  
  864. #ifdef _ADDON
  865.     char sUpr[256];
  866.     strncpy(sUpr, pFilename, 255);
  867.     strupr(sUpr);
  868.     if (strstr(sUpr, "WORLDS_AO"))
  869.     {
  870.         strncpy(szPath, pFilename, MAX_PATH);
  871.         m_bAddonLevel = DTRUE;
  872.     }
  873.     else
  874.     {
  875.         _mbscpy((unsigned char*)szPath, (const unsigned char*)"Worlds\\");
  876.         _mbscat((unsigned char*)szPath, (const unsigned char*)pFilename);
  877.         m_bAddonLevel = DFALSE;
  878.     }
  879. #else
  880.     _mbscpy((unsigned char*)szPath, (const unsigned char*)"Worlds\\");
  881.     _mbscat((unsigned char*)szPath, (const unsigned char*)pFilename);
  882. #endif
  883.  
  884.     // Set console variables
  885.     // Save the filename in a console var for later use.
  886.     g_pServerDE->SetGameConVar(g_szVarWorldName, szPath);
  887.  
  888.     // If this is a brand-new game, set various stuff
  889.     if (nLoadType == LOADTYPE_NEW_GAME)
  890.     {
  891.         // Set difficulty level
  892.         SetGameInfo(nGameType, nDifficulty);
  893.     }
  894.  
  895.     // Restoring an autosave game
  896.     if (nLoadType == LOADTYPE_RESTOREAUTOSAVE)
  897.     {
  898.         pFilename = g_szAutoSaveFile;    // Restore from "auto.sav" file
  899.         bRestoring = DTRUE;
  900.     }
  901.     // Restoring a saved game
  902.     else if (nLoadType == LOADTYPE_RESTORESAVE)
  903.     {
  904.         bRestoring = DTRUE;
  905.     }
  906.     // New level, so we need to save the current world and the player data
  907.     else if (nLoadType == LOADTYPE_NEW_LEVEL)
  908.     {
  909.         // Check if this is an add-on level that wants a player change
  910.         DoLevelChangeCharacterCheck(pFilename);
  911.  
  912.         // Save the player data
  913.         KeepAliveSave();
  914.         bRestoringKeepAlive = DTRUE;
  915.  
  916.         // Save the current world sans players or console, in case we want to go back
  917. /*        Not doing this, so I'll just comment it out for now.. (Greg 10/5)
  918.         if (pOldWorld)
  919.             SaveGame(pOldWorld, DFALSE, DFALSE);
  920.  
  921.         // See if there is a save file for this level
  922.         char szSavePath[MAX_PATH];
  923.         _mbscpy((unsigned char*)szSavePath, (const unsigned char*)g_szSavePath);
  924.         _mbscat((unsigned char*)szSavePath, (const unsigned char*)pFilename);
  925.         _mbscat((unsigned char*)szSavePath, (const unsigned char*)".sav");
  926.  
  927.         // See if there is a save file for this level
  928.         if (int fhl = _open(szSavePath, _O_RDONLY) != -1)
  929.         {
  930.             _close(fhl);
  931.             bRevisiting = DTRUE;
  932.             bRestoring = DTRUE;
  933.         }
  934. */
  935.     }
  936.  
  937.     if (pFilename && _mbstrlen(pFilename))
  938.     {
  939.         DDWORD dwLoadFlags = 0;
  940.  
  941.         // Set load flags
  942.         if (!bRestoring)
  943.             dwLoadFlags |= LOADWORLD_LOADWORLDOBJECTS;
  944. //        if (pOldWorld && _mbsicmp((const unsigned char*)pOldWorld, (const unsigned char*)szPath) == 0)    // loading same world as current, don't reload geometry
  945. //        {
  946.             dwLoadFlags |= LOADWORLD_NORELOADGEOMETRY;
  947. //            g_pServerDE->DebugOut("Not loading geometry");
  948. //        }
  949.  
  950.         dwLoadFlags |= LOADWORLD_NORELOADGEOMETRY;
  951.  
  952.         res = g_pServerDE->LoadWorld(szPath, dwLoadFlags);
  953.         if (res != DE_OK)
  954.         {
  955.             g_pServerDE->BPrint("Error loading world %s: %d", pFilename, res);
  956.             return DFALSE;
  957.         }
  958.     }
  959.     // Restoring a game - Restore player position too.
  960.     if (bRestoring)
  961.     {
  962.         if (nLoadType == LOADTYPE_RESTOREAUTOSAVE)
  963.             RestoreGame(SAVETYPE_AUTO);
  964.         else
  965.             RestoreGame(SAVETYPE_CURRENT);
  966.     }
  967.  
  968.     // Restoring saved player data
  969.     if (bRestoringKeepAlive)
  970.     {
  971.         KeepAliveLoad();
  972.     }
  973.  
  974.     // All types start at a startpoint if not restoring, or if restoring a previous visited level
  975.     g_pServerDE->SetGameConVar(g_szVarGotoStartpoint, (!bRestoring || bRestoringKeepAlive) ? "1" : "0");
  976.  
  977.     // Set this if we are revisiting a world
  978.     g_pServerDE->SetGameConVar(g_szVarRevisiting, bRevisiting ? "1" : "0");
  979.  
  980.     // Autosave if not restoring (new level), or if we are revisiting.
  981.     // Set this flag so we know whether to autosave later
  982.     g_pServerDE->SetGameConVar(g_szVarDoAutosave, (!bRestoring || bRevisiting) ? "1" : "0");
  983.  
  984.     // Now run the world
  985.     res = g_pServerDE->RunWorld();
  986.     if (res != DE_OK)
  987.     {
  988.         g_pServerDE->BPrint("Error running world %s: %d", pFilename, res);
  989.         return DFALSE;
  990.     }
  991.  
  992.     return DTRUE;
  993. }
  994.  
  995.             
  996. // ----------------------------------------------------------------------- //
  997. //
  998. //    ROUTINE:    CBloodServerShell::SaveGame()
  999. //
  1000. //    PURPOSE:    Saves the state of the current world
  1001. //
  1002. // ----------------------------------------------------------------------- //
  1003.  
  1004. DBOOL CBloodServerShell::SaveGame(DBYTE bySaveType, DBOOL bSavePlayers, DBOOL bSaveConsole)
  1005. {
  1006.     DBOOL bRet = DFALSE;
  1007.  
  1008.     if (!g_pServerDE) 
  1009.         return DFALSE;
  1010.  
  1011.     char szSavePath[MAX_PATH];
  1012.     
  1013.     _mbscpy((unsigned char*)szSavePath, (const unsigned char*)g_szSavePath);
  1014.     if (bySaveType == SAVETYPE_CURRENT)
  1015.         _mbscat((unsigned char*)szSavePath, (const unsigned char*)g_szCurrentSaveFile);
  1016.     else if (bySaveType == SAVETYPE_AUTO)
  1017.         _mbscat((unsigned char*)szSavePath, (const unsigned char*)g_szAutoSaveFile);
  1018.     else 
  1019.         return DFALSE;
  1020.  
  1021.     // Make a list of savable objects
  1022.     ObjectList* pObjectList = g_pServerDE->CreateObjectList();
  1023.  
  1024.     // Loop through active objects
  1025.     HOBJECT hObj = g_pServerDE->GetNextObject(DNULL);
  1026.     while (hObj)
  1027.     {
  1028.         DDWORD dwFlags = g_pServerDE->GetObjectUserFlags(hObj);
  1029.         // Can this object be saved?
  1030.         if ((dwFlags & USRFLG_SAVEABLE) && (bSavePlayers || !IsPlayer(hObj)))
  1031.         {
  1032.             ObjectLink *ol = g_pServerDE->AddObjectToList(pObjectList, hObj);
  1033.             ol->m_hObject = hObj;
  1034.         }
  1035.  
  1036.         hObj = g_pServerDE->GetNextObject(hObj);
  1037.     }
  1038.     // And inactive objects
  1039.     hObj = g_pServerDE->GetNextInactiveObject(DNULL);
  1040.     while (hObj)
  1041.     {
  1042.         DDWORD dwFlags = g_pServerDE->GetObjectUserFlags(hObj);
  1043.         // Can this object be saved?
  1044.         if ((dwFlags & USRFLG_SAVEABLE) && (bSavePlayers || !IsPlayer(hObj)))
  1045.         {
  1046.             ObjectLink *ol = g_pServerDE->AddObjectToList(pObjectList, hObj);
  1047.             ol->m_hObject = hObj;
  1048.         }
  1049.  
  1050.         hObj = g_pServerDE->GetNextInactiveObject(hObj);
  1051.     }
  1052.  
  1053.     DDWORD dwSaveFlags = 0;
  1054.  
  1055.     if (bSaveConsole)
  1056.         dwSaveFlags |= SAVEOBJECTS_SAVEGAMECONSOLE | SAVEOBJECTS_SAVEPORTALS;
  1057.  
  1058.     if (g_pServerDE->SaveObjects(szSavePath, pObjectList, 0, dwSaveFlags) == DE_OK)
  1059.         bRet = DTRUE;
  1060.  
  1061.     g_pServerDE->RelinquishList(pObjectList);
  1062.  
  1063.     return bRet;
  1064. }
  1065.  
  1066.  
  1067. // ----------------------------------------------------------------------- //
  1068. //
  1069. //    ROUTINE:    CBloodServerShell::RestoreGame()
  1070. //
  1071. //    PURPOSE:    Restores a saved game
  1072. //
  1073. // ----------------------------------------------------------------------- //
  1074.  
  1075. DBOOL CBloodServerShell::RestoreGame(DBYTE bySaveType)
  1076. {
  1077.     if (!g_pServerDE) 
  1078.         return DFALSE;
  1079.  
  1080.     char szSavePath[MAX_PATH];
  1081.     
  1082.     _mbscpy((unsigned char*)szSavePath, (const unsigned char*)g_szSavePath);
  1083.     if (bySaveType == SAVETYPE_CURRENT)
  1084.         _mbscat((unsigned char*)szSavePath, (const unsigned char*)g_szCurrentSaveFile);
  1085.     else if (bySaveType == SAVETYPE_AUTO)
  1086.         _mbscat((unsigned char*)szSavePath, (const unsigned char*)g_szAutoSaveFile);
  1087.     else 
  1088.         return DFALSE;
  1089.  
  1090.     if (g_pServerDE->RestoreObjects(szSavePath, 0, RESTOREOBJECTS_RESTORETIME) != DE_OK)
  1091.         return DFALSE;
  1092.  
  1093.     return DTRUE;
  1094. }
  1095.  
  1096. /*
  1097. // ----------------------------------------------------------------------- //
  1098. //
  1099. //    ROUTINE:    CBloodServerShell::BuildSavePath()
  1100. //
  1101. //    PURPOSE:    Builds a path for a save file given a world file
  1102. //
  1103. // ----------------------------------------------------------------------- //
  1104.  
  1105. DBOOL CBloodServerShell::BuildSavePath(char *pBuffer, char *pFilename)
  1106. {
  1107.     if (!pBuffer && !pFilename)
  1108.         return DFALSE;
  1109.  
  1110.     // Build the filename path..
  1111.     // Remove leading slashes..
  1112.     while(*pFilename == '\\' || *pFilename == '/')
  1113.         pFilename++;
  1114.  
  1115.     _mbscpy((unsigned char*)pBuffer, (const unsigned char*)g_szSavePath);
  1116.  
  1117.     // Keep track of the position that the filename will be appended to
  1118.     char *pEnd = (char *)(pBuffer + _mbstrlen(pBuffer));
  1119.  
  1120.     _mbscat((unsigned char*)pBuffer, (const unsigned char*)pFilename);
  1121.  
  1122.     // Replace slashes in the filename with underscores.
  1123.     char *pSlash;
  1124.     while (pSlash = _mbschr((const unsigned char*)pEnd, (unsigned int)'\\'))
  1125.         *pSlash = '_';
  1126.  
  1127.     // ..and tack on the extension.
  1128.     _mbscat((unsigned char*)pBuffer, (const unsigned char*)".sav");
  1129.  
  1130.     return DTRUE;
  1131. }
  1132. */
  1133.  
  1134. // ----------------------------------------------------------------------- //
  1135. //
  1136. //    ROUTINE:    CBloodServerShell::KeepAliveSave()
  1137. //
  1138. //    PURPOSE:    Saves the state of player objects between levels
  1139. //
  1140. // ----------------------------------------------------------------------- //
  1141.  
  1142. DBOOL CBloodServerShell::KeepAliveSave()
  1143. {
  1144.     DBOOL bRet = DFALSE;
  1145.     if (!g_pServerDE) return bRet;
  1146.  
  1147.     char szSavePath[MAX_PATH];
  1148.  
  1149. #ifndef _DEMO
  1150.     _mbscpy((unsigned char*)szSavePath, (const unsigned char*)g_szSavePath);
  1151.     _mbscat((unsigned char*)szSavePath, (const unsigned char*)"Keep.sav");
  1152. #else
  1153.     _mbscpy((unsigned char*)szSavePath, (const unsigned char*)"Keep.sav");
  1154. #endif
  1155.  
  1156.     // Make a list of savable objects
  1157.     ObjectList* pObjectList = g_pServerDE->CreateObjectList();
  1158.  
  1159.     HCLASS hPlayerTest = g_pServerDE->GetClass("CPlayerObj");
  1160.  
  1161.     HOBJECT hObj = g_pServerDE->GetNextObject(DNULL);
  1162.  
  1163.     while (hObj)
  1164.     {
  1165.         if (IsPlayer(hObj))
  1166.         {
  1167.             ObjectLink *ol = g_pServerDE->AddObjectToList(pObjectList, hObj);
  1168.             ol->m_hObject = hObj;
  1169.         }
  1170.  
  1171.         hObj = g_pServerDE->GetNextObject(hObj);
  1172.     }
  1173.  
  1174.     if (g_pServerDE->SaveObjects(szSavePath, pObjectList, 1, 0 ) == DE_OK)
  1175.         bRet = DTRUE;
  1176.  
  1177.     g_pServerDE->RelinquishList(pObjectList);
  1178.  
  1179.     return bRet;
  1180. }
  1181.  
  1182.  
  1183. // ----------------------------------------------------------------------- //
  1184. //
  1185. //    ROUTINE:    CBloodServerShell::KeepAliveLoad()
  1186. //
  1187. //    PURPOSE:    Restores player data saved when switching levels
  1188. //
  1189. // ----------------------------------------------------------------------- //
  1190.  
  1191. DBOOL CBloodServerShell::KeepAliveLoad()
  1192. {
  1193.     if (!g_pServerDE) return DFALSE;
  1194.  
  1195.     char szSavePath[MAX_PATH];
  1196.  
  1197. #ifndef _DEMO
  1198.     _mbscpy((unsigned char*)szSavePath, (const unsigned char*)g_szSavePath);
  1199.     _mbscat((unsigned char*)szSavePath, (const unsigned char*)"Keep.sav");
  1200. #else
  1201.     _mbscpy((unsigned char*)szSavePath, (const unsigned char*)"Keep.sav");
  1202. #endif
  1203.  
  1204.     if (g_pServerDE->RestoreObjects(szSavePath, 1, 0) != DE_OK)
  1205.         return DFALSE;
  1206.  
  1207.     return DTRUE;
  1208. }
  1209.  
  1210.  
  1211. // ----------------------------------------------------------------------- //
  1212. //
  1213. //    ROUTINE:    CBloodServerShell::SetGameDifficulty()
  1214. //
  1215. //    PURPOSE:    Sets game info console vars for difficulty level
  1216. //
  1217. // ----------------------------------------------------------------------- //
  1218.  
  1219. void CBloodServerShell::SetGameInfo(DBYTE nGameType, DBYTE nDifficulty)
  1220. {
  1221.     if (!g_pServerDE) return;
  1222.  
  1223.     char szValue[20];
  1224.  
  1225.     _itoa(nGameType, szValue, 10);
  1226.     g_pServerDE->SetGameConVar(g_szVarGameType, szValue);
  1227.  
  1228.     _itoa(nDifficulty, szValue, 10);
  1229.     g_pServerDE->SetGameConVar(g_szVarDifficulty, szValue);
  1230. }
  1231.  
  1232.  
  1233. // ----------------------------------------------------------------------- //
  1234. //
  1235. //    ROUTINE:    CBloodServerShell::CacheFiles()
  1236. //
  1237. //    PURPOSE:    Cache files that are used often
  1238. //
  1239. // ----------------------------------------------------------------------- //
  1240.  
  1241. void CBloodServerShell::CacheFiles()
  1242. {
  1243.     // Cache models...
  1244.     for (int i=0; i < NUM_CACHED_MODELS; i++)
  1245.     {
  1246.         g_pServerDE->CacheFile(FT_MODEL, g_pCachedModels[i]);
  1247.     }
  1248.  
  1249.     // Cache textures...
  1250.  
  1251.     for (i=0; i < NUM_CACHED_TEXTURES; i++)
  1252.     {
  1253.         g_pServerDE->CacheFile(FT_TEXTURE, g_pCachedTextures[i]);
  1254.     }
  1255.  
  1256.     // Cache sprites...
  1257.  
  1258.     for (i=0; i < NUM_CACHED_SPRITES; i++)
  1259.     {
  1260.         g_pServerDE->CacheFile(FT_SPRITE, g_pCachedSprite[i]);
  1261.     }
  1262.  
  1263.     // Cache sounds...
  1264.  
  1265.     for (i=0; i < NUM_CACHED_SOUNDS_LOCAL; i++)
  1266.     {
  1267.         g_pServerDE->CacheFile(FT_SOUND, g_pCachedSoundLocal[i]);
  1268.     }
  1269.  
  1270.     for (i=0; i < NUM_CACHED_SOUNDS_AMBIENT; i++)
  1271.     {
  1272.         g_pServerDE->CacheFile(FT_SOUND, g_pCachedSoundAmbient[i]);
  1273.     }
  1274.  
  1275.     for (i=0; i < NUM_CACHED_SOUNDS_3D; i++)
  1276.     {
  1277.         g_pServerDE->CacheFile(FT_SOUND, g_pCachedSound3D[i]);
  1278.     }
  1279. }
  1280.  
  1281.  
  1282. // ----------------------------------------------------------------------- //
  1283. //
  1284. //    ROUTINE:    CBloodServerShell::AddClientToList
  1285. //
  1286. //    PURPOSE:    Adds the given client handle to our local list
  1287. //
  1288. // ----------------------------------------------------------------------- //
  1289.  
  1290. DBOOL CBloodServerShell::AddClientToList(HCLIENT hClient)
  1291. {
  1292.     // Sanity checks...
  1293.  
  1294.     if (!hClient) return(DFALSE);
  1295.  
  1296.  
  1297.     // Make sure this client isn't already in our list...
  1298.  
  1299.     if (IsClientInList(hClient))
  1300.     {
  1301.         return(DTRUE);
  1302.     }
  1303.  
  1304.  
  1305.     // Add this client handle to our array...
  1306.  
  1307.     for (int i = 0; i < MAX_CLIENTS; i++)
  1308.     {
  1309.         if (m_aClients[i] == DNULL)
  1310.         {
  1311.             m_aClients[i] = hClient;
  1312.             return(DTRUE);
  1313.         }
  1314.     }
  1315.  
  1316.  
  1317.     // If we get here, there wasn't any space left in the array...
  1318.  
  1319.     return(DFALSE);
  1320. }
  1321.  
  1322.  
  1323. // ----------------------------------------------------------------------- //
  1324. //
  1325. //    ROUTINE:    CBloodServerShell::RemoveClientFromList
  1326. //
  1327. //    PURPOSE:    Adds the given client handle to our local list
  1328. //
  1329. // ----------------------------------------------------------------------- //
  1330.  
  1331. DBOOL CBloodServerShell::RemoveClientFromList(HCLIENT hClient)
  1332. {
  1333.     // Sanity checks...
  1334.  
  1335.     if (!hClient) return(DFALSE);
  1336.  
  1337.  
  1338.     // Remove this client handle from our array...
  1339.  
  1340.     for (int i = 0; i < MAX_CLIENTS; i++)
  1341.     {
  1342.         if (m_aClients[i] == hClient)
  1343.         {
  1344.             m_aClients[i] = DNULL;
  1345.             return(DTRUE);
  1346.         }
  1347.     }
  1348.  
  1349.  
  1350.     // If we get here, we didn't find the given client handle in the array...
  1351.  
  1352.     return(DFALSE);
  1353. }
  1354.  
  1355.  
  1356. // ----------------------------------------------------------------------- //
  1357. //
  1358. //    ROUTINE:    CBloodServerShell::IsClientInList
  1359. //
  1360. //    PURPOSE:    Determines if the given client handle is in our list
  1361. //
  1362. // ----------------------------------------------------------------------- //
  1363.  
  1364. DBOOL CBloodServerShell::IsClientInList(HCLIENT hClient)
  1365. {
  1366.     // Sanity checks...
  1367.  
  1368.     if (!hClient) return(DFALSE);
  1369.  
  1370.  
  1371.     // Look for this client handle in our array...
  1372.  
  1373.     for (int i = 0; i < MAX_CLIENTS; i++)
  1374.     {
  1375.         if (m_aClients[i] == hClient)
  1376.         {
  1377.             return(DTRUE);
  1378.         }
  1379.     }
  1380.  
  1381.  
  1382.     // If we get here, we didn't find the given client handle in the array...
  1383.  
  1384.     return(DFALSE);
  1385. }
  1386.  
  1387.  
  1388. // ----------------------------------------------------------------------- //
  1389. //
  1390. //    ROUTINE:    CBloodServerShell::GetPlayerFromClientList
  1391. //
  1392. //    PURPOSE:    Adds the given client handle to our local list
  1393. //
  1394. // ----------------------------------------------------------------------- //
  1395.  
  1396. CPlayerObj*    CBloodServerShell::GetPlayerFromClientList(HCLIENT hClient)
  1397. {
  1398.     // Sanity checks...
  1399.  
  1400.     if (!hClient) return(DNULL);
  1401.     if (!g_pServerDE) return(DNULL);
  1402.  
  1403.  
  1404.     // Remove this client handle from our array...
  1405.  
  1406.     for (int i = 0; i < MAX_CLIENTS; i++)
  1407.     {
  1408.         if (m_aClients[i] == hClient)
  1409.         {
  1410.             CPlayerObj* pPlayer = (CPlayerObj*)g_pServerDE->GetClientUserData(hClient);
  1411.             return(pPlayer);
  1412.         }
  1413.     }
  1414.  
  1415.  
  1416.     // If we get here, we didn't find the given client handle in the array...
  1417.  
  1418.     return(DNULL);
  1419. }
  1420.  
  1421.  
  1422. // ----------------------------------------------------------------------- //
  1423. //
  1424. //    ROUTINE:    CBloodServerShell::SetupGameInfo
  1425. //
  1426. //    PURPOSE:    Setup game info
  1427. //
  1428. // ----------------------------------------------------------------------- //
  1429.  
  1430. void CBloodServerShell::SetupGameInfo()
  1431. {
  1432.     if (g_pServerDE)
  1433.     {
  1434.         NetGame* pGameInfo;
  1435.         DDWORD dwLen = sizeof(NetGame);
  1436.         g_pServerDE->GetGameInfo((void**)&pGameInfo, &dwLen);
  1437.  
  1438.         if (pGameInfo)
  1439.         {
  1440.             memcpy(&m_GameInfo, pGameInfo, sizeof(NetGame));
  1441.         }
  1442.     }
  1443. }
  1444.  
  1445.  
  1446. // ----------------------------------------------------------------------- //
  1447. //
  1448. //    ROUTINE:    CBloodServerShell::Update
  1449. //
  1450. //    PURPOSE:    Update servier stuff periodically
  1451. //
  1452. // ----------------------------------------------------------------------- //
  1453.  
  1454. void CBloodServerShell::Update(DFLOAT timeElapsed)
  1455. {
  1456.     // Sanity checks...
  1457.  
  1458.     if (!g_pServerDE || GetGameType() == GAMETYPE_SINGLE) return;
  1459.  
  1460.  
  1461.     // Update the client ping times...
  1462.  
  1463.     UpdateClientPingTimes();
  1464.  
  1465.  
  1466.     // Check for a say message...
  1467.  
  1468.     if (!g_SayTrack.IsInitted())
  1469.     {
  1470.         g_SayTrack.Init(g_pServerDE, "Say", "", 0.0f);
  1471.     }
  1472.     else
  1473.     {
  1474.         char *sSay = g_SayTrack.GetStr("");
  1475.  
  1476.         if (sSay && sSay[0] != 0)
  1477.         {
  1478.             char sMsg[512];
  1479.             sprintf(sMsg, "HOST: %s", sSay);
  1480.             HMESSAGEWRITE hMessage = g_pServerDE->StartMessage(DNULL, SMSG_CONSOLEMESSAGE_ALL);
  1481.             g_pServerDE->WriteToMessageString(hMessage, sMsg);
  1482.             g_pServerDE->EndMessage2(hMessage, MESSAGE_NAGGLE);
  1483.             
  1484.             g_SayTrack.SetStr("");
  1485.         }
  1486.     }
  1487.  
  1488.  
  1489.     // Setup a static timer for session name updates...
  1490.  
  1491.     static DFLOAT timerUpdateName = 5;
  1492.  
  1493.  
  1494.     // Update our time and see if it's time to update the session name...
  1495.  
  1496.     if (timeElapsed < timerUpdateName)
  1497.     {
  1498.         timerUpdateName -= timeElapsed;
  1499.     }
  1500.     else
  1501.     {
  1502.         timerUpdateName = 10;
  1503.         UpdateSessionName();
  1504.     }
  1505.  
  1506.  
  1507.     // Update shogo server info...
  1508.  
  1509.     UpdateBlood2Server();
  1510.  
  1511.  
  1512.     // Update multiplayer stuff...
  1513.  
  1514.     UpdateMultiplayer();
  1515. }
  1516.  
  1517.  
  1518. // ----------------------------------------------------------------------- //
  1519. //
  1520. //    ROUTINE:    CBloodServerShell::UpdateSessionName
  1521. //
  1522. //    PURPOSE:    Updates the name of the session with current game info
  1523. //
  1524. // ----------------------------------------------------------------------- //
  1525.  
  1526. DBOOL CBloodServerShell::UpdateSessionName()
  1527. {
  1528.     // Get the current session name...
  1529.  
  1530.     static char sSession[4096];
  1531.  
  1532.     DRESULT dr = g_pServerDE->GetSessionName(sSession, 4096);
  1533.     if (dr != LT_OK) return(DFALSE);
  1534.  
  1535.  
  1536.     // Extract the info we want to keep...
  1537.  
  1538.     char sName[NML_NAME];
  1539.     if (!Sparam_Get(sName, sSession, NST_GAMENAME)) return(DFALSE);
  1540.  
  1541.     char sHost[NML_HOST];
  1542.     if (!Sparam_Get(sHost, sSession, NST_GAMEHOST)) return(DFALSE);
  1543.  
  1544.     char sType[32];
  1545.     if (!Sparam_Get(sType, sSession, NST_GAMETYPE)) return(DFALSE);
  1546.  
  1547.     
  1548.     // Get the base level name...
  1549.  
  1550.     char sLevel[128];
  1551.     _mbscpy((unsigned char*)sLevel, (const unsigned char*)m_GameInfo.m_sLevels[m_nCurLevel]);
  1552.  
  1553.  
  1554.     // Clear the session string now that we have the info we want from it...
  1555.  
  1556.     sSession[0] = '\0';
  1557.  
  1558.  
  1559.     // Add the info we kept...
  1560.  
  1561.     Sparam_Add(sSession, NST_GAMENAME, sName);
  1562.     Sparam_Add(sSession, NST_GAMEHOST, sHost);
  1563.     Sparam_Add(sSession, NST_GAMELEVEL, sLevel);
  1564.     Sparam_Add(sSession, NST_GAMETYPE, sType);
  1565.  
  1566.  
  1567.     // Add info for each player...
  1568.  
  1569.     int count = 0;
  1570.  
  1571.     for (int i = 0; i < MAX_CLIENTS; i++)
  1572.     {
  1573.         CPlayerObj* pPlayer = GetPlayerFromClientList(m_aClients[i]);
  1574.  
  1575.         if (pPlayer)
  1576.         {
  1577.             HSTRING hstrName = pPlayer->GetPlayerName();
  1578.             char* pName = hstrName ? g_pServerDE->GetStringData(hstrName) : "";
  1579.  
  1580.             count++;
  1581.             char sBase[32];
  1582.  
  1583.             sprintf(sBase, "%s%i", NST_PLRNAME_BASE, count);
  1584.             Sparam_Add(sSession, sBase, pName);
  1585.  
  1586.             sprintf(sBase, "%s%i", NST_PLRFRAG_BASE, count);
  1587.             Sparam_Add(sSession, sBase, pPlayer->GetFrags());
  1588.         }
  1589.     }
  1590.  
  1591.     Sparam_Add(sSession, NST_PLRCOUNT, count);
  1592.  
  1593.  
  1594.     // Update the session name...
  1595.  
  1596.     g_pServerDE->UpdateSessionName(sSession);
  1597.  
  1598.  
  1599.     // All done...
  1600.  
  1601.     return(DTRUE);
  1602. }
  1603.  
  1604.  
  1605. // ----------------------------------------------------------------------- //
  1606. //
  1607. //    ROUTINE:    CBloodServerShell::UpdateBlood2Server
  1608. //
  1609. //    PURPOSE:    Updates a stand-alone server with game info if necessary
  1610. //
  1611. // ----------------------------------------------------------------------- //
  1612.  
  1613. DBOOL CBloodServerShell::UpdateBlood2Server()
  1614. {
  1615.     // Check if we need to update...
  1616.  
  1617.     if (!m_bUpdateBlood2Serv)
  1618.     {
  1619.         return(DFALSE);
  1620.     }
  1621.  
  1622.     m_bUpdateBlood2Serv = FALSE;
  1623.  
  1624.  
  1625.     // Make sure we are actually being hosted via ShogoServ...
  1626.  
  1627.     if (!m_bBlood2ServHosted)
  1628.     {
  1629.         return(DFALSE);
  1630.     }
  1631.  
  1632.  
  1633.     // Get the current base level name...
  1634.  
  1635.     char sCurLevel[128];
  1636.     _mbscpy((unsigned char*)sCurLevel, (const unsigned char*)m_GameInfo.m_sLevels[m_nCurLevel]);
  1637.  
  1638.  
  1639.     // Get the next base level name...
  1640.  
  1641.     char sNextLevel[128];
  1642.     int  i = m_nCurLevel + 1;
  1643.     if (i >= m_GameInfo.m_byNumLevels) i = 0;
  1644.     _mbscpy((unsigned char*)sNextLevel, (const unsigned char*)m_GameInfo.m_sLevels[i]);
  1645.  
  1646.  
  1647.     // Declare the string...
  1648.  
  1649.     static    char sInfo[4096];
  1650.     sInfo[0] = '\0';
  1651.  
  1652.  
  1653.     // Flag that this is a standard update message...
  1654.  
  1655.     Sparam_Add(sInfo, "GMSG", NGM_STANDARDUPDATE);
  1656.  
  1657.  
  1658.     // Add the levels...
  1659.  
  1660.     Sparam_Add(sInfo, NST_CURLEVEL, sCurLevel);
  1661.     Sparam_Add(sInfo, NST_NEXTLEVEL, sNextLevel);
  1662.  
  1663.  
  1664.     // Add info for each player...
  1665.  
  1666.     int count = 0;
  1667.  
  1668.     for (i = 0; i < MAX_CLIENTS; i++)
  1669.     {
  1670.         CPlayerObj* pPlayer = GetPlayerFromClientList(m_aClients[i]);
  1671.         if (pPlayer)
  1672.         {
  1673.             HSTRING hstrName = pPlayer->GetPlayerName();
  1674.             char* pName = hstrName ? g_pServerDE->GetStringData(hstrName) : "";
  1675.  
  1676.             count++;
  1677.             char sBase[32];
  1678.  
  1679.             sprintf(sBase, "%s%i", NST_PLRNAME_BASE, count);
  1680.             Sparam_Add(sInfo, sBase, pName);
  1681.  
  1682.             sprintf(sBase, "%s%i", NST_PLRFRAG_BASE, count);
  1683.             Sparam_Add(sInfo, sBase, pPlayer->GetFrags());
  1684.  
  1685.             HCLIENT hClient = pPlayer->GetClient();
  1686.             if (hClient)
  1687.             {
  1688.                 sprintf(sBase, "%s%i", NST_PLRID_BASE, count);
  1689.                 Sparam_Add(sInfo, sBase, g_pServerDE->GetClientID(hClient));
  1690.             }
  1691.         }
  1692.     }
  1693.  
  1694.     Sparam_Add(sInfo, NST_PLRCOUNT, count);
  1695.  
  1696.  
  1697.     // Pass this info to the Shogo Server...
  1698.  
  1699.     g_pServerDE->SendToServerApp(sInfo);
  1700.  
  1701.  
  1702.     // All done...
  1703.  
  1704.     return(DTRUE);
  1705. }
  1706.  
  1707.  
  1708. // ----------------------------------------------------------------------- //
  1709. //
  1710. //    ROUTINE:    CBloodServerShell::UpdateMultiplayer
  1711. //
  1712. //    PURPOSE:    Determine if it is time to change levels
  1713. //
  1714. // ----------------------------------------------------------------------- //
  1715.  
  1716. void CBloodServerShell::UpdateMultiplayer()
  1717. {
  1718.     if (!g_pServerDE || GetGameType() == GAMETYPE_SINGLE) return;
  1719.     
  1720.     DBOOL bStartLevel = DFALSE;
  1721.  
  1722.     if (m_GameInfo.m_byEnd == NGE_TIME ||
  1723.         m_GameInfo.m_byEnd == NGE_FRAGSANDTIME)
  1724.     {
  1725.         DFLOAT fEndLevelTime = (m_GameInfo.m_dwEndTime * 60.0f);
  1726.         DFLOAT fTime = g_pServerDE->GetTime();
  1727.  
  1728.         if (fTime >= fEndLevelTime)
  1729.         {
  1730.             bStartLevel = DTRUE;
  1731.         }
  1732.     }
  1733.  
  1734.     if ( !bStartLevel && 
  1735.          (m_GameInfo.m_byEnd == NGE_FRAGS || 
  1736.           m_GameInfo.m_byEnd == NGE_FRAGSANDTIME) )
  1737.     {
  1738.         if (IsMultiplayerTeamBasedGame())
  1739.         {
  1740.             CTeam* pTeam = m_TeamMgr.GetFirstTeam();
  1741.  
  1742.             while (pTeam)
  1743.             {
  1744.                 if (pTeam->GetFrags() >= (int)m_GameInfo.m_dwEndFrags)
  1745.                 {
  1746.                     bStartLevel = DTRUE;
  1747.                     break;
  1748.                 }
  1749.  
  1750.                 pTeam = m_TeamMgr.GetNextTeam(pTeam);
  1751.             }
  1752.         }
  1753.         else
  1754.         {
  1755.             for (int i = 0; i < MAX_CLIENTS; i++)
  1756.             {
  1757.                 CPlayerObj* pPlayer = GetPlayerFromClientList(m_aClients[i]);
  1758.                 if (pPlayer)
  1759.                 {
  1760.                     if (pPlayer->GetFrags() >= (int)m_GameInfo.m_dwEndFrags)
  1761.                     {
  1762.                         bStartLevel = DTRUE;
  1763.                         break;
  1764.                     }
  1765.                 }
  1766.             }
  1767.         }
  1768.     }
  1769.  
  1770.     if (g_bWaitToStartNextLevel)
  1771.     {
  1772.         if(g_pServerDE->GetTime() - g_fWaitTimeForNextLevel > WAIT_TIME_FOR_LEVEL_SWITCH)
  1773.         {
  1774.             g_bWaitToStartNextLevel = DFALSE;
  1775.             StartNextMultiplayerLevelAck();
  1776.         }
  1777.         return;
  1778.     }
  1779.  
  1780.     if (g_bNextLevel)
  1781.     {
  1782.         bStartLevel = DTRUE;
  1783.     }
  1784.  
  1785.     if (bStartLevel)
  1786.     {
  1787.         StartNextMultiplayerLevel();
  1788.         g_bNextLevel = DFALSE;
  1789.     }
  1790. }
  1791.  
  1792.  
  1793. // ----------------------------------------------------------------------- //
  1794. //
  1795. //    ROUTINE:    CBloodServerShell::StartNextMultiplayerLevel
  1796. //
  1797. //    PURPOSE:    Start the next multiplayer level
  1798. //
  1799. // ----------------------------------------------------------------------- //
  1800.  
  1801. void CBloodServerShell::StartNextMultiplayerLevel()
  1802. {
  1803.     // Tell the server that we're changing the level...
  1804. /*
  1805.     char sInfo[1024];
  1806.     sInfo[0] = '\0';
  1807.  
  1808.     Sparam_Add(sInfo, NST_GENERICMESSAGE, NGM_LEVELCHANGING);
  1809.     g_pServerDE->SendToServerApp(sInfo);
  1810. */
  1811.  
  1812.     // Tell all clients we're changing levels...
  1813.  
  1814.     HMESSAGEWRITE hWrite = g_pServerDE->StartMessage(DNULL, SMSG_MP_CHANGING_LEVELS);
  1815.     g_pServerDE->EndMessage(hWrite);
  1816.  
  1817.     g_bWaitToStartNextLevel = DTRUE;
  1818.     g_fWaitTimeForNextLevel = g_pServerDE->GetTime();
  1819.  
  1820.  
  1821.     // Clear player frags...
  1822. /*
  1823.     for (int i = 0; i < MAX_CLIENTS; i++)
  1824.     {
  1825.         CPlayerObj* pPlayer = GetPlayerFromClientList(m_aClients[i]);
  1826.         if (pPlayer)
  1827.         {
  1828.             pPlayer->SetFrags(0);
  1829.         }
  1830.     }
  1831.  
  1832.  
  1833.     // Stop voice mgr stuff...
  1834.  
  1835.     m_VoiceMgr.StopAll();
  1836.  
  1837.  
  1838.     // Create the transition team id list so we can properly restore the teams...
  1839.  
  1840.     m_TeamMgr.CreateTeamTransIDs();
  1841.  
  1842.  
  1843.     // Load the next level...
  1844.     
  1845.     if (++m_nCurLevel >= m_GameInfo.m_byNumLevels)
  1846.     {
  1847.         m_nCurLevel = 0;
  1848.     }
  1849.  
  1850.     char* pLevelName = m_GameInfo.m_sLevels[m_nCurLevel];
  1851.     if (pLevelName)
  1852.     {
  1853.         g_pServerDE->LoadWorld(pLevelName, LOADWORLD_LOADWORLDOBJECTS | LOADWORLD_RUNWORLD);
  1854.     }
  1855.     else
  1856.     {
  1857.         g_pServerDE->BPrint("ERROR CAN'T START NEXT MULTIPLAYER LEVEL!");
  1858.     }
  1859.  
  1860.  
  1861.     // Tell the shogo server that we changed the level...
  1862.  
  1863.     sInfo[0] = '\0';
  1864.  
  1865.     Sparam_Add(sInfo, NST_GENERICMESSAGE, NGM_LEVELCHANGED);
  1866.  
  1867.     char sCurLevel[128];
  1868.     _mbscpy((unsigned char*)sCurLevel, (const unsigned char*)m_GameInfo.m_sLevels[m_nCurLevel]);
  1869.  
  1870.     char sNextLevel[128];
  1871.     i = m_nCurLevel + 1;
  1872.     if (i >= m_GameInfo.m_byNumLevels) i = 0;
  1873.     _mbscpy((unsigned char*)sNextLevel, (const unsigned char*)m_GameInfo.m_sLevels[i]);
  1874.  
  1875.     Sparam_Add(sInfo, NST_CURLEVEL, sCurLevel);
  1876.     Sparam_Add(sInfo, NST_NEXTLEVEL, sNextLevel);
  1877.  
  1878.     g_pServerDE->SendToServerApp(sInfo);*/
  1879. }
  1880.  
  1881.  
  1882. // ----------------------------------------------------------------------- //
  1883. //
  1884. //    ROUTINE:    CBloodServerShell::StartNextMultiplayerLevelAck
  1885. //
  1886. //    PURPOSE:    Start the next multiplayer level
  1887. //
  1888. // ----------------------------------------------------------------------- //
  1889.  
  1890. void CBloodServerShell::StartNextMultiplayerLevelAck()
  1891. {
  1892.     // Tell the shogo server that we're changing the level...
  1893.  
  1894.     char sInfo[1024];
  1895.     sInfo[0] = '\0';
  1896.  
  1897.     Sparam_Add(sInfo, NST_GENERICMESSAGE, NGM_LEVELCHANGING);
  1898.     g_pServerDE->SendToServerApp(sInfo);
  1899.  
  1900.  
  1901.     // Clear player frags...
  1902.     for (int i = 0; i < MAX_CLIENTS; i++)
  1903.     {
  1904.         CPlayerObj* pPlayer = GetPlayerFromClientList(m_aClients[i]);
  1905.         if (pPlayer)
  1906.             pPlayer->SetFrags(0);
  1907.     }
  1908.  
  1909.  
  1910.     // Stop voice mgr stuff...
  1911.     m_VoiceMgr.StopAll();
  1912.  
  1913.  
  1914.     // Create the transition team id list so we can properly restore the teams...
  1915.     m_TeamMgr.CreateTeamTransIDs();
  1916.  
  1917.  
  1918.     // Load the next level...
  1919.     if (++m_nCurLevel >= m_GameInfo.m_byNumLevels)
  1920.         m_nCurLevel = 0;
  1921.  
  1922.  
  1923.     char* pLevelName = m_GameInfo.m_sLevels[m_nCurLevel];
  1924.     if (pLevelName)
  1925.         g_pServerDE->LoadWorld(pLevelName, LOADWORLD_LOADWORLDOBJECTS | LOADWORLD_RUNWORLD);
  1926.     else
  1927.         g_pServerDE->BPrint("ERROR CAN'T START NEXT MULTIPLAYER LEVEL!");
  1928.  
  1929.  
  1930.     // Tell the shogo server that we changed the level...
  1931.     sInfo[0] = '\0';
  1932.  
  1933.     Sparam_Add(sInfo, NST_GENERICMESSAGE, NGM_LEVELCHANGED);
  1934.  
  1935.     char sCurLevel[128];
  1936.     _mbscpy((unsigned char*)sCurLevel, (const unsigned char*)m_GameInfo.m_sLevels[m_nCurLevel]);
  1937.  
  1938.     char sNextLevel[128];
  1939.     i = m_nCurLevel + 1;
  1940.     if (i >= m_GameInfo.m_byNumLevels) i = 0;
  1941.     _mbscpy((unsigned char*)sNextLevel, (const unsigned char*)m_GameInfo.m_sLevels[i]);
  1942.  
  1943.     Sparam_Add(sInfo, NST_CURLEVEL, sCurLevel);
  1944.     Sparam_Add(sInfo, NST_NEXTLEVEL, sNextLevel);
  1945.  
  1946.     g_pServerDE->SendToServerApp(sInfo);
  1947. }
  1948.  
  1949.  
  1950. // ----------------------------------------------------------------------- //
  1951. //
  1952. //    ROUTINE:    CBloodServerShell::ServerAppMessageFn
  1953. //
  1954. //    PURPOSE:    Server app message function
  1955. //
  1956. // ----------------------------------------------------------------------- //
  1957.  
  1958. DRESULT CBloodServerShell::ServerAppMessageFn(char* sMsg)
  1959. {
  1960.     // Sanity checks...
  1961.  
  1962.     if (!sMsg) return(LT_OK);
  1963.  
  1964.  
  1965.     // Check for "GAMEINIT" message...
  1966.  
  1967.     if (_mbscmp((const unsigned char*)sMsg, (const unsigned char*)"GAMEINIT") == 0)
  1968.     {
  1969.         SetupGameInfo();
  1970.     }
  1971.     else if (_mbscmp((const unsigned char*)sMsg, (const unsigned char*)"NEXTLEVEL") == 0)
  1972.     {
  1973.         StartNextMultiplayerLevel();
  1974.     }
  1975.     else if (_mbscmp((const unsigned char*)sMsg, (const unsigned char*)"SERVHOST") == 0)
  1976.     {
  1977.         m_bBlood2ServHosted = DTRUE;
  1978.     }
  1979.  
  1980.  
  1981.     // All done...
  1982.  
  1983.     return(LT_OK);
  1984. }
  1985.  
  1986.  
  1987. // ----------------------------------------------------------------------- //
  1988. //
  1989. //    ROUTINE:    CBloodServerShell::SendBlood2ServConsoleMessage
  1990. //
  1991. //    PURPOSE:    Sends a string to be displayed in the ShogoServ console
  1992. //
  1993. // ----------------------------------------------------------------------- //
  1994.  
  1995. void CBloodServerShell::SendBlood2ServConsoleMessage(char* sMsg)
  1996. {
  1997.     if (!sMsg || !m_bBlood2ServHosted) return;
  1998.  
  1999.     char sInfo[1024];
  2000.     sInfo[0] = '\0';
  2001.  
  2002.     Sparam_Add(sInfo, NST_GENERICMESSAGE, NGM_CONSOLEMSG);
  2003.     Sparam_Add(sInfo, NST_CONSOLEMESSAGE, sMsg);
  2004.  
  2005.     g_pServerDE->SendToServerApp(sInfo);
  2006. }
  2007.  
  2008.  
  2009. // ----------------------------------------------------------------------- //
  2010. //
  2011. //    ROUTINE:    CBloodServerShell::FindClient
  2012. //
  2013. //    PURPOSE:    Goes through the client list and checks for a player
  2014. //                represented by hObject. Returns the HCLIENT if it's still an 
  2015. //                active player.
  2016. //
  2017. // ----------------------------------------------------------------------- //
  2018.  
  2019. HCLIENT CBloodServerShell::FindClient(HOBJECT hObject)
  2020. {
  2021.     if (!g_pServerDE) return DFALSE;
  2022.  
  2023.     for (int i = 0; i < MAX_CLIENTS; i++)
  2024.     {
  2025.         if (m_aClients[i])
  2026.         {
  2027.             CPlayerObj *pObj = (CPlayerObj*)g_pServerDE->GetClientUserData(m_aClients[i]);
  2028.             if (pObj && pObj->m_hObject == hObject)
  2029.                 return m_aClients[i];
  2030.         }
  2031.     }
  2032.     return DNULL;
  2033. }
  2034.  
  2035.  
  2036. // ----------------------------------------------------------------------- //
  2037. //
  2038. //    ROUTINE:    CBloodServerShell::UpdateClientPingTimes
  2039. //
  2040. //    PURPOSE:    Updates each client with all client ping times
  2041. //
  2042. // ----------------------------------------------------------------------- //
  2043.  
  2044. void CBloodServerShell::UpdateClientPingTimes()
  2045. {
  2046.     HMESSAGEWRITE hWrite;
  2047.     float ping;
  2048.     DDWORD clientID;
  2049.     HCLIENT hClient;
  2050.     
  2051.     ServerDE *pServerDE = g_pServerDE;
  2052.     if(!pServerDE) return;
  2053.  
  2054.     static DFLOAT fPingUpdateCounter = 0.0f;
  2055.  
  2056.     fPingUpdateCounter += pServerDE->GetFrameTime();
  2057.     if(fPingUpdateCounter > CLIENT_PING_UPDATE_RATE)
  2058.     {
  2059.         hWrite = pServerDE->StartMessage(DNULL, SMSG_PINGTIMES);
  2060.         
  2061.             hClient = DNULL;
  2062.             while(hClient = pServerDE->GetNextClient(hClient))
  2063.             {
  2064.                 clientID = pServerDE->GetClientID(hClient);
  2065.                 pServerDE->GetClientPing(hClient, ping);
  2066.  
  2067.                 pServerDE->WriteToMessageWord(hWrite, (D_WORD)clientID);
  2068.                 pServerDE->WriteToMessageWord(hWrite, (D_WORD)(ping * 1000.0f));
  2069.             }
  2070.  
  2071.         pServerDE->WriteToMessageWord(hWrite, 0xFFFF);
  2072.         pServerDE->EndMessage2(hWrite, MESSAGE_NAGGLE);
  2073.  
  2074.         fPingUpdateCounter = 0.0f;
  2075.     }
  2076. }
  2077.  
  2078. // ----------------------------------------------------------------------- //
  2079. //
  2080. //    ROUTINE:    CBloodServerShell::DoLevelChangeCharacterCheck
  2081. //
  2082. //    PURPOSE:    Updates each client with all client ping times
  2083. //
  2084. // ----------------------------------------------------------------------- //
  2085.  
  2086. void CBloodServerShell::DoLevelChangeCharacterCheck(char* sLevel)
  2087. {
  2088.     g_bLevelChangeCharacter = DFALSE;
  2089.  
  2090. #ifndef _ADDON
  2091.     return;
  2092. #endif
  2093.  
  2094.     char sUpr[256];
  2095.     strncpy(sUpr, sLevel, 255);
  2096.     strupr(sUpr);
  2097.  
  2098.     if (strstr(sUpr, "_AO"))            // is this an add-on level?
  2099.     {
  2100.         if (strstr(sUpr, "_CC_C"))        // switch to caleb?
  2101.         {
  2102.             g_bLevelChangeCharacter = DTRUE;
  2103.             g_nLevelChangeCharacter = CHARACTER_CALEB;
  2104.         }
  2105.         else if (strstr(sUpr, "_CC_I"))    // switch to ishmael?
  2106.         {
  2107.             g_bLevelChangeCharacter = DTRUE;
  2108.             g_nLevelChangeCharacter = CHARACTER_ISHMAEL;
  2109.         }
  2110.         else if (strstr(sUpr, "_CC_O"))    // switch to ophelia?
  2111.         {
  2112.             g_bLevelChangeCharacter = DTRUE;
  2113.             g_nLevelChangeCharacter = CHARACTER_OPHELIA;
  2114.         }
  2115.         else if (strstr(sUpr, "_CC_G"))    // switch to gabby?
  2116.         {
  2117.             g_bLevelChangeCharacter = DTRUE;
  2118.             g_nLevelChangeCharacter = CHARACTER_GABREILLA;
  2119.         }
  2120.  
  2121.         // check for the last level...
  2122.  
  2123.         if (strstr(sUpr, "ENDBOSS_CC_C"))    // check for final caleb nightmare level
  2124.         {
  2125.             g_bLevelChangeCharacter = DFALSE;
  2126.         }
  2127.     }
  2128. }
  2129.  
  2130.