Recent Posts
None | 9 sec ago
Java | 13 sec ago
None | 31 sec ago
None | 34 sec ago
C++ | 36 sec ago
None | 39 sec ago
Python | 45 sec ago
None | 53 sec ago
None | 1 min ago
None | 1 min ago
Sitereport
Find cool info about any domain on the internet?
visit sitereport
Free Subdomains
Want a pastebin.com sub-domain for your community?
learn more...
What is pastebin?
Pastebin is a website that hosts all your text & code on dedicated servers for easy sharing.
learn more...
Learn a little bit about the new Pastebin.com on our help page. hide message
By Anonymous on the 9th of Feb 2010 10:55:09 PM Download | Raw | Embed | Report
  1. ////////////////////////
  2. //To do prior to 1.0 release
  3. //
  4. ////////////////////////
  5. // Nitnoid
  6. // Make color defs below constant... need to change associated externs too!
  7.  
  8. // Some time
  9. // Add mouse coords to diagnostics screen, raw key codes
  10.  
  11. // Editor
  12. // list of levels you can edit
  13.  
  14. // Long term
  15. // Admin select level w/ preview(?)
  16. // Implement level selection based on MinPlayers & MaxPlayers
  17.  
  18. //Test:
  19.  
  20. // TODO:
  21. // Turrets at end of wall can rotate through wall.  Why?
  22. // Create color global for reticle color
  23.  
  24.  
  25.  
  26.  
  27.  
  28. //-----------------------------------------------------------------------------------
  29. //
  30. // Bitfighter - A multiplayer vector graphics space game
  31. // Based on Zap demo released for Torque Network Library by GarageGames.com
  32. //
  33. // Derivative work copyright (C) 2008-2009 Chris Eykamp
  34. // Original work copyright (C) 2004 GarageGames.com, Inc.
  35. // Other code copyright as noted
  36. //
  37. // This program is free software; you can redistribute it and/or modify
  38. // it under the terms of the GNU General Public License as published by
  39. // the Free Software Foundation; either version 2 of the License, or
  40. // (at your option) any later version.
  41. //
  42. // This program is distributed in the hope that it will be useful (and fun!),
  43. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  44. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  45. // GNU General Public License for more details.
  46. //
  47. // You should have received a copy of the GNU General Public License
  48. // along with this program; if not, write to the Free Software
  49. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  50. //
  51. //------------------------------------------------------------------------------------
  52.  
  53. #ifdef _MSC_VER
  54. #pragma warning (disable: 4996)     // Disable POSIX deprecation, certain security warnings that seem to be specific to VC++
  55. #endif
  56.  
  57. #include "IniFile.h"
  58.  
  59. #include "../tnl/tnl.h"
  60. #include "../tnl/tnlRandom.h"
  61. #include "../tnl/tnlGhostConnection.h"
  62. #include "../tnl/tnlNetInterface.h"
  63. #include "../tnl/tnlJournal.h"
  64.  
  65. #ifdef TNL_OS_MAC_OSX
  66. #include "Directory.h"
  67. #endif
  68.  
  69. #include "zapjournal.h"
  70.  
  71. #include "../glut/glutInclude.h"
  72. #include <stdarg.h>
  73. #include <sys/stat.h>
  74.  
  75. using namespace TNL;
  76.  
  77. #include "UI.h"
  78. #include "UIGame.h"
  79. #include "UINameEntry.h"
  80. #include "UIMenus.h"
  81. #include "UIEditor.h"
  82. #include "UIErrorMessage.h"
  83. #include "UIDiagnostics.h"
  84. #include "UICredits.h"
  85. #include "game.h"
  86. #include "gameNetInterface.h"
  87. #include "masterConnection.h"
  88. #include "sfx.h"
  89. #include "sparkManager.h"
  90. #include "input.h"
  91. #include "keyCode.h"
  92. #include "config.h"
  93. #include "md5wrapper.h"
  94.  
  95. #include "screenShooter.h"
  96.  
  97.  
  98. #ifdef TNL_OS_MAC_OSX
  99. #include <unistd.h>
  100. #endif
  101.  
  102. struct init_glut_before_main
  103. {
  104.    // xStartPos in UIChat.cpp uses getStringWidth in its global
  105.    // constructor, which in turn uses glutStrokeLength _before_
  106.    // glutInit, making Freeglut exit violently.  DailyWTF, here I
  107.    // come.
  108.    init_glut_before_main()
  109.    {
  110.       char *argv[] = { (char *) "bitfighter", 0 };
  111.       int argc = 1;
  112.       glutInit(&argc, argv);
  113.    }
  114. } init_glut_before_main_hack;
  115.  
  116. namespace Zap
  117. {
  118.  
  119. string gHostName;                // Server name used when hosting a game (default set in config.h, set in INI or on cmd line)
  120. string gHostDescr;               // Brief description of host
  121. const char *gWindowTitle = "Bitfighter";
  122.  
  123. // The following things can be set via command line parameters
  124. S32 gMaxPlayers;                 // Max players allowed -- can change on cmd line, or INI.  Default value in config.h
  125. U32 gSimulatedLag;               // Simulate a slow network -- can change on cmd line
  126. F32 gSimulatedPacketLoss;        // Simulate a bad network -- can change on cmd line
  127.  
  128.  
  129. #ifdef ZAP_DEDICATED
  130. bool gDedicatedServer = true;    // This will allow us to omit the -dedicated parameter when compiled in dedicated mode
  131. #else
  132. bool gDedicatedServer = false;   // Usually, we just want to play.  If true, we'll be in server-only, no-player mode
  133. #endif
  134.  
  135. bool gQuit = false;
  136. bool gIsServer = false;
  137.  
  138. // Handle any md5 requests
  139. md5wrapper md5;
  140.  
  141.  
  142. bool gShowAimVector = false;     // Do we render an aim vector?  This should probably not be a global, but until we find a better place for it...
  143. bool gDisableShipKeyboardInput;  // Disable ship movement while user is in menus
  144.  
  145. U32 gUseStickNumber = 1;         // Which joystick do you want to use (1 = first, which is typical)
  146. U32 gSticksFound = 0;            // Which joystick we're actually using...
  147.  
  148. CIniFile gINI("bitfighter.ini");    // This is our INI file
  149.  
  150. CmdLineSettings gCmdLineSettings;
  151. IniSettings gIniSettings;
  152.  
  153. ControllerTypeType gAutoDetectedJoystickType;   // Remember what sort of joystick was found for diagnostic purposes
  154.  
  155.  
  156. // Some colors -- other candidates include global and local chat colors, which are defined elsewhere.  Include here?
  157. Color gNexusOpenColor(0, 0.7, 0);
  158. Color gNexusClosedColor(0.85, 0.3, 0);
  159. Color gErrorMessageTextColor(1, 0.5, 0.5);
  160. Color gNeutralTeamColor(0.8, 0.8, 0.8);         // Objects that are neutral (on team -1)
  161. Color gHostileTeamColor(0.5, 0.5, 0.5);         // Objects that are "hostile-to-all" (on team -2)
  162. Color gMasterServerBlue(0.8, 0.8, 1);           // Messages about successful master server statii
  163. Color gHelpTextColor(0, 1, 0);
  164.  
  165. S32 gMaxPolygonPoints = 32;                     // Max number of points we can have in Nexuses, LoadoutZones, etc.
  166.  
  167. bool gReadyToConnectToMaster = false;           // When we're sure we have a nickname, we'll set this to true and proceed to connect to the master
  168.  
  169. const char *gServerPassword = NULL;
  170. const char *gAdminPassword = NULL;
  171. const char *gLevelChangePassword = NULL;
  172.  
  173. Address gMasterAddress;
  174. Address gConnectAddress;
  175. Address gBindAddress(IPProtocol, Address::Any, 28000);      // Good for now, may be overwritten by INI or cmd line setting
  176.       // Above is equivalent to ("IP:Any:28000")
  177.  
  178. string gLevelDir = "levels";              // Where our levels are stored, can be overwritten by ini or cmd line param
  179. Vector<StringTableEntry> gLevelList;      // Holds a list of the levels we'll play when we're hosting
  180.  
  181. // Lower = more slippery!  Not used at the moment...
  182. F32 gNormalFriction = 1000;   // Friction between vehicle and ground, ordinary
  183. F32 gSlipFriction = 400;      // Friction, on a slip square
  184.  
  185. char gJoystickName[gJoystickNameLength] = "";
  186.  
  187. extern Point gMousePos;
  188.  
  189. // Since GLUT reports the current mouse pos via a series of events, and does not make
  190. // its position available upon request, we'll store it when it changes so we'll have
  191. // it when we need it.
  192. void setMousePos(S32 x, S32 y)
  193. {
  194.    gMousePos.x = x;
  195.    gMousePos.y = y;
  196. }
  197.  
  198. enum HostingModePhases { NotHosting, LoadingLevels, DoneLoadingLevels, Hosting };
  199. HostingModePhases gHostingModePhase;
  200.  
  201. Screenshooter gScreenshooter;    // For taking screen shots
  202.  
  203. ZapJournal gZapJournal;    // Our main journaling object
  204.  
  205. // Handler called by GLUT when window is reshaped
  206. void GLUT_CB_reshape(int nw, int nh)
  207. {
  208.    gZapJournal.reshape(nw, nh);
  209. }
  210.  
  211. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, reshape, (S32 newWidth, S32 newHeight), (newWidth, newHeight))
  212. {
  213.    // If we are entering fullscreen mode, then we don't want to mess around with proportions and all that.  Just save window size and get out.
  214.    if(gIniSettings.fullscreen)
  215.    {
  216.       // The following block will attempt to keep graphics from being stretched on a monitor with non-standard proportions
  217.       // It works, but the effect is worse than the stretching, in my opinion.
  218.       //F32 fact;
  219.       //if((newWidth - UserInterface::canvasWidth) > (newHeight - UserInterface::canvasHeight))
  220.       //   fact = max((F32) newHeight / (F32) UserInterface::canvasHeight, 0.15f);
  221.       //else
  222.       //   fact = max((F32) newWidth / (F32) UserInterface::canvasWidth, 0.15f);
  223.  
  224.       //newHeight = UserInterface::canvasHeight * fact;
  225.       //newWidth = UserInterface::canvasWidth * fact;
  226.  
  227.       UserInterface::windowWidth = newWidth;
  228.       UserInterface::windowHeight = newHeight;
  229.       return;
  230.    }
  231.  
  232.    // Constrain window to correct proportions...
  233.    if((newWidth - UserInterface::canvasWidth) > (newHeight - UserInterface::canvasHeight))
  234.       gIniSettings.winSizeFact = max((F32) newHeight / (F32) UserInterface::canvasHeight, 0.15f);
  235.    else
  236.       gIniSettings.winSizeFact = max((F32) newWidth / (F32) UserInterface::canvasWidth, 0.15f);
  237.  
  238.    newHeight = (S32)(UserInterface::canvasHeight * gIniSettings.winSizeFact);
  239.    newWidth  = (S32)(UserInterface::canvasWidth  * gIniSettings.winSizeFact);
  240.  
  241.    glutReshapeWindow(newWidth, newHeight);
  242.  
  243.    UserInterface::windowWidth = newWidth;
  244.    UserInterface::windowHeight = newHeight;
  245.  
  246.    gINI.SetValueF("Settings", "WindowScalingFactor", gIniSettings.winSizeFact, true);
  247. }
  248.  
  249. // Handler called by GLUT when mouse motion is detected
  250. void GLUT_CB_motion(int x, int y)
  251. {
  252.    gZapJournal.motion(x, y);
  253. }
  254.  
  255. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, motion, (S32 x, S32 y), (x, y))
  256. {
  257.    setMousePos(x, y);
  258.  
  259.    if(UserInterface::current)
  260.       UserInterface::current->onMouseDragged(x, y);
  261. }
  262.  
  263. // Handler called by GLUT when "passive" mouse motion is detected
  264. void GLUT_CB_passivemotion(int x, int y)
  265. {
  266.    gZapJournal.passivemotion(x, y);
  267. }
  268.  
  269. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, passivemotion, (S32 x, S32 y), (x, y))
  270. {
  271.  
  272.    // Glut sometimes fires spurious events.  Let's ignore those.
  273.    if(x == gMousePos.x && y == gMousePos.y)
  274.       return;
  275.  
  276.    setMousePos(x, y);
  277.  
  278.    if(UserInterface::current)
  279.       UserInterface::current->onMouseMoved(x, y);
  280. }
  281.  
  282. void keyDown(KeyCode keyCode, char ascii)    // Launch the onKeyDown event
  283. {
  284.    if(UserInterface::current)
  285.       UserInterface::current->onKeyDown(keyCode, ascii);
  286. }
  287.  
  288. // Sometimes we need to pretend a key was pressed, such as for those that don't
  289. // generate events (shift/ctrl/alt, controller buttons, etc.)
  290. void simulateKeyDown(KeyCode keyCode)
  291. {
  292.    setKeyState(keyCode, true);
  293.    keyDown(keyCode, 0);
  294. }
  295.  
  296. void keyUp(KeyCode keyCode)              // Launch the onKeyUp event
  297. {
  298.    if(UserInterface::current)
  299.       UserInterface::current->onKeyUp(keyCode);
  300. }
  301.  
  302. void simulateKeyUp(KeyCode keyCode)
  303. {
  304.    setKeyState(keyCode, false);
  305.    keyUp(keyCode);
  306. }
  307.  
  308. // GLUT handler for key-down events
  309. void GLUT_CB_keydown(unsigned char key, S32 x, S32 y)
  310. {
  311.    gZapJournal.keydown(key);
  312. }
  313.  
  314.  
  315. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, keydown, (U8 key), (key))
  316. {
  317.    // First check for some "universal" keys.  If keydown isn't one of those, we'll pass the key onto the keyDown handler
  318.    // Check for ALT-ENTER --> toggles window mode/full screen
  319.    if(key == '\r' && (glutGetModifiers() & GLUT_ACTIVE_ALT))
  320.       gOptionsMenuUserInterface.toggleFullscreen();
  321.    else if(key == 17)      // GLUT reports Ctrl-Q as 17
  322.       gScreenshooter.phase = 1;
  323.    else
  324.    {
  325.       KeyCode keyCode = standardGLUTKeyToKeyCode(key);
  326.       setKeyState(keyCode, true);
  327.       keyDown(keyCode, keyToAscii(key, keyCode));
  328.    }
  329. }
  330.  
  331. #ifndef ZAP_DEDICATED
  332.  
  333. // GLUT handler for key-up events
  334. void GLUT_CB_keyup(unsigned char key, int x, int y)
  335. {
  336.    gZapJournal.keyup(key);
  337. }
  338.  
  339. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, keyup, (U8 key), (key))
  340. {
  341.    KeyCode keyCode = standardGLUTKeyToKeyCode(key);
  342.    setKeyState(keyCode, false);
  343.    keyUp(keyCode);
  344. }
  345.  
  346. // GLUT handler for mouse clicks
  347. void GLUT_CB_mouse(int button, int state, int x, int y)
  348. {
  349.    gZapJournal.mouse(button, state, x, y);
  350. }
  351.  
  352. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, mouse, (S32 button, S32 state, S32 x, S32 y), (button, state, x, y))
  353. {
  354.    setMousePos(x, y);
  355.  
  356.    if(!UserInterface::current) return;    // Bail if no current UI
  357.  
  358.    if(button == GLUT_LEFT_BUTTON)
  359.    {
  360.       setKeyState(MOUSE_LEFT, (state == GLUT_DOWN));
  361.  
  362.       if(state == GLUT_DOWN)
  363.          keyDown(MOUSE_LEFT, 0);
  364.       else // state == GLUT_UP
  365.          keyUp(MOUSE_LEFT);
  366.    }
  367.    else if(button == GLUT_RIGHT_BUTTON)
  368.    {
  369.       setKeyState(MOUSE_RIGHT, (state == GLUT_DOWN));
  370.  
  371.       if(state == GLUT_DOWN)
  372.          keyDown(MOUSE_RIGHT, 0);
  373.       else // state == GLUT_UP
  374.          keyUp(MOUSE_RIGHT);
  375.    }
  376.    else if(button == GLUT_MIDDLE_BUTTON)
  377.    {
  378.       setKeyState(MOUSE_MIDDLE, (state == GLUT_DOWN));
  379.  
  380.       if(state == GLUT_DOWN)
  381.          keyDown(MOUSE_MIDDLE, 0);
  382.       else // state == GLUT_UP
  383.          keyUp(MOUSE_MIDDLE);
  384.    }
  385. }
  386.  
  387. // GLUT callback for special key down (special keys are things like F1-F12)
  388. void GLUT_CB_specialkeydown(int key, int x, int y)
  389. {
  390.    gZapJournal.specialkeydown(key);
  391. }
  392.  
  393. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, specialkeydown, (S32 key), (key))
  394. {
  395.    KeyCode keyCode = specialGLUTKeyToKeyCode(key);
  396.    setKeyState(keyCode, true);
  397.  
  398.    if(keyCode == keyDIAG && !gDiagnosticInterface.isActive())   // Turn on diagnostic overlay if not already on
  399.    {
  400.       UserInterface::playBoop();
  401.       gDiagnosticInterface.activate();
  402.    }
  403.    else
  404.       keyDown(keyCode, keyToAscii(key, keyCode));           // Launch onKeyDown event
  405. }
  406.  
  407.  
  408. // GLUT callback for special key up
  409. void GLUT_CB_specialkeyup(int key, int x, int y)
  410. {
  411.    gZapJournal.specialkeyup(key);
  412. }
  413.  
  414. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, specialkeyup, (S32 key), (key))
  415. {
  416.    KeyCode keyCode = specialGLUTKeyToKeyCode(key);
  417.    setKeyState(keyCode, false);
  418.    keyUp(keyCode);
  419. }
  420. #endif
  421.  
  422. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, modifierkeydown, (U32 key), (key))
  423. {
  424.    if(key == 0)         // shift
  425.    {
  426.       setKeyState(KEY_SHIFT, true);
  427.       keyDown(KEY_SHIFT, 0);
  428.    }
  429.    else if(key == 1)    // ctrl
  430.    {
  431.       setKeyState(KEY_CTRL, true);
  432.       keyDown(KEY_CTRL, 0);
  433.    }
  434.    else if(key == 2)    // alt
  435.    {
  436.       setKeyState(KEY_ALT, true);
  437.       keyDown(KEY_ALT, 0);
  438.    }
  439. }
  440.  
  441. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, modifierkeyup, (U32 key), (key))
  442. {
  443.    if(key == 0)         // shift
  444.    {
  445.       setKeyState(KEY_SHIFT, false);
  446.       keyUp(KEY_SHIFT);
  447.    }
  448.    else if(key == 1)    // ctrl
  449.    {
  450.       setKeyState(KEY_CTRL, false);
  451.       keyUp(KEY_CTRL);
  452.    }
  453.    else if(key == 2)    // alt
  454.    {
  455.       setKeyState(KEY_ALT, false);
  456.       keyUp(KEY_ALT);
  457.    }
  458. }
  459.  
  460.  
  461. void exitGame(S32 errcode)
  462. {
  463.    #ifdef TNL_OS_XBOX
  464.       extern void xboxexit();
  465.       xboxexit();
  466.    #else
  467.       exit(errcode);
  468.    #endif
  469. }
  470.  
  471.  
  472. // Exit the game, back to the OS
  473. void exitGame()
  474. {
  475.    exitGame(0);
  476. }
  477.  
  478.  
  479. // If we can't load any levels, here's the plan...
  480. void abortHosting()
  481. {
  482.    if(gDedicatedServer)
  483.    {
  484.       logprintf("No levels were loaded from folder %s.  Cannot host a game.", gLevelDir.c_str());
  485.       s_logprintf("No levels were loaded from folder %s.  Cannot host a game.", gLevelDir.c_str());
  486.       //printf("No levels were loaded from folder %s.  Cannot host a game.", gLevelDir.c_str());      ==> Does nothing
  487.       exitGame(1);
  488.    }
  489.    else
  490.    {
  491.       gErrorMsgUserInterface.reset();
  492.       gErrorMsgUserInterface.setTitle("HOUSTON, WE HAVE A PROBLEM");
  493.       gErrorMsgUserInterface.setMessage(1, "No levels were loaded.  Cannot host a game.");
  494.       gErrorMsgUserInterface.setMessage(3, "Check the LevelDir parameter in your INI file,");
  495.       gErrorMsgUserInterface.setMessage(4, "or your command-line parameters to make sure");
  496.       gErrorMsgUserInterface.setMessage(5, "you have correctly specified a folder containing");
  497.       gErrorMsgUserInterface.setMessage(6, "valid level files.");
  498.       gErrorMsgUserInterface.setMessage(8, "Trying to load levels from folder:");
  499.       gErrorMsgUserInterface.setMessage(9, gLevelDir.c_str());
  500.       gErrorMsgUserInterface.activate();
  501.    }
  502.    delete gServerGame;
  503.    gServerGame = NULL;
  504.  
  505.    gMainMenuUserInterface.levelLoadDisplayDisplay = false;
  506.    gMainMenuUserInterface.levelLoadDisplayFadeTimer.clear();
  507.  
  508.    return;
  509. }
  510.  
  511.  
  512. // Host a game (and maybe even play a bit, too!)
  513. void initHostGame(Address bindAddress, bool testMode)
  514. {
  515.    gServerGame = new ServerGame(bindAddress, gMaxPlayers, gHostName.c_str(), testMode);
  516.  
  517.    // Don't need to build our level list when in test mode because we're only running that one level stored in editor.tmp
  518.    if(!testMode)
  519.       LevelListLoader::buildLevelList();
  520.  
  521.    // Parse all levels, make sure they are in some sense valid, and record some critical parameters
  522.    if(gLevelList.size())
  523.    {
  524.       gServerGame->setLevelList(gLevelList);
  525.       gServerGame->resetLevelLoadIndex();
  526.       gMainMenuUserInterface.levelLoadDisplayDisplay = true;
  527.    }
  528.    else
  529.    {
  530.       abortHosting();
  531.       return;
  532.    }
  533.  
  534.   gHostingModePhase = LoadingLevels;      // Do this even if there are no levels, so hostGame error handling will be triggered
  535. }
  536.  
  537.  
  538. void hostGame()
  539. {
  540.    gHostingModePhase = Hosting;
  541.    s_logprintf("----------\nbitfighter server started %s", getTimeStamp().c_str());
  542.    s_logprintf("hostname=[%s], hostdescr=[%s]", gServerGame->getHostName(), gServerGame->getHostDescr());
  543.    s_logprintf("hosting %d levels:", gServerGame->getLevelNameCount());
  544.  
  545.    for(S32 i = 0; i < gServerGame->getLevelNameCount(); i++)
  546.       s_logprintf("\t%s [%s]", gServerGame->getLevelNameFromIndex(i).getString(), gServerGame->getLevelFileNameFromIndex(i).c_str());
  547.  
  548.    if(gServerGame->getLevelNameCount())   // Levels loaded --> start game!
  549.       gServerGame->cycleLevel(0);         // Start the first level
  550.  
  551.    else        // No levels loaded... we'll crash if we try to start a game
  552.    {
  553.       abortHosting();
  554.       return;
  555.    }
  556.  
  557.    gMainMenuUserInterface.levelLoadDisplayDisplay = false;
  558.    gMainMenuUserInterface.levelLoadDisplayFadeTimer.reset();
  559.  
  560.    if(!gDedicatedServer)                  // If this isn't a dedicated server...
  561.       joinGame(Address(), false, true);   // ...then we'll play, too!
  562.       //      (let the system assign ip and port, false -> not from master, true -> local connection)
  563.    //else
  564.    //   printf("Bitfighter host launched.\n");     ==> Does nothing
  565. }
  566.  
  567.  
  568. // This is the master idle loop that gets registered with GLUT and is called on every game tick.
  569. // This in turn calls the idle functions for all other objects in the game.
  570. void idle()
  571. {
  572.    if(gHostingModePhase == LoadingLevels)
  573.       gServerGame->loadNextLevel();
  574.    else if(gHostingModePhase == DoneLoadingLevels)
  575.       hostGame();
  576.  
  577.    checkModifierKeyState();      // Most keys are handled as events by GLUT...  but not Ctrl, Alt, Shift!
  578.    static S64 lastTimer = Platform::getHighPrecisionTimerValue();
  579.    static F64 unusedFraction = 0;
  580.  
  581.    S64 currentTimer = Platform::getHighPrecisionTimerValue();
  582.  
  583.    F64 timeElapsed = Platform::getHighPrecisionMilliseconds(currentTimer - lastTimer) + unusedFraction;
  584.    U32 integerTime = U32(timeElapsed);
  585.  
  586.    if(integerTime >= 10)
  587.    {
  588.       lastTimer = currentTimer;
  589.       unusedFraction = timeElapsed - integerTime;
  590.  
  591.       gZapJournal.idle(integerTime);
  592.    }
  593.  
  594.    // So, what's with all the SDL code in here?  I looked at converting from GLUT to SDL, in order to get
  595.    // a richer set of keyboard events.  Looks possible, but SDL appears to be missing some very handy
  596.    // windowing code (e.g. the ability to resize or move a window) that GLUT has.  So until we find a
  597.    // platform independent window library, we'll stick with GLUT, or maybe go to FreeGlut.
  598.    // Note that moving to SDL will require our journaling system to be re-engineered.
  599.    // Note too that SDL will require linking in SDL.lib and SDLMain.lib, and including the SDL.dll in the EXE folder.
  600.  
  601.    /* SDL requires an active polling loop.  We could use something like the following:
  602.    while(SDL_PollEvent(&e))
  603.    {
  604.       switch(e.type)
  605.       {
  606.          case SDL_KEYDOWN:
  607.             gZapJournal.keydown((S32) e.key.keysym.sym);      // Cast to S32 to ensure journaling system can cope
  608.             break;
  609.          case SDL_KEYUP:
  610.             gZapJournal.keyup((S32) e.key.keysym.sym);
  611.             break;
  612.          case SDL_MOUSEMOTION:
  613.             break;
  614.          case SDL_VIDEORESIZE:
  615.             window_resized(e.resize.w, e.resize.h);
  616.             break;
  617.          case SDL_QUIT:       // User closed game window
  618.             exitGame();
  619.             break;
  620.       }
  621.    }
  622.  
  623.    gZapJournal.display();    // Draw the screen --> GLUT handles this via callback, with SDL we need to do it in our main loop
  624.    END SDL event polling */
  625.  
  626.    // Sleep a bit so we don't saturate the system. For a non-dedicated server,
  627.    // sleep(0) helps reduce the impact of OpenGL on windows.
  628.    U32 sleepTime = 1;
  629.  
  630.    if(gClientGame) sleepTime = 0;      // Live player at the console
  631.  
  632.    // If there are no players, set sleepTime to 40 to further reduce impact on the server.
  633.    // We'll only go into this longer sleep on dedicated servers when there are no players.
  634.    if(gDedicatedServer && !(gServerGame && gServerGame->getGameType() && gServerGame->getGameType()->mClientList.size()))
  635.       sleepTime = 40;
  636.  
  637.    Platform::sleep(sleepTime);
  638.  
  639.    gZapJournal.processNextJournalEntry();    // Does nothing unless we're playing back a journal...
  640.  
  641. }  // end idle()
  642.  
  643.  
  644.  
  645. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, idle, (U32 integerTime), (integerTime))
  646. {
  647.    if(UserInterface::current)
  648.       UserInterface::current->idle(integerTime);
  649.  
  650.    if(gHostingModePhase != LoadingLevels)    // Don't idle games during level load
  651.    {
  652.       if(gClientGame)
  653.          gClientGame->idle(integerTime);
  654.       if(gServerGame)
  655.          gServerGame->idle(integerTime);
  656.    }
  657.  
  658.    if(gClientGame)
  659.       glutPostRedisplay();
  660. }
  661.  
  662. void dedicatedServerLoop()
  663. {
  664.    for(;;)        // Loop forever!
  665.       idle();     // Idly!
  666. }
  667.  
  668. #ifndef ZAP_DEDICATED
  669. void GLUT_CB_display(void)
  670. {
  671.    gZapJournal.display();
  672.  
  673.    if(gScreenshooter.phase)      // We're in mid-shot, so be sure to visit the screenshooter!
  674.       gScreenshooter.saveScreenshot();
  675. }
  676. #endif
  677.  
  678. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, display, (), ())
  679. {
  680.    glFlush();
  681.    UserInterface::renderCurrent();
  682.  
  683.    // Render master connection state if we're not connected
  684.    if(gClientGame && gClientGame->getConnectionToMaster() && gClientGame->getConnectionToMaster()->getConnectionState() != NetConnection::Connected)
  685.    {
  686.       glColor3f(1, 1, 1);
  687.       UserInterface::drawStringf(10, 550, 15, "Master Server - %s", gConnectStatesTable[gClientGame->getConnectionToMaster()->getConnectionState()]);
  688.    }
  689.  
  690.    // Swap the buffers. This this tells the driver to render the next frame from the contents of the
  691.    // back-buffer, and to set all rendering operations to occur on what was the front-buffer.
  692.    // Double buffering prevents nasty visual tearing from the application drawing on areas of the
  693.    // screen that are being updated at the same time.
  694.    glutSwapBuffers();
  695.    //SDL_GL_SwapBuffers();  // Use this if we convert to SDL
  696.  }
  697.  
  698. #include <stdio.h>
  699. // Each instnatiation of a LogConsumer subclass gets a copy of all log messages.  Here we'll log both
  700. // to the screen as well as to a file called bitfighter.log
  701. class StdoutLogConsumer : public LogConsumer   // Dumps logs to stdout
  702. {
  703. public:
  704.    void logString(const char *string)
  705.    {
  706.       printf("%s", string);
  707.    }
  708. } gStdoutLogConsumer;
  709.  
  710.  
  711. class FileLogConsumer : public LogConsumer     // Dumps logs to bitfighter.log
  712. {
  713. private:
  714.    FILE *f;
  715. public:
  716.    FileLogConsumer(const char* logFile="bitfighter.log")
  717.    {
  718.       f = fopen(logFile, "w");
  719.       logString("------ Bitfighter Log File ------\n");
  720.    }
  721.  
  722.    ~FileLogConsumer()
  723.    {
  724.       if(f)
  725.          fclose(f);
  726.    }
  727.  
  728.    void logString(const char *string)
  729.    {
  730.       if(f)
  731.       {
  732.          fprintf(f, "%s", string);
  733.          fflush(f);
  734.       }
  735.    }
  736. } gFileLogConsumer;
  737.  
  738.  
  739. //
  740. class ServerFileLogConsumer : public LogConsumer    // Dumps logs to bitfighter.log
  741. {
  742. private:
  743.    FILE *f;
  744. public:
  745.    ServerFileLogConsumer(const char* logFile="bitfighter_server.log")
  746.    {
  747.       f = fopen(logFile, "a");
  748.       setFilterType(LogConsumer::ServerFilter);
  749.    }
  750.  
  751.    ~ServerFileLogConsumer()
  752.    {
  753.       if(f)
  754.          fclose(f);
  755.    }
  756.  
  757.    void logString(const char *string)
  758.    {
  759.       if(f)
  760.       {
  761.          fprintf(f, "%s", string);
  762.          fflush(f);
  763.       }
  764.    }
  765. } gServerLogConsumer;
  766.  
  767.  
  768. // Player has selected a game from the QueryServersUserInterface, and is ready to join
  769. void joinGame(Address remoteAddress, bool isFromMaster, bool local)
  770. {
  771.    if(isFromMaster && gClientGame->getConnectionToMaster())
  772.    {
  773.       gClientGame->getConnectionToMaster()->requestArrangedConnection(remoteAddress);
  774.       gGameUserInterface.activate();
  775.    }
  776.    else
  777.    {
  778.       GameConnection *theConnection = new GameConnection();
  779.       gClientGame->setConnectionToServer(theConnection);
  780.  
  781.       // Use name specified in name entry screen, falling back to defaultName (from INI) if blank
  782.       const char *name = gNameEntryUserInterface.getText()[0] ? gNameEntryUserInterface.getText() : gIniSettings.defaultName.c_str();
  783.  
  784.       theConnection->setClientName(name);
  785.  
  786.       theConnection->setSimulatedNetParams(gSimulatedPacketLoss, gSimulatedLag);
  787.  
  788.       if(local)   // Local client
  789.       {
  790.          theConnection->connectLocal(gClientGame->getNetInterface(), gServerGame->getNetInterface());
  791.          theConnection->setIsAdmin(true);          // Local connection is always admin
  792.          theConnection->setIsLevelChanger(true);   // Local connection can always change levels
  793.  
  794.          GameConnection *gc = dynamic_cast<GameConnection *>(theConnection->getRemoteConnectionObject());
  795.  
  796.          if(gc)                              // gc might evaluate false if a bad password was supplied to a password-protected server
  797.          {
  798.             gc->setIsAdmin(true);            // Set isAdmin on server
  799.             gc->setIsLevelChanger(true);     // Set isLevelChanger on server
  800.  
  801.             gc->s2cSetIsAdmin(true);         // Set isAdmin on the client
  802.             gc->s2cSetIsLevelChanger(true);  // Set isLevelChanger on the client
  803.             gc->setServerName(gServerGame->getHostName());     // Server name is whatever we've set locally
  804.          }
  805.       }
  806.       else        // Remote client
  807.          theConnection->connect(gClientGame->getNetInterface(), remoteAddress);  // (method in tnlNetConnection)
  808.  
  809.       gGameUserInterface.activate();
  810.    }
  811. }
  812.  
  813. // Disconnect from servers and exit game in an orderly fashion
  814. void endGame()
  815. {
  816.    // Disconnect from master server
  817.    if(gClientGame && gClientGame->getConnectionToMaster())
  818.       gClientGame->getConnectionToMaster()->cancelArrangedConnectionAttempt();
  819.  
  820.    // Disconnect from game server
  821.    if(gClientGame && gClientGame->getConnectionToServer())
  822.       gClientGame->getConnectionToServer()->disconnect(NetConnection::ReasonSelfDisconnect, "");
  823.  
  824.    delete gServerGame;
  825.    gServerGame = NULL;
  826. }
  827.  
  828.  
  829. // Run when we're quitting the game
  830. void onExit()
  831. {
  832.    endGame();
  833.    SFXObject::shutdown();
  834.    ShutdownJoystick();
  835.  
  836.    // Save settings to capture window position
  837.    gINI.SetValue("Settings", "WindowMode", (gIniSettings.fullscreen ? "Fullscreen" : "Window"), true);
  838.    if(!gIniSettings.fullscreen)
  839.    {
  840.       gINI.SetValueI("Settings", "WindowXPos", glutGet(GLUT_WINDOW_X), true);
  841.       gINI.SetValueI("Settings", "WindowYPos", glutGet(GLUT_WINDOW_Y), true);
  842.    }
  843.  
  844.    gINI.WriteFile();
  845.  
  846.    NetClassRep::logBitUsage();
  847.    TNL::logprintf("Bye!");
  848.  
  849.    exitGame();
  850. }
  851.  
  852.  
  853. // If we're running in dedicated mode, these things need to be set as such.
  854. void setParamsForDedicatedMode()
  855. {
  856.    gCmdLineSettings.clientMode = false;
  857.    gCmdLineSettings.serverMode = true;
  858.    gDedicatedServer = true;
  859.    gReadyToConnectToMaster = true;
  860.  
  861.    gCmdLineSettings.connectRemote = false;
  862. }
  863.  
  864.  
  865.  
  866. // Read the command line params... if we're replaying a journal, we'll process those params as if they were actually there, while
  867. // ignoring those params that were provided.
  868. TNL_IMPLEMENT_JOURNAL_ENTRYPOINT(ZapJournal, readCmdLineParams, (Vector<StringPtr> argv), (argv))
  869. {
  870.    S32 argc = argv.size();
  871.  
  872.    // Process command line args  --> see http://bitfighter.org/wiki/index.php?title=Command_line_parameters
  873.    for(S32 i = 0; i < argc; i+=2)
  874.    {
  875.       bool hasAdditionalArg = (i != argc - 1 && argv[i + 1].getString()[0] != '-');     // Assume "args" starting with "-" are actually follow-on params
  876.       bool has2AdditionalArgs = hasAdditionalArg && (i != argc - 2);
  877.  
  878.       // Connect to a game server
  879.       if(!stricmp(argv[i], "-connect"))       // additional arg required
  880.       {
  881.          if(hasAdditionalArg)
  882.          {
  883.             gCmdLineSettings.connectRemote = true;
  884.             gCmdLineSettings.connect = argv[i+1];
  885.          }
  886.          else
  887.          {
  888.             logprintf("You must specify a server address to connect to with the -connect option");
  889.             exitGame(1);
  890.          }
  891.       }
  892.       // Specify a master server
  893.       else if(!stricmp(argv[i], "-master"))        // additional arg required
  894.       {
  895.          if(hasAdditionalArg)
  896.             gCmdLineSettings.masterAddress = argv[i+1];
  897.          else
  898.          {
  899.             logprintf("You must specify a master server address with -master option");
  900.             exitGame(1);
  901.          }
  902.       }
  903.       // Address to use when we're hosting
  904.       else if(!stricmp(argv[i], "-hostaddr"))       // additional arg required
  905.       {
  906.          if(hasAdditionalArg)
  907.             gCmdLineSettings.hostaddr = argv[i+1];
  908.          else
  909.          {
  910.             logprintf("You must specify a host address for the host to listen on (e.g. IP:Any:28000 or IP:192.169.1.100:5500)");
  911.             exitGame(1);
  912.          }
  913.       }
  914.       // Simulate packet loss 0 (none) - 1 (total)  [I think]
  915.       else if(!stricmp(argv[i], "-loss"))          // additional arg required
  916.       {
  917.          if(hasAdditionalArg)
  918.             gCmdLineSettings.loss = atof(argv[i+1]);
  919.          else
  920.          {
  921.             logprintf("You must specify a loss rate between 0 and 1 with the -loss option");
  922.             exitGame(1);
  923.          }
  924.       }
  925.       // Simulate network lag
  926.       else if(!stricmp(argv[i], "-lag"))           // additional arg required
  927.       {
  928.          if(hasAdditionalArg)
  929.             gCmdLineSettings.lag = atoi(argv[i+1]);
  930.          else
  931.          {
  932.             logprintf("You must specify a lag (in ms) with the -lag option");
  933.             exitGame(1);
  934.          }
  935.       }
  936.       // Run as a dedicated server
  937.       else if(!stricmp(argv[i], "-dedicated"))     // additional arg optional
  938.       {
  939.          setParamsForDedicatedMode();
  940.  
  941.          if(hasAdditionalArg)
  942.             gCmdLineSettings.dedicated = argv[i+1];
  943.          else
  944.             i--;     // Correct for the fact that we don't really have two args here...
  945.       }
  946.       // Specify user name
  947.       else if(!stricmp(argv[i], "-name"))          // additional arg required
  948.       {
  949.          if(hasAdditionalArg)
  950.             gCmdLineSettings.name = argv[i+1];
  951.          else
  952.          {
  953.             logprintf("You must enter a nickname with the -name option");
  954.             exitGame(1);
  955.          }
  956.       }
  957.       // Specify password for accessing locked ser vers
  958.       else if(!stricmp(argv[i], "-password"))      // additional arg required
  959.       {
  960.          if(hasAdditionalArg)
  961.             gCmdLineSettings.password = argv[i+1];
  962.          else
  963.          {
  964.             logprintf("You must enter a password with the -password option");
  965.             exitGame(1);
  966.          }
  967.       }
  968.       // Specify admin password for server
  969.       else if(!stricmp(argv[i], "-adminpassword")) // additional arg required
  970.       {
  971.          if(hasAdditionalArg)
  972.             gCmdLineSettings.adminPassword = argv[i+1];
  973.          else
  974.          {
  975.             logprintf("You must specify an admin password with the -adminpassword option");
  976.             exitGame(1);
  977.          }
  978.       }
  979.       // Specify level change password for server
  980.       else if(!stricmp(argv[i], "-levelchangepassword")) // additional arg required
  981.       {
  982.          if(hasAdditionalArg)
  983.             gCmdLineSettings.levelChangePassword = argv[i+1];
  984.          else
  985.          {
  986.             logprintf("You must specify an level-change password with the -levelchangepassword option");
  987.             exitGame(1);
  988.          }
  989.       }
  990.       // Specify to include all levels in levels folder -- not really needed any more, but can be used as a shortcut to tell game to ignore levels in INI file...
  991.       else if(!stricmp(argv[i], "-alllevels"))     // no additional args
  992.       {
  993.          i--;  // compentsate for +=2 in for loop with single param
  994.          gCmdLineSettings.alllevels = true;
  995.       }
  996.       // Read all levels in the specified subfolder
  997.       else if(!stricmp(argv[i], "-leveldir"))      // additional arg required
  998.       {
  999.          if(!hasAdditionalArg)
  1000.          {
  1001.             logprintf("You must specify a levels subfolder with the -leveldir option");
  1002.             exitGame(1);
  1003.          }
  1004.  
  1005.          gCmdLineSettings.levelDir = argv[i+1].getString();
  1006.       }
  1007.  
  1008.       // Specify list of levels...  all remaining params will be taken as level names
  1009.       else if(!stricmp(argv[i], "-levels"))     // additional arg(s) required
  1010.       {
  1011.          if(!hasAdditionalArg)
  1012.          {
  1013.             logprintf("You must specify one or more levels to load with the -levels option");
  1014.             exitGame(1);
  1015.          }
  1016.  
  1017.          // We'll overwrite our main level list directly, so if we're writing the INI for the first time,
  1018.          // we'll use the cmd line args to generate the INI Level keys, rather than the built-in defaults.
  1019.          for(S32 j = i+1; j < argc; j++)
  1020.             gCmdLineSettings.specifiedLevels.push_back(StringTableEntry(argv[j]));
  1021.  
  1022.          return;     // This param must be last, so no more args to process.  We can return.
  1023.  
  1024.       }
  1025.       // Specify name of the server as others will see it from the Join menu
  1026.       else if(!stricmp(argv[i], "-hostname"))   // additional arg required
  1027.       {
  1028.          if(hasAdditionalArg)
  1029.             gCmdLineSettings.hostname = argv[i+1];
  1030.          else
  1031.          {
  1032.             logprintf("You must specify a server name with the -hostname option");
  1033.             exitGame(1);
  1034.          }
  1035.       }
  1036.       else if(!stricmp(argv[i], "-hostdescr"))   // additional arg required
  1037.       {
  1038.          if(hasAdditionalArg)
  1039.             gCmdLineSettings.hostdescr = argv[i+1];
  1040.          else
  1041.          {
  1042.             logprintf("You must specify a description (use quotes) with the -hostdescr option");
  1043.             exitGame(1);
  1044.          }
  1045.       }
  1046.       // Change max players on server
  1047.       else if(!stricmp(argv[i], "-maxplayers")) // additional arg required
  1048.       {
  1049.          if(hasAdditionalArg)
  1050.             gCmdLineSettings.maxplayers = atoi(argv[i+1]);
  1051.          else
  1052.          {
  1053.             logprintf("You must specify the max number of players on your server with the -maxplayers option");
  1054.             exitGame(1);
  1055.          }
  1056.       }
  1057.       // Start in window mode
  1058.       else if(!stricmp(argv[i], "-window"))     // no additional args
  1059.       {
  1060.          i--;  // compentsate for +=2 in for loop with single param
  1061.          gCmdLineSettings.window = true;
  1062.       }
  1063.       // Start in fullscreen mode
  1064.       else if(!stricmp(argv[i], "-fullscreen")) // no additional args
  1065.       {
  1066.          i--;
  1067.          gCmdLineSettings.fullscreen = true;
  1068.       }
  1069.       // Specify position of window
  1070.       else if(!stricmp(argv[i], "-winpos"))     // 2 additional args required
  1071.       {
  1072.          if(has2AdditionalArgs)
  1073.          {
  1074.             gCmdLineSettings.xpos = atoi(argv[i+1]);
  1075.             gCmdLineSettings.ypos = atoi(argv[i+2]);
  1076.             i++;  // compentsate for +=2 in for loop with single param (because we're grabbing two)
  1077.          }
  1078.          else
  1079.          {
  1080.             logprintf("You must specify the x and y position of the window with the -winpos option");
  1081.             exitGame(1);
  1082.          }
  1083.       }
  1084.       // Specify width of the game window
  1085.       else if(!stricmp(argv[i], "-winwidth")) // additional arg required
  1086.       {
  1087.          if(hasAdditionalArg)
  1088.             gCmdLineSettings.winWidth = atoi(argv[i+1]);
  1089.          else
  1090.          {
  1091.             logprintf("You must specify the width of the game window with the -winwidth option");
  1092.             exitGame(1);
  1093.          }
  1094.       }
  1095.       else if(!stricmp(argv[i], "-help"))       // no additional args
  1096.       {
  1097.          i--;
  1098.          logprintf("See http://bitfighter.org/wiki/index.php?title=Command_line_parameters for information");
  1099.          exitGame(0);
  1100.       }
  1101.       // Highly speculative use of different joysticks
  1102.       else if(!stricmp(argv[i], "-usestick")) // additional arg required
  1103.       {
  1104.          if(hasAdditionalArg)
  1105.             gUseStickNumber = atoi(argv[i+1]);           /////////////////////////////////////////  TODO: should be part of gCmdLineSettings
  1106.          else
  1107.          {
  1108.             logprintf("You must specify the joystick you want to use with the -usestick option");
  1109.             exitGame(1);
  1110.          }
  1111.       }
  1112.    }
  1113.  
  1114. // Override some settings if we're compiling ZAP_DEDICATED
  1115. #ifdef ZAP_DEDICATED
  1116.    setParamsForDedicatedMode();
  1117. #endif
  1118. }
  1119.  
  1120. /*
  1121. void InitSdlVideo()
  1122. {
  1123.    // Information about the current video settings.
  1124.    const SDL_VideoInfo* info = NULL;
  1125.  
  1126.    // Flags we will pass into SDL_SetVideoMode.
  1127.    S32 flags = 0;
  1128.  
  1129.    // First, initialize SDL's video subsystem.
  1130.    if (SDL_Init(SDL_INIT_VIDEO) < 0)
  1131.    {
  1132.        // Failed, exit.
  1133.        logprintf("SDL Video initialization failed: %s", SDL_GetError( ));
  1134.        exitGame();
  1135.    }
  1136.  
  1137.    // Let's get some video information.
  1138.    info = SDL_GetVideoInfo( );
  1139.  
  1140.    if( !info ) {
  1141.        // This should probably never happen.
  1142.        logprintf("SDL Video query failed: %s", SDL_GetError());
  1143.        exitGame();
  1144.    }
  1145.  
  1146.    // We get the bpp we will request from
  1147.    // the display. On X11, VidMode can't change
  1148.    // resolution, so this is probably being overly
  1149.    // safe. Under Win32, ChangeDisplaySettings
  1150.    // can change the bpp.
  1151.  
  1152.    gBPP = info->vfmt->BitsPerPixel;
  1153.  
  1154.    // Now, we want to setup our requested
  1155.    // window attributes for our OpenGL window.
  1156.    // We want *at least* 5 bits of red, green
  1157.    // and blue. We also want at least a 16-bit
  1158.    // depth buffer.
  1159.    //
  1160.    // The last thing we do is request a double
  1161.    // buffered window. '1' turns on double
  1162.    // buffering, '0' turns it off.
  1163.    //
  1164.    // Note that we do not use SDL_DOUBLEBUF in
  1165.    // the flags to SDL_SetVideoMode. That does
  1166.    // not affect the GL attribute state, only
  1167.    // the standard 2D blitting setup.
  1168.  
  1169.    SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
  1170.    SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
  1171.    SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
  1172.    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
  1173.    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
  1174.  
  1175.    // We want to request that SDL provide us with an OpenGL window, possibly in a fullscreen video mode.
  1176.    // Note the SDL_DOUBLEBUF flag is not required to enable double buffering when setting an OpenGL
  1177.    // video mode. Double buffering is enabled or disabled using the SDL_GL_DOUBLEBUFFER attribute.
  1178.    flags = SDL_OPENGL | SDL_RESIZABLE ; // | SDL_FULLSCREEN;
  1179.  
  1180.  
  1181.    if(SDL_SetVideoMode(gScreenWidth, gScreenHeight, gBPP, flags ) == 0)
  1182.    {
  1183.       // This could happen for a variety of reasons,
  1184.       // including DISPLAY not being set, the specified
  1185.       // resolution not being available, etc.
  1186.  
  1187.       logprintf("SDL Video mode set failed: %s", SDL_GetError());
  1188.       exitGame();
  1189.    }
  1190.  
  1191.    SDL_WM_SetCaption(gWindowTitle, "Icon XXX");    // TODO: Fix icon here
  1192. }
  1193. */
  1194.  
  1195.  
  1196. // Basically checks if the folder base exists, and if not, makes it a subdir of levels
  1197. // Typos on the user's part can lead to hilarity!
  1198. string getLevelsFolder(string base)
  1199. {
  1200.    // See if levelsFolder could refer to a standalone folder (rather than a subfolder of gLevelDir)
  1201.    struct stat st;
  1202.    if(stat(base.c_str(), &st) != 0 )
  1203.       return gLevelDir + "/" + base;      // It doesn't
  1204.    else
  1205.       return base;                        // It does
  1206. }
  1207.  
  1208.  
  1209. // Now integrate INI settings with those from the command line and process them
  1210. void processStartupParams()
  1211. {
  1212.    // These options can only be set on cmd line
  1213.    if(!gCmdLineSettings.server.empty())
  1214.       gBindAddress.set(gCmdLineSettings.server);
  1215.  
  1216.    if(!gCmdLineSettings.dedicated.empty())
  1217.       gBindAddress.set(gCmdLineSettings.dedicated);
  1218.  
  1219.    if(gCmdLineSettings.connect != "")
  1220.       gConnectAddress.set(gCmdLineSettings.connect);
  1221.  
  1222.    gSimulatedPacketLoss = gCmdLineSettings.loss;
  1223.    gSimulatedLag = gCmdLineSettings.lag;
  1224.  
  1225.    // Enable some logging...
  1226.    TNLLogEnable(LogConnectionProtocol, gIniSettings.logConnectionProtocol);
  1227.    TNLLogEnable(LogNetConnection, gIniSettings.logNetConnection);
  1228.    TNLLogEnable(LogEventConnection, gIniSettings.logEventConnection);
  1229.    TNLLogEnable(LogGhostConnection, gIniSettings.logGhostConnection);
  1230.  
  1231.    TNLLogEnable(LogNetInterface, gIniSettings.logNetInterface);
  1232.    TNLLogEnable(LogPlatform, gIniSettings.logPlatform);
  1233.    TNLLogEnable(LogNetBase, gIniSettings.logNetBase);
  1234.    TNLLogEnable(LogUDP, gIniSettings.logUDP);
  1235.  
  1236.  
  1237.    // These options can come either from cmd line or INI file
  1238.    if(gCmdLineSettings.name != "")
  1239.       gNameEntryUserInterface.setText(gCmdLineSettings.name.c_str());
  1240.    else if(gIniSettings.name != "")
  1241.       gNameEntryUserInterface.setText(gIniSettings.name.c_str());
  1242.    else
  1243.       gNameEntryUserInterface.setText(gIniSettings.lastName.c_str());
  1244.  
  1245.  
  1246.    if(gCmdLineSettings.password != "")
  1247.       gServerPassword = gCmdLineSettings.password.c_str();
  1248.    else if(gIniSettings.password != "")
  1249.       gServerPassword = gIniSettings.password.c_str();
  1250.    // else rely on gServerPassword default of ""
  1251.  
  1252.    if(gCmdLineSettings.adminPassword != "")
  1253.       gAdminPassword = gCmdLineSettings.adminPassword.c_str();
  1254.    else if(gIniSettings.adminPassword != "")
  1255.       gAdminPassword = gIniSettings.adminPassword.c_str();
  1256.    // else rely on gAdminPassword default of ""   i.e. no one can do admin tasks on the server
  1257.  
  1258.    if(gCmdLineSettings.levelChangePassword != "")
  1259.       gLevelChangePassword = gCmdLineSettings.levelChangePassword.c_str();
  1260.    else if(gIniSettings.levelChangePassword != "")
  1261.       gLevelChangePassword = gIniSettings.levelChangePassword.c_str();
  1262.    // else rely on gLevelChangePassword default of ""   i.e. no one can change levels on the server
  1263.  
  1264.    if(gIniSettings.levelDir != "")
  1265.       gLevelDir = gIniSettings.levelDir;
  1266.    else
  1267.       gIniSettings.levelDir = gLevelDir;     // So a good default will be written to the INI
  1268.  
  1269.    // This way, the main level dir can be specified in the INI, but it can either be overridden here,
  1270.    // or a subfolder can be specified, depending on what's in the leveldir param
  1271.    if(gCmdLineSettings.levelDir != "")
  1272.       gLevelDir = getLevelsFolder(gCmdLineSettings.levelDir);
  1273.    else
  1274.       gLevelDir = getLevelsFolder(gIniSettings.levelDir);
  1275.    // else leave gLevelDir at it's default setting, "levels"
  1276.  
  1277.    if(gCmdLineSettings.hostname != "")
  1278.       gHostName = gCmdLineSettings.hostname;
  1279.    else
  1280.       gHostName = gIniSettings.hostname;
  1281.  
  1282.    if(gCmdLineSettings.hostdescr != "")
  1283.       gHostDescr = gCmdLineSettings.hostdescr;
  1284.    else
  1285.       gHostDescr = gIniSettings.hostdescr;
  1286.  
  1287.    if(gCmdLineSettings.hostaddr != "")
  1288.       gBindAddress.set(gCmdLineSettings.hostaddr);
  1289.    else if(gIniSettings.hostaddr != "")
  1290.       gBindAddress.set(gIniSettings.hostaddr);
  1291.    // else stick with default defined earlier
  1292.  
  1293.    U32 maxplay;
  1294.    if (gCmdLineSettings.maxplayers > 0)
  1295.       maxplay = gCmdLineSettings.maxplayers;
  1296.    else
  1297.       maxplay = gIniSettings.maxplayers;
  1298.    if (maxplay < 0 || maxplay > 128)
  1299.       maxplay = 128;
  1300.    gMaxPlayers = (U32) maxplay;
  1301.  
  1302.  
  1303.    if(gCmdLineSettings.fullscreen)
  1304.       gIniSettings.fullscreen = true;    // Simply clobber the gINISettings copy
  1305.    else if(gCmdLineSettings.window)
  1306.       gIniSettings.fullscreen = false;
  1307.  
  1308.    if(gCmdLineSettings.xpos != -9999)
  1309.       gIniSettings.winXPos = gCmdLineSettings.xpos;
  1310.    if(gCmdLineSettings.ypos != -9999)
  1311.       gIniSettings.winYPos = gCmdLineSettings.ypos;
  1312.    if(gCmdLineSettings.winWidth > 0)
  1313.       gIniSettings.winSizeFact = max((F32) gCmdLineSettings.winWidth / (F32) UserInterface::canvasWidth, 0.15f);
  1314.  
  1315.    if(gCmdLineSettings.masterAddress != "")
  1316.       gMasterAddress.set(gCmdLineSettings.masterAddress);
  1317.    else
  1318.       gMasterAddress.set(gIniSettings.masterAddress);    // This will always have a value
  1319.  
  1320.    if(gCmdLineSettings.name != "")                       // We'll clobber the INI file setting.  Since this
  1321.       gIniSettings.name = gCmdLineSettings.name;         // setting is never saved, we won't mess up our INI
  1322.  
  1323.  
  1324.    // Note that we can be in both clientMode and serverMode (such as when we're hosting a game interactively)
  1325.  
  1326.    if(gCmdLineSettings.clientMode)               // Create ClientGame object
  1327.       gClientGame = new ClientGame(Address());   //   let the system figure out IP address and assign a port
  1328.  
  1329.    //LevelListLoader::buildLevelList();            // Get our level list squared away before we jump off to initHostGame() if that's what's going to happen
  1330.  
  1331.    if(gCmdLineSettings.serverMode)
  1332.       initHostGame(gBindAddress, false);         // Start hosting
  1333.    else if(gCmdLineSettings.connectRemote)       //       or
  1334.       joinGame(gConnectAddress, false, false);   // Connect to a game server (i.e. bypass master matchmaking)
  1335.  
  1336.  
  1337.    // Not immediately starting a connection...  start out with name entry or main menu
  1338.    if(!gCmdLineSettings.connectRemote && !gDedicatedServer)
  1339.    {
  1340.       if(gIniSettings.name == "")
  1341.          gNameEntryUserInterface.activate();
  1342.       else
  1343.       {
  1344.          gMainMenuUserInterface.activate();
  1345.          gReadyToConnectToMaster = true;         // Set elsewhere if in dedicated server mode
  1346.       }
  1347.    }
  1348. }
  1349.  
  1350.  
  1351.  
  1352. };  // namespace Zap
  1353.  
  1354.  
  1355. using namespace Zap;
  1356.  
  1357.  
  1358.  
  1359. #ifdef TNL_OS_XBOX
  1360. int zapmain(int argc, char **argv)
  1361. #else
  1362. int main(int argc, char **argv)
  1363. #endif
  1364. {
  1365. #ifdef TNL_OS_MAC_OSX
  1366.    // Move to the application bundle's path (RDW)
  1367.    moveToAppPath();
  1368. #endif
  1369.  
  1370.  
  1371.    gCmdLineSettings.init();      // Init cmd line settings struct
  1372.    gIniSettings.init();          // Init struct that holds INI settings
  1373.  
  1374.    //setDefaultLevelList();        // Levels we'll play, unless we're told otherwise
  1375.  
  1376.    Vector<TNL::StringPtr> theArgv;
  1377.  
  1378.    // Process some command line args that need to be handled early, like journaling options
  1379.    for(S32 i = 1; i < argc; i++)
  1380.    {
  1381.       //if(!stricmp(argv[i], "-createsampleini")) // Create sample INI file and exit
  1382.       //{
  1383.       //   gINI.Path("bitfighter.ini.sample");
  1384.       //   saveSettingsToINI();
  1385.       //   logprintf("Wrote bitfighter.ini.sample, for version %s/%d", ZAP_GAME_RELEASE, BUILD_VERSION);
  1386.       //   exitGame(0);
  1387.       //}
  1388.       if(!stricmp(argv[i], "-rules"))            // Print current rules and exit
  1389.       {
  1390.          GameType::printRules();
  1391.          exitGame(0);
  1392.       }
  1393.       else if(!stricmp(argv[i], "-jsave"))      // Write game to journal
  1394.       {
  1395.          if(i != argc - 1)
  1396.          {
  1397.             gZapJournal.record(argv[i+1]);
  1398.             i++;
  1399.          }
  1400.       }
  1401.       else if(!stricmp(argv[i], "-jplay"))      // Replay game from journal
  1402.       {
  1403.          if(i != argc - 1)
  1404.          {
  1405.             gZapJournal.load(argv[i+1]);
  1406.             i++;
  1407.          }
  1408.       }
  1409.       else
  1410.          theArgv.push_back(argv[i]);
  1411.    }  // End processing command line args
  1412.  
  1413.    gZapJournal.readCmdLineParams(theArgv);   // Process normal command line params, read INI, and start up
  1414.    gZapJournal.processNextJournalEntry();    // If we're replaying a journal, this will cause the cmd line params to be read from the saved journal
  1415.  
  1416.    gHostingModePhase = NotHosting;
  1417.  
  1418.    loadSettingsFromINI();                    // Read INI
  1419.  
  1420.    processStartupParams();                   // And process command lines and INI settings in a unified way
  1421.  
  1422.    SFXObject::init();
  1423.  
  1424. #ifndef ZAP_DEDICATED
  1425.    if(gClientGame)     // That is, we're starting up in interactive mode, as opposed to running a dedicated server
  1426.    {
  1427.       FXManager::init();                     // Get ready for sparks!!  C'mon baby!!
  1428.       InitJoystick();
  1429.       resetKeyStates();                      // Reset keyboard state mapping to show no keys depressed
  1430.       gAutoDetectedJoystickType = autodetectJoystickType();
  1431.       gOptionsMenuUserInterface.setJoystick(gAutoDetectedJoystickType);     // Will override INI settings, so process INI first
  1432.  
  1433.       glutInitWindowSize(gScreenWidth, gScreenHeight);                      // Does this actually do anything?  Seem to get same result, regardless of params!
  1434.  
  1435.  
  1436.       // On OS X, glutInit changes the working directory to the app
  1437.       // bundle's resource directory.  We don't want that. (RDW)
  1438. #ifdef TNL_OS_MAC_OSX
  1439.       moveToAppPath();
  1440. #endif
  1441.       // InitSdlVideo();      // Get our main SDL rendering window all set up
  1442.       // SDL_ShowCursor(0);   // Hide cursor
  1443.  
  1444.       glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB);
  1445.       glutCreateWindow(gWindowTitle);
  1446.  
  1447.       // Register keyboard/mouse event handlers -- see GLUT docs for details
  1448.       glutDisplayFunc(GLUT_CB_display);        // Called when GLUT thinks display needs to be redrawn
  1449.       glutReshapeFunc(GLUT_CB_reshape);        // Handle window reshape events
  1450.       glutPassiveMotionFunc(GLUT_CB_passivemotion);  // Handle mouse motion when button is not pressed
  1451.       glutMotionFunc(GLUT_CB_motion);          // Handle mouse motion when button is pressed
  1452.       glutKeyboardFunc(GLUT_CB_keydown);       // Handle key-down events for regular keys
  1453.       glutKeyboardUpFunc(GLUT_CB_keyup);       // Handle key-up events for regular keys
  1454.       glutSpecialFunc(GLUT_CB_specialkeydown); // Handle key-down events for special keys
  1455.       glutSpecialUpFunc(GLUT_CB_specialkeyup); // Handle key-up events for special keys
  1456.       glutMouseFunc(GLUT_CB_mouse);            // Handle mouse-clicks
  1457.  
  1458.       glutIdleFunc(idle);                      // Register our idle function.  This will get run whenever GLUT is idling
  1459.       glutSetCursor(GLUT_CURSOR_NONE);         // Turn off the cursor -- we'll turn this back on in the editor, or when the user tries to use mouse to work menus
  1460.  
  1461.       glMatrixMode(GL_PROJECTION);
  1462.       glOrtho(0, gScreenWidth, gScreenHeight, 0, 0, 1);
  1463.       glMatrixMode(GL_MODELVIEW);
  1464.       glLoadIdentity();
  1465.       glTranslatef(gScreenWidth/2, gScreenHeight/2, 0);
  1466.       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1467.       glLineWidth(gDefaultLineWidth);
  1468.  
  1469.       atexit(onExit);
  1470.       gOptionsMenuUserInterface.actualizeScreenMode(true);     // Create a display window
  1471.  
  1472.       glutMainLoop();         // Launch GLUT on it's merry way.  It'll call back with events and when idling.
  1473.       // dedicatedServerLoop();  //    Instead, with SDL, loop forever, running the idle command endlessly
  1474.  
  1475.    }
  1476.    else                       // We're running a dedicated server so...
  1477. #endif
  1478.       dedicatedServerLoop();  //    loop forever, running the idle command endlessly
  1479.  
  1480.    return 0;
  1481. }
Submit a correction or amendment below. Make A New Post
To highlight particular lines, prefix each line with @h@
Syntax highlighting:
Post expiration:
Post exposure:
Name / Title:
Email: