src/tron/gGame.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023 
00024 ***************************************************************************
00025 
00026 */
00027 
00028 #include "eEventNotification.h"
00029 #include "eEventNotification.h"
00030 #include "gStuff.h"
00031 #include "eSoundMixer.h"
00032 #include "eGrid.h"
00033 #include "eTeam.h"
00034 #include "tSysTime.h"
00035 #include "gGame.h"
00036 #include "rTexture.h"
00037 #include "gWall.h"
00038 #include "rConsole.h"
00039 #include "gCycle.h"
00040 #include "eCoord.h"
00041 #include "eTimer.h"
00042 #include "gAIBase.h"
00043 #include "rSysdep.h"
00044 #include "rFont.h"
00045 #include "uMenu.h"
00046 #include "nConfig.h"
00047 #include "rScreen.h"
00048 #include "rViewport.h"
00049 #include "uInput.h"
00050 #include "ePlayer.h"
00051 #include "gSpawn.h"
00052 #include "uInput.h"
00053 #include "uInputQueue.h"
00054 #include "nNetObject.h"
00055 #include "tToDo.h"
00056 #include "gMenus.h"
00057 #include "gCamera.h"
00058 #include "gServerBrowser.h"
00059 #include "gServerFavorites.h"
00060 #include "gFriends.h"
00061 #include "gLogo.h"
00062 #include "gLanguageMenu.h"
00063 #include "nServerInfo.h"
00064 #include "gAICharacter.h"
00065 #include "tDirectories.h"
00066 #include "gTeam.h"
00067 #ifdef ENABLE_ZONESV2
00068 #include "zone/zZone.h"
00069 #endif
00070 #include "gWinZone.h"
00071 #include "eVoter.h"
00072 #include "tRecorder.h"
00073 #include "gStatistics.h"
00074 
00075 #include "tXmlParser.h"
00076 #include "gParser.h"
00077 #include "nAuthentication.h"
00078 
00079 //#include "uWebinterface.h"
00080 
00081 #include "gRotation.h"
00082 
00083 #include <math.h>
00084 #include <stdlib.h>
00085 #include <string>
00086 #include <fstream>
00087 #include <ctype.h>
00088 #include <time.h>
00089 
00090 #include "nSocket.h"
00091 
00092 #include "gArena.h"
00093 gArena Arena;
00094 
00095 #ifdef KRAWALL_SERVER
00096 #include "nKrawall.h"
00097 #endif
00098 
00099 
00100 #ifndef DEDICATED
00101 #include "rSDL.h"
00102 #include <SDL_thread.h>
00103 
00104 #ifdef DEBUG
00105 #ifndef WIN32
00106 //#include <GL/xmesa>
00107 
00108 //static bool fullscreen=1;
00109 #endif
00110 #endif
00111 #endif
00112 
00113 #ifdef DEBUG
00114 //#define CONNECTION_STRESS
00115 #endif
00116 
00117 tCONFIG_ENUM( gGameType );
00118 tCONFIG_ENUM( gFinishType );
00119 
00120 // extra round pause time
00121 static REAL sg_extraRoundTime = 0.0f;
00122 static tSettingItem<REAL> sg_extraRoundTimeConf( "EXTRA_ROUND_TIME", sg_extraRoundTime );
00123 
00124 static REAL sg_lastChatBreakTime = -1.0f;
00125 static tSettingItem<REAL> sg_lastChatBreakTimeConf( "LAST_CHAT_BREAK_TIME", sg_lastChatBreakTime );
00126 
00127 #define DEFAULT_MAP "Anonymous/polygon/regular/square-1.0.1.aamap.xml"
00128 static tString mapfile(DEFAULT_MAP);
00129 
00130 /*
00131 static void sg_ParseMap ( gParser * aParser, tString map_file );
00132 static void change_mapfile(std::istream &s)
00133 {
00134     // read new MAP_FILE value
00135     tString new_mapfile;
00136     new_mapfile.ReadLine(s, true);
00137 
00138     if (new_mapfile == mapfile)
00139         return;
00140 
00141     // verify the map loads
00142     try {
00143         sg_ParseMap(aParser, new_mapfile);
00144     } catch (tGenericException &e) {
00145         sn_ConsoleOut( e.GetName(), e.GetDescription(), 120000 );
00146         sg_ParseMap(aParser);   // is this necessary?
00147         return;
00148     }
00149 
00150     if (printChange)
00151     {
00152         tOutput o;
00153         o.SetTemplateParameter(1, "MAP_FILE");
00154         o.SetTemplateParameter(2, mapfile);
00155         o.SetTemplateParameter(3, new_mapfile);
00156         o << "$config_value_changed";
00157         con << o;
00158     }
00159 
00160     mapfile = new_mapfile;
00161 }
00162 */
00163 static nSettingItemWatched<tString> conf_mapfile("MAP_FILE",mapfile, nConfItemVersionWatcher::Group_Breaking, 8 );
00164 
00165 // config item for semi-colon deliminated list of maps/configs, needs semi-colon at the end
00166 // ie, original/map-1.0.1.xml;original/map-1.0.1.xml;
00167 class tSettingRotation: public tConfItemBase
00168 {
00169 public:
00170     tSettingRotation( char const * name )
00171     : tConfItemBase( name ),
00172       current_(0)
00173     {
00174     }
00175 
00176     // the number of items
00177     int Size() const
00178     {
00179         return items_.Len();
00180     }
00181 
00182     // returns the current value
00183     tString const & Current() const
00184     {
00185         tASSERT( Size() > 0 && current_ >= 0 && current_ < Size() );
00186 
00187         return items_[current_];
00188     }
00189 
00190     // rotates
00191     void Rotate()
00192     {
00193         if ( ++current_ >= items_.Len() )
00194         {
00195             current_ = 0;
00196         }
00197     }
00198 private:
00199     virtual void ReadVal( std::istream &is )
00200     {
00201         tString mapsT;
00202         mapsT.ReadLine (is);
00203         items_.SetLen (0);
00204         
00205         int strpos = 0;
00206         int nextsemicolon = mapsT.StrPos(";");
00207         
00208         if (nextsemicolon != -1)
00209         {
00210             do
00211             {
00212                 tString const &map = mapsT.SubStr(strpos, nextsemicolon - strpos);
00213                 
00214                 strpos = nextsemicolon + 1;
00215                 nextsemicolon = mapsT.StrPos(strpos, ";");
00216                 
00217                 items_.Insert(map);
00218             }
00219             while ((nextsemicolon = mapsT.StrPos(strpos, ";")) != -1);
00220         }
00221 
00222         // make sure the current value is correct
00223         if ( current_ >= items_.Len() )
00224         {
00225             current_ = 0;
00226         }
00227     }
00228 
00229     virtual void WriteVal(std::ostream &s){}
00230     virtual bool Writable(){return false;}
00231     virtual bool Save(){return false;}
00232 
00233     tArray<tString> items_; // the various values the rotating config can take
00234     int current_;           // the index of the current 
00235 };
00236 
00237 static tSettingRotation sg_mapRotation("MAP_ROTATION");
00238 static tSettingRotation sg_configRotation("CONFIG_ROTATION");
00239 
00240 //0 = never, 1 = round, 2 = match
00241 static int rotationtype = 0;
00242 static tSettingItem<int> conf_rotationtype("ROTATION_TYPE",rotationtype);
00243 
00244 // bool globalingame=false;
00245 tString sg_GetCurrentTime( char const * szFormat )
00246 {
00247     char szTemp[128];
00248     time_t     now;
00249     struct tm *pTime;
00250     now = time(NULL);
00251     pTime = localtime(&now);
00252     strftime(szTemp,sizeof(szTemp),szFormat,pTime);
00253     return tString(szTemp);
00254 }
00255 
00256 void sg_PrintCurrentTime( char const * szFormat )
00257 {
00258     con << sg_GetCurrentTime(szFormat);
00259 }
00260 
00261 void sg_PrintCurrentDate()
00262 {
00263     sg_PrintCurrentTime( "%Y%m%d");
00264 }
00265 
00266 void sg_PrintCurrentTime()
00267 {
00268     sg_PrintCurrentTime( "%H%M%S" );
00269 }
00270 
00271 void sg_Timestamp()
00272 {
00273 #ifdef DEDICATED
00274     sg_PrintCurrentTime( "Timestamp: %Y/%m/%d %H:%M:%S\n" );
00275     if ( tRecorder::IsRunning() )
00276     {
00277         con << "Uptime: " << int(tSysTimeFloat()) << " seconds.\n";
00278 
00279 #ifdef DEBUG_X
00280         // to set breakpoints at specific round starts
00281         static double breakTime = 0;
00282         if ( tSysTimeFloat() > breakTime )
00283             st_Breakpoint();
00284 #endif
00285     }
00286 #endif
00287 }
00288 
00289 static REAL ded_idle=24;
00290 static tSettingItem<REAL> dedicaded_idle("DEDICATED_IDLE",ded_idle);
00291 
00292 static float sg_gameTimeInterval=-1;
00293 static tSettingItem<float> sggti("LADDERLOG_GAME_TIME_INTERVAL",
00294                                  sg_gameTimeInterval);
00295 
00296 #define MAXAI (gAICharacter::s_Characters.Len())
00297 
00298 #define AUTO_AI_MAXFRAC 6
00299 #define AUTO_AI_WIN     3
00300 #define AUTO_AI_LOSE    1
00301 
00302 gGameSettings::gGameSettings(int a_scoreWin,
00303                              int a_limitTime, int a_limitRounds, int a_limitScore,
00304                              int a_numAIs,    int a_minPlayers,  int a_AI_IQ,
00305                              bool a_autoNum, bool a_autoIQ,
00306                              int a_speedFactor, int a_sizeFactor,
00307                              gGameType a_gameType,  gFinishType a_finishType,
00308                              int a_minTeams,
00309                              int a_winZoneMinRoundTime, int a_winZoneMinLastDeath
00310                             )
00311         :scoreWin(a_scoreWin),
00312         limitTime(a_limitTime), limitRounds(a_limitRounds), limitScore(a_limitScore),
00313         numAIs(a_numAIs),       minPlayers(a_minPlayers),   AI_IQ(a_AI_IQ),
00314         autoNum(a_autoNum),     autoIQ(a_autoIQ),
00315         speedFactor(a_speedFactor), sizeFactor(a_sizeFactor),
00316         winZoneMinRoundTime( a_winZoneMinRoundTime ),winZoneMinLastDeath( a_winZoneMinLastDeath ),
00317         gameType(a_gameType),   finishType(a_finishType),
00318         minTeams(a_minTeams)
00319 {
00320     autoAIFraction = AUTO_AI_MAXFRAC >> 1;
00321 
00322     maxTeams = 16;
00323     minPlayersPerTeam = 1;
00324     maxPlayersPerTeam = 10;
00325     maxTeamImbalance = 1;
00326     balanceTeamsWithAIs = true;
00327     enforceTeamRulesOnQuit = false;
00328 
00329     wallsStayUpDelay = 2.0f;
00330     wallsLength      = -1.0f;
00331     explosionRadius  = 4.0f;
00332 }
00333 
00334 void gGameSettings::AutoAI(bool success){
00335     if (!autoNum && !autoIQ)
00336         return;
00337 
00338     if (autoNum)
00339     {
00340         if (success)
00341         {
00342             autoAIFraction += AUTO_AI_WIN;
00343             while (autoAIFraction > AUTO_AI_MAXFRAC)
00344             {
00345                 autoAIFraction -= AUTO_AI_MAXFRAC;
00346                 if (numAIs < MAXAI) numAIs++;
00347             }
00348         }
00349         else
00350         {
00351             autoAIFraction -= AUTO_AI_LOSE;
00352             while (autoAIFraction < 0)
00353             {
00354                 autoAIFraction += AUTO_AI_MAXFRAC;
00355                 if (numAIs >= 2) numAIs--;
00356             }
00357         }
00358     }
00359 
00360 
00361     if (autoIQ)
00362     {
00363         if (!autoNum)
00364             AI_IQ += 4 * (success ? AUTO_AI_WIN : -AUTO_AI_LOSE);
00365         else
00366         {
00367             int total = numAIs * numAIs * AI_IQ;
00368             // try to keep total around 100: that is either 10 dumb AIs or
00369             // one smart AI.
00370 
00371             if (success)
00372                 if (total > 100)
00373                     AI_IQ += AUTO_AI_WIN * 4;
00374                 else
00375                     AI_IQ += AUTO_AI_WIN;
00376             else
00377                 if (total < 100)
00378                     AI_IQ -= AUTO_AI_LOSE * 4;
00379                 else
00380                     AI_IQ -= AUTO_AI_LOSE;
00381         }
00382     }
00383 
00384     if (AI_IQ > 100)
00385         AI_IQ = 100;
00386     if (AI_IQ < 0)
00387         AI_IQ = 0;
00388 }
00389 
00390 
00391 void gGameSettings::Menu()
00392 {
00393     uMenu GameSettings("$game_settings_menu_text");
00394 
00395     uMenuItemInt wzmr
00396     (&GameSettings,
00397      "$game_menu_wz_mr_text",
00398      "$game_menu_wz_mr_help",
00399      winZoneMinRoundTime,0,1000,10);
00400 
00401     uMenuItemInt wzmld
00402     (&GameSettings,
00403      "$game_menu_wz_ld_text",
00404      "$game_menu_wz_ld_help",
00405      winZoneMinLastDeath,0,1000,10);
00406 
00407     uMenuItemToggle team_et
00408     (&GameSettings,
00409      "$game_menu_balance_quit_text",
00410      "$game_menu_balance_quit_help",
00411      enforceTeamRulesOnQuit);
00412 
00413     uMenuItemToggle team_bt
00414     (&GameSettings,
00415      "$game_menu_balance_ais_text",
00416      "$game_menu_balance_ais_help",
00417      balanceTeamsWithAIs);
00418 
00419     uMenuItemInt team_mi
00420     (&GameSettings,
00421      "$game_menu_imb_text",
00422      "$game_menu_imb_help",
00423      maxTeamImbalance,2,10);
00424 
00425     uMenuItemInt team_maxp
00426     (&GameSettings,
00427      "$game_menu_max_players_text",
00428      "$game_menu_max_players_help",
00429      maxPlayersPerTeam,1,16);
00430 
00431     uMenuItemInt team_minp
00432     (&GameSettings,
00433      "$game_menu_min_players_text",
00434      "$game_menu_min_players_help",
00435      minPlayersPerTeam,1,16);
00436 
00437     uMenuItemInt team_max
00438     (&GameSettings,
00439      "$game_menu_max_teams_text",
00440      "$game_menu_max_teams_help",
00441      maxTeams,1,16);
00442 
00443     uMenuItemInt team_min
00444     (&GameSettings,
00445      "$game_menu_min_teams_text",
00446      "$game_menu_min_teams_help",
00447      minTeams,1,16);
00448 
00449     uMenuItemSelection<gFinishType> finisht
00450     (&GameSettings,"$game_menu_finish_text",
00451      "$game_menu_finish_help",finishType);
00452     finisht.NewChoice("$game_menu_finish_expr_text",
00453                       "$game_menu_finish_expr_help",
00454                       gFINISH_EXPRESS);
00455     finisht.NewChoice("$game_menu_finish_stop_text",
00456                       "$game_menu_finish_stop_help",
00457                       gFINISH_IMMEDIATELY);
00458     finisht.NewChoice("$game_menu_finish_fast_text",
00459                       "$game_menu_finish_fast_help",
00460                       gFINISH_SPEEDUP);
00461     finisht.NewChoice("$game_menu_finish_normal_text",
00462                       "$game_menu_finish_normal_help",
00463                       gFINISH_NORMAL);
00464 
00465     uMenuItemSelection<gGameType> gamet
00466     (&GameSettings,"$game_menu_mode_text",
00467      "$game_menu_mode_help",gameType);
00468     gamet.NewChoice("$game_menu_mode_free_text",
00469                     "$game_menu_mode_free_help",
00470                     gFREESTYLE);
00471     gamet.NewChoice("$game_menu_mode_lms_text",
00472                     "$game_menu_mode_lms_help",
00473                     gDUEL);
00474     /*
00475         gamet.NewChoice("$game_menu_mode_team_text",
00476                                         "$game_menu_mode_team_help",
00477                                         gHUMAN_VS_AI);
00478     */
00479 
00480     uMenuItemInt speedconf
00481     (&GameSettings,
00482      "$game_menu_speed_text",
00483      "$game_menu_speed_help",
00484      speedFactor,-10,10);
00485 
00486     uMenuItemInt sizeconf
00487     (&GameSettings,
00488      "$game_menu_size_text",
00489      "$game_menu_size_help",
00490      sizeFactor,-10,10);
00491 
00492     uMenuItemSelection<REAL> wsuconf
00493     (&GameSettings,
00494      "$game_menu_wallstayup_text",
00495      "$game_menu_wallstayup_help",
00496      wallsStayUpDelay);
00497     wsuconf.NewChoice( "$game_menu_wallstayup_infinite_text",
00498                        "$game_menu_wallstayup_infinite_help",
00499                        -1.0f );
00500     wsuconf.NewChoice( "$game_menu_wallstayup_immediate_text",
00501                        "$game_menu_wallstayup_immediate_help",
00502                        0.0f );
00503     wsuconf.NewChoice( "$game_menu_wallstayup_halfsecond_text",
00504                        "$game_menu_wallstayup_halfsecond_help",
00505                        0.5f );
00506     wsuconf.NewChoice( "$game_menu_wallstayup_second_text",
00507                        "$game_menu_wallstayup_second_help",
00508                        1.0f );
00509     wsuconf.NewChoice( "$game_menu_wallstayup_2second_text",
00510                        "$game_menu_wallstayup_2second_help",
00511                        2.0f );
00512     wsuconf.NewChoice( "$game_menu_wallstayup_4second_text",
00513                        "$game_menu_wallstayup_4second_help",
00514                        4.0f );
00515     wsuconf.NewChoice( "$game_menu_wallstayup_8second_text",
00516                        "$game_menu_wallstayup_8second_help",
00517                        8.0f );
00518     wsuconf.NewChoice( "$game_menu_wallstayup_16second_text",
00519                        "$game_menu_wallstayup_16second_help",
00520                        16.0f );
00521     wsuconf.NewChoice( "$game_menu_wallstayup_32second_text",
00522                        "$game_menu_wallstayup_32second_help",
00523                        32.0f );
00524 
00525     uMenuItemSelection<REAL> wlconf
00526     (&GameSettings,
00527      "$game_menu_wallslength_text",
00528      "$game_menu_wallslength_help",
00529      wallsLength);
00530     wlconf.NewChoice( "$game_menu_wallslength_infinite_text",
00531                       "$game_menu_wallslength_infinite_help",
00532                       -1.0f );
00533     wlconf.NewChoice( "$game_menu_wallslength_25meter_text",
00534                       "$game_menu_wallslength_25meter_help",
00535                       25.0f );
00536     wlconf.NewChoice( "$game_menu_wallslength_50meter_text",
00537                       "$game_menu_wallslength_50meter_help",
00538                       50.0f );
00539     wlconf.NewChoice( "$game_menu_wallslength_100meter_text",
00540                       "$game_menu_wallslength_100meter_help",
00541                       100.0f );
00542     wlconf.NewChoice( "$game_menu_wallslength_200meter_text",
00543                       "$game_menu_wallslength_200meter_help",
00544                       200.0f );
00545     wlconf.NewChoice( "$game_menu_wallslength_300meter_text",
00546                       "$game_menu_wallslength_300meter_help",
00547                       300.0f );
00548     wlconf.NewChoice( "$game_menu_wallslength_400meter_text",
00549                       "$game_menu_wallslength_400meter_help",
00550                       400.0f );
00551     wlconf.NewChoice( "$game_menu_wallslength_600meter_text",
00552                       "$game_menu_wallslength_600meter_help",
00553                       600.0f );
00554     wlconf.NewChoice( "$game_menu_wallslength_800meter_text",
00555                       "$game_menu_wallslength_800meter_help",
00556                       800.0f );
00557     wlconf.NewChoice( "$game_menu_wallslength_1200meter_text",
00558                       "$game_menu_wallslength_1200meter_help",
00559                       1200.0f );
00560     wlconf.NewChoice( "$game_menu_wallslength_1600meter_text",
00561                       "$game_menu_wallslength_1600meter_help",
00562                       1600.0f );
00563 
00564     uMenuItemSelection<REAL> erconf
00565     (&GameSettings,
00566      "$game_menu_exrad_text",
00567      "$game_menu_exrad_help",
00568      explosionRadius);
00569     erconf.NewChoice( "$game_menu_exrad_0_text",
00570                       "$game_menu_exrad_0_help",
00571                       0.0f );
00572     erconf.NewChoice( "$game_menu_exrad_2meters_text",
00573                       "$game_menu_exrad_2meters_help",
00574                       2.0f );
00575     erconf.NewChoice( "$game_menu_exrad_4meters_text",
00576                       "$game_menu_exrad_4meters_help",
00577                       4.0f );
00578     erconf.NewChoice( "$game_menu_exrad_8meters_text",
00579                       "$game_menu_exrad_8meters_help",
00580                       8.0f );
00581     erconf.NewChoice( "$game_menu_exrad_16meters_text",
00582                       "$game_menu_exrad_16meters_help",
00583                       16.0f );
00584     erconf.NewChoice( "$game_menu_exrad_32meters_text",
00585                       "$game_menu_exrad_32meters_help",
00586                       32.0f );
00587     erconf.NewChoice( "$game_menu_exrad_64meters_text",
00588                       "$game_menu_exrad_64meters_help",
00589                       64.0f );
00590     erconf.NewChoice( "$game_menu_exrad_128meters_text",
00591                       "$game_menu_exrad_128meters_help",
00592                       128.0f );
00593 
00594     uMenuItemToggle autoiqconf
00595     (&GameSettings,
00596      "$game_menu_autoiq_text",
00597      "$game_menu_autoiq_help",
00598      autoIQ);
00599 
00600     uMenuItemToggle autoaiconf
00601     (&GameSettings,
00602      "$game_menu_autoai_text",
00603      "$game_menu_autoai_help",
00604      autoNum);
00605 
00606 
00607     uMenuItemInt iqconf
00608     (&GameSettings,
00609      "$game_menu_iq_text",
00610      "$game_menu_iq_help",
00611      AI_IQ, 20, 100, 10);
00612 
00613     uMenuItemInt mpconf
00614     (&GameSettings,
00615      "$game_menu_minplayers_text",
00616      "$game_menu_minplayers_help",
00617      minPlayers,0,MAXAI);
00618 
00619     uMenuItemInt aiconf
00620     (&GameSettings,
00621      "$game_menu_ais_text",
00622      "$game_menu_ais_help",
00623      numAIs,0,MAXAI);
00624 
00625 
00626     GameSettings.Enter();
00627 }
00628 
00629 gGameSettings singlePlayer(10,
00630                            30, 10, 100000,
00631                            1,   0, 30,
00632                            true, true,
00633                            0  ,  -3,
00634                            gDUEL, gFINISH_IMMEDIATELY, 1,
00635                            100000, 1000000);
00636 
00637 gGameSettings multiPlayer(10,
00638                           30, 10, 100,
00639                           0,   4, 100,
00640                           false, false,
00641                           0  ,  -3,
00642                           gDUEL, gFINISH_IMMEDIATELY, 2,
00643                           60, 30 );
00644 
00645 gGameSettings* sg_currentSettings = &singlePlayer;
00646 
00647 
00648 
00649 static tSettingItem<int> mp_sw("SCORE_WIN"   ,multiPlayer.scoreWin);
00650 static tSettingItem<int> mp_lt("LIMIT_TIME"  ,multiPlayer.limitTime);
00651 static tSettingItem<int> mp_lr("LIMIT_ROUNDS",multiPlayer.limitRounds);
00652 static tSettingItem<int> mp_ls("LIMIT_SCORE" ,multiPlayer.limitScore);
00653 
00654 static tConfItem<int>    mp_na("NUM_AIS"     ,multiPlayer.numAIs);
00655 static tConfItem<int>    mp_mp("MIN_PLAYERS" ,multiPlayer.minPlayers);
00656 static tConfItem<int>    mp_iq("AI_IQ"       ,multiPlayer.AI_IQ);
00657 
00658 static tConfItem<bool>   mp_an("AUTO_AIS"    ,multiPlayer.autoNum);
00659 static tConfItem<bool>   mp_aq("AUTO_IQ"     ,multiPlayer.autoIQ);
00660 
00661 static tConfItem<int>    mp_sf("SPEED_FACTOR",multiPlayer.speedFactor);
00662 static tConfItem<int>    mp_zf("SIZE_FACTOR" ,multiPlayer.sizeFactor);
00663 
00664 static tConfItem<gGameType>    mp_gt("GAME_TYPE",multiPlayer.gameType);
00665 static tConfItem<gFinishType>  mp_ft("FINISH_TYPE",multiPlayer.finishType);
00666 
00667 static tConfItem<int>    mp_wzmr("WIN_ZONE_MIN_ROUND_TIME",multiPlayer.winZoneMinRoundTime);
00668 static tConfItem<int>    mp_wzld("WIN_ZONE_MIN_LAST_DEATH",multiPlayer.winZoneMinLastDeath);
00669 
00670 static tConfItem<int>    mp_tmin        ("TEAMS_MIN",                                   multiPlayer.minTeams);
00671 static tConfItem<int>    mp_tmax        ("TEAMS_MAX",                                   multiPlayer.maxTeams);
00672 static tConfItem<int>    mp_mtp         ("TEAM_MIN_PLAYERS",                    multiPlayer.minPlayersPerTeam);
00673 static tConfItem<int>    mp_tp          ("TEAM_MAX_PLAYERS",                    multiPlayer.maxPlayersPerTeam);
00674 static tConfItem<int>    mp_tib         ("TEAM_MAX_IMBALANCE",                  multiPlayer.maxTeamImbalance);
00675 static tConfItem<bool>   mp_tbai        ("TEAM_BALANCE_WITH_AIS",               multiPlayer.balanceTeamsWithAIs);
00676 static tConfItem<bool>   mp_tboq        ("TEAM_BALANCE_ON_QUIT",                multiPlayer.enforceTeamRulesOnQuit);
00677 
00678 static tConfItem<REAL>   mp_wsu         ("WALLS_STAY_UP_DELAY"  ,               multiPlayer.wallsStayUpDelay);
00679 static tConfItem<REAL>   mp_wl          ("WALLS_LENGTH"             ,           multiPlayer.wallsLength     );
00680 static tConfItem<REAL>   mp_er          ("EXPLOSION_RADIUS"             ,               multiPlayer.explosionRadius );
00681 
00682 static tSettingItem<int> sp_sw("SP_SCORE_WIN"   ,singlePlayer.scoreWin);
00683 static tSettingItem<int> sp_lt("SP_LIMIT_TIME"  ,singlePlayer.limitTime);
00684 static tSettingItem<int> sp_lr("SP_LIMIT_ROUNDS",singlePlayer.limitRounds);
00685 static tSettingItem<int> sp_ls("SP_LIMIT_SCORE" ,singlePlayer.limitScore);
00686 
00687 static tConfItem<int>    sp_na("SP_NUM_AIS"     ,singlePlayer.numAIs);
00688 static tConfItem<int>    sp_mp("SP_MIN_PLAYERS" ,singlePlayer.minPlayers);
00689 static tConfItem<int>    sp_iq("SP_AI_IQ"       ,singlePlayer.AI_IQ);
00690 
00691 static tConfItem<bool>   sp_an("SP_AUTO_AIS"    ,singlePlayer.autoNum);
00692 static tConfItem<bool>   sp_aq("SP_AUTO_IQ"     ,singlePlayer.autoIQ);
00693 
00694 static tConfItem<int>    sp_sf("SP_SPEED_FACTOR",singlePlayer.speedFactor);
00695 static tConfItem<int>    sp_zf("SP_SIZE_FACTOR" ,singlePlayer.sizeFactor);
00696 
00697 static tConfItem<gGameType>    sp_gt("SP_GAME_TYPE",singlePlayer.gameType);
00698 static tConfItem<gFinishType>  sp_ft("SP_FINISH_TYPE",singlePlayer.finishType);
00699 
00700 static tConfItem<int>    sp_wzmr("SP_WIN_ZONE_MIN_ROUND_TIME",singlePlayer.winZoneMinRoundTime);
00701 static tConfItem<int>    sp_wzld("SP_WIN_ZONE_MIN_LAST_DEATH",singlePlayer.winZoneMinLastDeath);
00702 
00703 static tConfItem<int>    sp_tmin        ("SP_TEAMS_MIN",                                        singlePlayer.minTeams);
00704 static tConfItem<int>    sp_tmax        ("SP_TEAMS_MAX",                                        singlePlayer.maxTeams);
00705 static tConfItem<int>    sp_mtp         ("SP_TEAM_MIN_PLAYERS",                         singlePlayer.minPlayersPerTeam);
00706 static tConfItem<int>    sp_tp          ("SP_TEAM_MAX_PLAYERS",                         singlePlayer.maxPlayersPerTeam);
00707 static tConfItem<int>    sp_tib         ("SP_TEAM_MAX_IMBALANCE",                       singlePlayer.maxTeamImbalance);
00708 static tConfItem<bool>   sp_tbai        ("SP_TEAM_BALANCE_WITH_AIS",            singlePlayer.balanceTeamsWithAIs);
00709 static tConfItem<bool>   sp_tboq        ("SP_TEAM_BALANCE_ON_QUIT",             singlePlayer.enforceTeamRulesOnQuit);
00710 
00711 static tConfItem<REAL>   sp_wsu         ("SP_WALLS_STAY_UP_DELAY"       ,               singlePlayer.wallsStayUpDelay);
00712 static tConfItem<REAL>   sp_wl          ("SP_WALLS_LENGTH"                  ,           singlePlayer.wallsLength     );
00713 static tConfItem<REAL>   sp_er          ("SP_EXPLOSION_RADIUS"          ,               singlePlayer.explosionRadius );
00714 
00715 static void GameSettingsMP(){
00716     multiPlayer.Menu();
00717 }
00718 
00719 static void GameSettingsSP(){
00720     singlePlayer.Menu();
00721 }
00722 
00723 static void GameSettingsCurrent(){
00724     sg_currentSettings->Menu();
00725 }
00726 
00727 static REAL sg_Timeout = 5.0f;
00728 static tConfItem<REAL>   sg_ctimeout("GAME_TIMEOUT"             ,               sg_Timeout );
00729 
00730 bool sg_TalkToMaster = true;
00731 static tSettingItem<bool> sg_ttm("TALK_TO_MASTER",
00732                                  sg_TalkToMaster);
00733 
00734 #define PREPARE_TIME 4
00735 
00736 static bool just_connected=true;
00737 static bool sg_singlePlayer=0;
00738 static int winner=0;
00739 static int absolute_winner=0;
00740 static REAL lastTime_gameloop=0;
00741 static REAL lastTimeTimestep=0;
00742 
00743 static int wishWinner = 0;
00744 static char const * wishWinnerMessage = "";
00745 
00746 void sg_DeclareWinner( eTeam* team, char const * message )
00747 {
00748     if ( team && !winner )
00749     {
00750         wishWinner = team->TeamID() + 1;
00751         wishWinnerMessage = message;
00752     }
00753 }
00754 
00755 
00756 static tCONTROLLED_PTR(gGame) sg_currentGame;
00757 
00758 
00759 
00760 /*
00761 static gCycle *Cycle(int id){
00762   eGameObject *object=NULL;
00763   for(int i=se_PlayerNetIDs.Len()-1;i>=0;i--)
00764     if (se_PlayerNetIDs[i]->pID==id && se_PlayerNetIDs[i]->Object())
00765       object=se_PlayerNetIDs[i]->Object();
00766 
00767   return dynamic_cast<gCycle *>(object);
00768 }
00769 */
00770 
00771 #ifdef POWERPAK_DEB
00772 #include "PowerPak/poweruInput.h"
00773 #include "PowerPak/joystick.h"
00774 #endif
00775 
00776 #include "rRender.h"
00777 
00778 
00779 
00780 void exit_game_grid(eGrid *grid){
00781     grid->Clear();
00782 }
00783 
00784 void exit_game_objects(eGrid *grid){
00785     sr_con.fullscreen=true;
00786 
00787     su_prefetchInput=false;
00788 
00789     int i;
00790     for (i=ePlayer::Num()-1;i>=0;i--){
00791         if (ePlayer::PlayerConfig(i))
00792             tDESTROY(ePlayer::PlayerConfig(i)->cam);
00793     }
00794 
00795     eGameObject::DeleteAll(grid);
00796 
00797     if (sn_GetNetState()!=nCLIENT)
00798         for (int i=se_PlayerNetIDs.Len()-1;i>=0;i--)
00799             if (se_PlayerNetIDs(i))
00800                 se_PlayerNetIDs(i)->ClearObject();
00801 
00802     gNetPlayerWall::Clear();
00803 
00804     exit_game_grid(grid);
00805 }
00806 
00807 REAL exponent(int i)
00808 {
00809     int abs = i;
00810     if ( abs < 0 )
00811         abs = -abs;
00812 
00813     REAL ret = 1;
00814     REAL fac = sqrtf(2);
00815 
00816     while (abs > 0)
00817     {
00818         if ( 1 == (abs & 1) )
00819             ret *= fac;
00820 
00821         fac *= fac;
00822         abs >>= 1;
00823     }
00824 
00825     if (i < 0)
00826         ret = 1/ret;
00827 
00828     return ret;
00829 }
00830 
00831 #ifndef DEDICATED
00832 extern REAL stc_fastestSpeedRound;
00833 #endif
00834 extern bool sg_axesIndicator;
00835 
00836 void init_game_grid(eGrid *grid, gParser *aParser){
00837     se_ResetGameTimer();
00838     se_PauseGameTimer(true);
00839 
00840 #ifndef DEDICATED
00841     if (sr_glOut){
00842         sr_ResetRenderState();
00843 
00844         // rSysDep::ClearGL();
00845 
00846         // glViewport (0, 0, static_cast<GLsizei>(sr_screenWidth), static_cast<GLsizei>(sr_screenHeight));
00847 
00848         // rSysDep::SwapGL();
00849     }
00850     stc_fastestSpeedRound = .0;
00851 #endif
00852 
00853     /*
00854       if(!speedup)
00855       SDL_Delay(1000);
00856     */
00857 
00858     Arena.PrepareGrid(grid, aParser);
00859 
00860     absolute_winner=winner=wishWinner=0;
00861 }
00862 
00863 int sg_NumHumans()
00864 {
00865     int humans = 0;
00866     for (int i = se_PlayerNetIDs.Len()-1; i>=0; i--)
00867     {
00868         ePlayerNetID* p = se_PlayerNetIDs(i);
00869         if (p->IsHuman() && p->IsActive() && ( bool(p->CurrentTeam()) || bool(p->NextTeam()) ) )
00870             humans++;
00871     }
00872 
00873     return humans;
00874 }
00875 
00876 int sg_NumUsers()
00877 {
00878     // return se_PlayerNetIDs.Len() ;
00879 #ifdef DEDICATED
00880     return sn_NumUsers();
00881 #else
00882     return sn_NumUsers() + 1;
00883 #endif
00884 }
00885 
00886 static void sg_copySettings()
00887 {
00888     eTeam::minTeams                                     = sg_currentSettings->minTeams;
00889     eTeam::maxTeams                                     = sg_currentSettings->maxTeams;
00890     eTeam::maxPlayers                           = sg_currentSettings->maxPlayersPerTeam;
00891     eTeam::minPlayers                           = sg_currentSettings->minPlayersPerTeam;
00892     eTeam::maxImbalance                         = sg_currentSettings->maxTeamImbalance;
00893     eTeam::balanceWithAIs                       = sg_currentSettings->balanceTeamsWithAIs;
00894     eTeam::enforceRulesOnQuit           = sg_currentSettings->enforceTeamRulesOnQuit;
00895 
00896     gCycle::SetWallsStayUpDelay ( sg_currentSettings->wallsStayUpDelay  );
00897     gCycle::SetWallsLength              ( sg_currentSettings->wallsLength               );
00898     gCycle::SetExplosionRadius  ( sg_currentSettings->explosionRadius   );
00899     gCycle::SetSpeedMultiplier  ( exponent( sg_currentSettings->speedFactor ) );
00900     gArena::SetSizeMultiplier   ( exponent( sg_currentSettings->sizeFactor ) );
00901 }
00902 
00903 void update_settings()
00904 {
00905     if (sn_GetNetState()!=nCLIENT)
00906     {
00907 #ifdef DEDICATED
00908         // wait for players to join
00909         {
00910             bool restarted = false;
00911 
00912             REAL timeout = tSysTimeFloat() + 3.0f;
00913             while ( sg_NumHumans() <= 0 && sg_NumUsers() > 0 )
00914             {
00915                 if ( !restarted && bool(sg_currentGame) )
00916                 {
00917                     sg_currentGame->StartNewMatch();
00918                     restarted = true;
00919                 }
00920 
00921                 if ( tSysTimeFloat() > timeout )
00922                 {
00923                     tOutput o("$gamestate_wait_players");
00924                     sn_CenterMessage(o);
00925 
00926                     tOutput o2("$gamestate_wait_players_con");
00927                     sn_ConsoleOut(o2);
00928 
00929                     timeout = tSysTimeFloat() + 10.0f;
00930 
00931                     // do tasks
00932                     st_DoToDo();
00933                     nAuthentication::OnBreak();
00934                 }
00935 
00936                 // kick spectators and chatbots
00937                 nMachine::KickSpectators();
00938                 ePlayerNetID::RemoveChatbots();
00939 
00940                 // wait for network messages
00941                 sn_BasicNetworkSystem.Select( 0.1f );
00942                 gGame::NetSyncIdle();
00943 
00944                 // handle console input
00945                 sr_Read_stdin();
00946             }
00947         }
00948 
00949         if ( sg_NumUsers() <= 0 && bool( sg_currentGame ) )
00950         {
00951             sg_currentGame->NoLongerGoOn();
00952         }
00953 
00954         // count the active players
00955         int humans = sg_NumHumans();
00956 
00957         bool newsg_singlePlayer = (humans<=1);
00958 #else
00959         bool newsg_singlePlayer = (sn_GetNetState() == nSTANDALONE);
00960 #endif
00961         if (sg_singlePlayer != newsg_singlePlayer && bool( sg_currentGame ) )
00962         {
00963             sg_currentGame->StartNewMatch();
00964         }
00965         sg_singlePlayer=newsg_singlePlayer;
00966 
00967         if (sg_singlePlayer)
00968             sg_currentSettings = &singlePlayer;
00969         else
00970             sg_currentSettings = &multiPlayer;
00971 
00972         sg_copySettings();
00973     }
00974 
00975     // update team properties
00976     for (int i = eTeam::teams.Len() - 1; i>=0; --i)
00977         eTeam::teams(i)->UpdateProperties();
00978 }
00979 
00980 static int sg_spawnPointGroupSize=0;
00981 static tSettingItem< int > sg_spawnPointGroupSizeConf( "SPAWN_POINT_GROUP_SIZE", sg_spawnPointGroupSize );
00982 
00983 void init_game_objects(eGrid *grid){
00984     /*
00985       static REAL r[MAX_PLAYERS]={1,.2,.2,1};
00986       static REAL g[MAX_PLAYERS]={.2,1,.2,1};
00987       static REAL b[MAX_PLAYERS]={.2,.2,1,.2};
00988     */
00989 
00990     if (sn_GetNetState()!=nCLIENT)
00991     {
00992         // update team settings
00993         gAIPlayer::SetNumberOfAIs(sg_currentSettings->numAIs,
00994                                   sg_currentSettings->minPlayers,
00995                                   sg_currentSettings->AI_IQ);
00996 
00997         int spawnPointsUsed = 0;
00998         for (int t=eTeam::teams.Len()-1;t>=0;t--)
00999         {
01000             eTeam *team = eTeam::teams(t);
01001             team->Update();
01002 
01003             gSpawnPoint *spawn = Arena.LeastDangerousSpawnPoint();
01004             spawnPointsUsed++;
01005 
01006             // if the spawn points are grouped, make sure the last player is not in a goup of his
01007             // own by skipping one spawnpoint
01008             if ( ( eTeam::teams(0)->IsHuman() || eTeam::teams(0)->NumPlayers() == 1 ) && sg_spawnPointGroupSize > 2 && ( spawnPointsUsed % sg_spawnPointGroupSize == sg_spawnPointGroupSize - 1 ) )
01009             {
01010                 // the next spawn point is the last of this group. Skip it if
01011                 // either only two players are left (and the one would need to play alone)
01012                 // or we can fill the remaining groups well with one player short.
01013                 if ( t == 2 || ( ( t % ( sg_spawnPointGroupSize - 1 ) ) == 0 && t < ( sg_spawnPointGroupSize - 1 ) * ( sg_spawnPointGroupSize - 1 ) ) )
01014                 {
01015                     eCoord pos, dir;
01016                     spawn->Spawn( pos, dir );
01017                     spawn = Arena.LeastDangerousSpawnPoint();
01018                     spawnPointsUsed++;
01019                 }
01020             }
01021 
01022             int numPlayers = team->NumPlayers();
01023             for (int p = 0; p<numPlayers; ++p)
01024             {
01025                 ePlayerNetID *pni=team->Player( p );
01026 
01027                 if ( !team->IsHuman() )
01028                 {
01029                     spawn = Arena.LeastDangerousSpawnPoint();
01030                     spawnPointsUsed++;
01031                 }
01032 
01033                 //                      bool isHuman = pni->IsHuman();
01034 
01035                 // don't give inactive players a cycle
01036                 if (!pni->IsActive())
01037                     continue;
01038 
01039                 eCoord pos,dir;
01040                 gCycle *cycle=NULL;
01041                 if (sn_GetNetState()!=nCLIENT){
01042 #ifdef DEBUG
01043                     //                std::cout << "spawning player " << pni->name << '\n';
01044 #endif
01045                     spawn->Spawn(pos,dir);
01046                     pni->Greet();
01047                     cycle = new gCycle(grid, pos, dir, pni);
01048                     pni->ControlObject(cycle);
01049                     nNetObject::SyncAll();
01050                 }
01051                 //    int i=se_PlayerNetIDs(p)->pID;
01052 
01053                 // se_ResetGameTimer();
01054                 // se_PauseGameTimer(true);
01055             }
01056         }
01057 
01058 
01059 #ifdef ALLOW_NO_TEAM
01060         for (int p=se_PlayerNetIDs.Len()-1;p>=0;p--){
01061             ePlayerNetID *pni=se_PlayerNetIDs(p);
01062 
01063             gSpawnPoint *spawn=Arena.LeastDangerousSpawnPoint();
01064 
01065             if ( NULL == pni->CurrentTeam() )
01066             {
01067 #ifdef KRAWALL_SERVER
01068                 // don't allow unknown players to play
01069                 if (!pni->IsAuth())
01070                     continue;
01071 #endif
01072 
01073                 // don't give inactive players a cycle
01074                 if (!pni->IsActive())
01075                     continue;
01076 
01077                 eCoord pos,dir;
01078                 gCycle *cycle=NULL;
01079                 if (sn_GetNetState()!=nCLIENT){
01080 #ifdef DEBUG
01081                     //con << "spawning player " << se_PlayerNetIDs[p]->name << '\n';
01082 #endif
01083                     st_Breakpoint();
01084 
01085                     spawn->Spawn(pos,dir);
01086                     pni->Greet();
01087                     cycle = new gCycle(grid, pos, dir, pni, 0);
01088                     pni->ControlObject(cycle);
01089                     nNetObject::SyncAll();
01090                 }
01091                 //    int i=se_PlayerNetIDs(p)->pID;
01092 
01093                 // se_ResetGameTimer();
01094                 // se_PauseGameTimer(true);
01095             }
01096         }
01097 #endif
01098     }
01099 
01100     /*
01101     for(int p=se_PlayerNetIDs.Len()-1;p>=0;p--){
01102         ePlayerNetID *pni=se_PlayerNetIDs(p);
01103 
01104         bool isHuman = pni->IsHuman();
01105 
01106     #ifdef KRAWALL_SERVER
01107         // don't allow unknown players to play
01108         if (!pni->IsAuth())
01109                 continue;
01110     #endif
01111 
01112         // don't give inactive players a cycle
01113         if (!pni->IsActive())
01114                 continue;
01115        
01116         eCoord pos,dir;
01117         gCycle *cycle=NULL;
01118         if (sn_GetNetState()!=nCLIENT){
01119     #ifdef DEBUG
01120                 //con << "spawning player " << se_PlayerNetIDs[p]->name << '\n';
01121     #endif
01122                 spawn->Spawn(pos,dir);
01123                 pni->Greet();
01124                 cycle = new gCycle(grid, pos, dir, pni, 0);
01125                 pni->ControlObject(cycle);
01126                 nNetObject::SyncAll();
01127         }
01128         //    int i=se_PlayerNetIDs(p)->pID;
01129 
01130         se_ResetGameTimer();
01131         se_PauseGameTimer(true);
01132 
01133         if (sg_currentSettings->gameType==gHUMAN_VS_AI){
01134                 //      if (Cycle(p))
01135                 //      Cycle(p)->team=1;
01136                 if (cycle)
01137                 {
01138                         spawn=Arena.LeastDangerousSpawnPoint();
01139                         if (isHuman)
01140                                 cycle->team=2;
01141                         else
01142                         {
01143                                 cycle->team=1;
01144                         }
01145                 }
01146         }
01147         else{
01148     #ifdef DEBUG
01149                 //con << "new eSpawnPoint.\n";
01150     #endif
01151                 if (cycle)
01152                 {
01153                         spawn=Arena.LeastDangerousSpawnPoint();
01154                         if (isHuman)
01155                                 cycle->team=p + 2;
01156                         else
01157                                 cycle->team=1;
01158                 }
01159                 //      if (Cycle(p))
01160                 //      Cycle(p)->team=p+1;
01161         }
01162     }
01163     */
01164 
01165     //  spawn=Arena.LeastDangerousSpawnPoint();
01166 
01167     /*
01168     static REAL rgb[MAXAI][3]={
01169       {1,1,.2},
01170       {1,.2,1},
01171       {.2,1,1},
01172       {1,.6,.2},
01173       {.2,1,.6},
01174       {.6,.2,1},
01175       {1,.2,.6},
01176       {.6,1,.2},
01177       {1,1,1},
01178       {.2,.2,.2}
01179     };
01180     */
01181 
01182 
01183     rITexture::LoadAll();
01184     // se_ResetGameTimer();
01185     // se_PauseGameTimer(true);
01186 
01187     su_prefetchInput=true;
01188 
01189     lastTime_gameloop=lastTimeTimestep=0;
01190 
01191     // reset scores, all players that are spawned need to get ladder points
01192     ePlayerNetID::ResetScoreDifferences();
01193 }
01194 
01195 void init_game_camera(eGrid *grid){
01196 #ifndef DEDICATED
01197     for (int i=ePlayer::Num()-1;i>=0;i--)
01198         if (ePlayer::PlayerIsInGame(i)){
01199             ePlayerNetID *p=ePlayer::PlayerConfig(i)->netPlayer;
01200 
01201             if ( sg_currentSettings->finishType == gFINISH_EXPRESS && ( sn_GetNetState() != nCLIENT ) )
01202                 se_ResetGameTimer( -PREPARE_TIME/5 - sg_extraRoundTime );
01203             else
01204                 se_ResetGameTimer( -PREPARE_TIME - sg_extraRoundTime );
01205 
01206             // se_PauseGameTimer(true);
01207 
01208             ePlayer::PlayerConfig(i)->cam=new gCamera(grid,
01209                                           ePlayer::PlayerViewport(i),
01210                                           p,
01211                                           ePlayer::PlayerConfig(i),
01212                                           CAMERA_SMART);
01213 
01214             lastTime_gameloop=lastTimeTimestep=0;
01215         }
01216 #else
01217     se_ResetGameTimer( -PREPARE_TIME - sg_extraRoundTime );
01218     se_PauseGameTimer(false);
01219 #endif
01220     /*
01221       for(int p=se_PlayerNetIDs.Len()-1;p>=0;p--){
01222       int i=se_PlayerNetIDs(p)->pID;
01223 
01224       se_ResetGameTimer(-PREPARE_TIME);
01225       se_PauseGameTimer(true);
01226 
01227       if (i>=0)
01228          playerConfig[i]->cam=new eCamera(PlayerViewport(i),
01229       se_PlayerNetIDs(p),CAMERA_SMART);
01230       }
01231 
01232     */
01233 }
01234 
01235 bool think=1;
01236 
01237 #ifdef DEDICATED
01238 static int sg_dedicatedFPS = 40;
01239 static tSettingItem<int> sg_dedicatedFPSConf( "DEDICATED_FPS", sg_dedicatedFPS );
01240 
01241 static REAL sg_dedicatedFPSIdleFactor = 2.0;
01242 static tSettingItem<REAL> sg_dedicatedFPSMinstepConf( "DEDICATED_FPS_IDLE_FACTOR", sg_dedicatedFPSIdleFactor );
01243 #endif
01244 
01245 void s_Timestep(eGrid *grid, REAL time,bool cam){
01246     gNetPlayerWall::s_CopyIntoGrid();
01247     REAL minstep = 0;
01248 #ifdef DEDICATED
01249     minstep = 1.0/sg_dedicatedFPS;
01250 
01251     // the low possible simulation frequency, together with lazy timesteps, produces
01252     // this much possible extra time difference between gameobjects
01253     eGameObject::SetMaxLazyLag( ( 1 + sg_dedicatedFPSIdleFactor )/( sg_dedicatedFPSIdleFactor * sg_dedicatedFPS ) );
01254 #endif
01255     eGameObject::s_Timestep(grid, time, minstep );
01256 
01257     if (cam)
01258         eCamera::s_Timestep(grid, time);
01259 
01260     lastTimeTimestep=time;
01261 }
01262 
01263 #ifndef DEDICATED
01264 void RenderAllViewports(eGrid *grid){
01265     rViewportConfiguration *conf=rViewportConfiguration::CurrentViewportConfiguration();
01266 
01267     if (sr_glOut){
01268         sr_ResetRenderState();
01269 
01270         // enable distance based fog
01271         /*
01272         glFogi( GL_FOG_MODE, GL_EXP );
01273         glFogf( GL_FOG_DENSITY, .01/gArena::SizeMultiplier() );
01274         GLfloat black[3]={0,0,0};
01275         glFogfv( GL_FOG_COLOR, black );
01276         glEnable( GL_FOG );
01277         */
01278 
01279         const tList<eCamera>& cameras = grid->Cameras();
01280 
01281         for (int i=cameras.Len()-1;i>=0;i--){
01282             int p=sr_viewportBelongsToPlayer[i];
01283             conf->Select(i);
01284             rViewport *act=conf->Port(i);
01285             if (act && ePlayer::PlayerConfig(p))
01286                 ePlayer::PlayerConfig(p)->Render();
01287             else con << "hey! viewport " << i << " does not exist!\n";
01288         }
01289 
01290         // glDisable( GL_FOG );
01291     }
01292 
01293 #ifdef POWERPAK_DEB
01294     if (pp_out){
01295         eGameObject::PPDisplayAll();
01296         PD_ShowDoubleBuffer();
01297     }
01298 #endif
01299 }
01300 #endif
01301 
01302 
01303 void Render(eGrid *grid, REAL time, bool swap=true){
01304 #ifdef DEBUG
01305     //  eFace::UpdateVisAll(10);
01306 #endif
01307     //  se_debugExt=0;
01308 
01309 #ifndef DEDICATED
01310     if (sr_glOut){
01311         RenderAllViewports(grid);
01312 
01313         sr_ResetRenderState(true);
01314         gLogo::Display();
01315 
01316         if (swap){
01317             rSysDep::SwapGL();
01318             rSysDep::ClearGL();
01319         }
01320     }
01321     else
01322     {
01323         if ( swap )
01324             rSysDep::SwapGL();
01325 
01326         tDelay( sn_defaultDelay );
01327     }
01328 #endif
01329 }
01330 
01331 #ifdef DEDICATED
01332 static void cp(){
01333     std::ofstream s;
01334 
01335     if ( tDirectories::Var().Open(s, "players.txt") ){
01336         if (se_PlayerNetIDs.Len()>0)
01337             s << tColoredString::RemoveColors(ePlayerNetID::Ranking( -1, false ));
01338         else{
01339             tOutput o;
01340 
01341             int count=0;
01342             for (int i=MAXCLIENTS;i>0;i--)
01343                 if (sn_Connections[i].socket)
01344                     count++;
01345             if (count==0)
01346                 o << "$online_activity_nobody";
01347             else if (count==1)
01348                 o << "$online_activity_onespec";
01349             else
01350             {
01351                 o.SetTemplateParameter(1, count);
01352                 o << "$online_activity_manyspec";
01353             }
01354             o << "\n";
01355             s << o;
01356         }
01357     }
01358 }
01359 #endif
01360 
01361 
01362 static void own_game( nNetState enter_state ){
01363     tNEW(gGame);
01364     se_MakeGameTimer();
01365 #ifndef DEDICATED
01366     stc_fastestSpeedRound = .0;
01367 #endif
01368     sg_EnterGame( enter_state );
01369 
01370     // write scores one last time
01371     ePlayerNetID::LogScoreDifferences();
01372     se_SaveToLadderLog(tString("GAME_END\n"));
01373     se_sendEventNotification(tString("Game end"), tString("The Game has ended"));
01374 
01375     sg_currentGame=NULL;
01376     se_KillGameTimer();
01377 }
01378 
01379 static void singlePlayer_game(){
01380     sn_SetNetState(nSTANDALONE);
01381 
01382     update_settings();
01383     ePlayerNetID::CompleteRebuild();
01384 
01385     own_game( nSTANDALONE );
01386 }
01387 
01388 void sg_HostGame(){
01389     //we'll want to collect stats
01390     gStats = new gStatistics();
01391 
01392     {
01393         // create a game to check map once
01394         tJUST_CONTROLLED_PTR< gGame > game = tNEW(gGame);
01395         game->Verify();
01396     }
01397 
01398     if (sg_TalkToMaster)
01399     {
01400         nServerInfo::TellMasterAboutMe( gServerBrowser::CurrentMaster() );
01401     }
01402 
01403     sn_SetNetState(nSERVER);
01404 
01405     update_settings();
01406     ePlayerNetID::CompleteRebuild();
01407 
01408     tAdvanceFrame();
01409 
01410     //#ifndef DEBUG
01411 #ifdef DEDICATED
01412     static double startTime=tSysTimeFloat();
01413 
01414     if ( sg_NumUsers() == 0)
01415     {
01416         cp();
01417         con << tOutput("$online_activity_napping") << "\n";
01418         sg_Timestamp();
01419 
01420         int counter = -1;
01421 
01422         int numPlayers = 0;
01423 
01424         while (numPlayers == 0 &&
01425                 (ded_idle<.0001 || tSysTimeFloat()<startTime + ded_idle * 3600 ) && !uMenu::quickexit ){
01426             sr_Read_stdin();
01427             st_DoToDo();
01428             gGame::NetSyncIdle();
01429 
01430             sn_BasicNetworkSystem.Select( 1.0f );
01431 
01432             // std::cout the players who are logged in:
01433             numPlayers = sg_NumUsers();
01434             /*
01435                                 for (int i = se_PlayerNetIDs.Len()-1; i>=0; i--)
01436                                         if (se_PlayerNetIDs(i)->IsAuth())
01437                                                 numPlayers++;
01438             */
01439 
01440             if (counter <= 0)
01441             {
01442                 // restart network, just in case we lost the input socket
01443                 sn_BasicNetworkSystem.AccessListener().Listen(false);
01444                 sn_BasicNetworkSystem.AccessListener().Listen(true);
01445                 counter = 50;
01446             }
01447         }
01448 
01449         if (sg_NumUsers() <= 0 && ded_idle>0.0001 &&
01450                 tSysTimeFloat()>= startTime + ded_idle * 3600 )
01451         {
01452             sg_Timestamp();
01453             con << "Server exiting due to DEDICATED_IDLE after " << (tSysTimeFloat() - startTime)/3600 << " hours.\n";
01454             uMenu::quickexit = true;
01455         }
01456     }
01457     cp();
01458 
01459     if (!uMenu::quickexit)
01460 #endif
01461         //#endif
01462         own_game( nSERVER );
01463 
01464     sn_SetNetState(nSTANDALONE);
01465 
01466     // close listening sockets
01467     sn_BasicNetworkSystem.AccessListener().Listen(false);
01468 
01469     //wrap up the stats
01470     delete gStats;
01471 }
01472 
01473 static tString sg_roundCenterMessage("");
01474 static tConfItemLine sn_roundCM_ci("ROUND_CENTER_MESSAGE",sg_roundCenterMessage);
01475 
01476 static tString sg_roundConsoleMessage("");
01477 static tConfItemLine sn_roundCcM1_ci("ROUND_CONSOLE_MESSAGE",sg_roundConsoleMessage);
01478 
01479 static bool sg_RequestedDisconnection = false;
01480 
01481 static bool sg_NetworkError( const tOutput& title, const tOutput& message, REAL timeout )
01482 {
01483     tOutput message2 ( message );
01484 
01485     if ( sn_DenyReason.Len() > 2 )
01486     {
01487         message2.AddLiteral("\n\n");
01488         message2.AddLocale("network_kill_preface");
01489         message2.AddLiteral("\n");
01490         message2.AddLiteral(sn_DenyReason);
01491     }
01492 
01493     nServerInfoBase * redirect = sn_PeekRedirectTo();
01494     if ( redirect )
01495     {
01496         message2.Append( tOutput( "$network_redirect", redirect->GetConnectionName(), (int)redirect->GetPort() ) );
01497     }
01498 
01499     return tConsole::Message( title, message2, timeout );
01500 }
01501 
01502 // revert settings to defaults in the current scope
01503 class gSettingsReverter
01504 {
01505 public:
01506     gSettingsReverter()
01507     {
01508         // restore default configuration of network settings, saving your settings
01509         nConfItemBase::s_SaveValues();
01510         nConfItemBase::s_RevertToDefaults();
01511     }
01512 
01513     ~gSettingsReverter()
01514     {
01515         // restore saved values
01516         nConfItemBase::s_RevertToSavedValues();
01517     }
01518 };
01519 
01520 // receive network data
01521 void sg_Receive()
01522 {
01523     sn_Receive();
01524     if ( sn_GetNetState() == nSERVER )
01525     {
01526         // servers should ignore data sent to the control socket. It probably would be better
01527         // to close the socket altogether, but that opens another can of worms.
01528         sn_DiscardFromControlSocket();
01529     }
01530 }
01531 
01532 // return code: false if there was an error or abort
01533 bool ConnectToServerCore(nServerInfoBase *server)
01534 {
01535     tASSERT( server );
01536 
01537     ePlayerNetID::ClearAll();
01538 
01539     // revert to default settings, restore current vlaues on exit
01540     gSettingsReverter reverter;
01541 
01542     sn_bigBrotherString = renderer_identification;
01543 
01544     nNetObject::ClearAll();
01545 
01546     just_connected=true;
01547 
01548     rViewport::Update(MAX_PLAYERS);
01549     // ePlayerNetID::Update();
01550 
01551 #ifndef DEDICATED
01552     rSysDep::SwapGL();
01553     rSysDep::ClearGL();
01554     rSysDep::SwapGL();
01555     rSysDep::ClearGL();
01556 #endif
01557 
01558     sr_con.autoDisplayAtNewline=true;
01559     sr_con.fullscreen=true;
01560 
01561     bool to=sr_textOut;
01562     sr_textOut=true;
01563 
01564     tOutput o;
01565 
01566     nConnectError error = nOK;
01567 
01568     nNetObject::ClearAll();
01569 
01570     o.SetTemplateParameter(1, server->GetName());
01571     o << "$network_connecting_to_server";
01572     con << o;
01573     error = server->Connect();
01574 
01575     switch (error)
01576     {
01577     case nABORT:
01578         return false;
01579         break;
01580     case nOK:
01581         break;
01582     case nTIMEOUT:
01583         sg_NetworkError("$network_message_timeout_title", "$network_message_timeout_inter", 20);
01584         return false;
01585         break;
01586 
01587     case nDENIED:
01588         sg_NetworkError("$network_message_denied_title", sn_DenyReason.Len() > 2 ? "$network_message_denied_inter2" : "$network_message_denied_inter", 20);
01589         return false;
01590         break;
01591     }
01592 
01593     // ePlayerNetID::CompleteRebuild();
01594 
01595     if (sn_GetNetState()==nCLIENT){
01596         REAL endTime=tSysTimeFloat()+30;
01597         con << tOutput("$network_connecting_gamestate");
01598         while (!sg_currentGame && tSysTimeFloat()<endTime && (sn_GetNetState() != nSTANDALONE)){
01599             tAdvanceFrame();
01600             sg_Receive();
01601             nNetObject::SyncAll();
01602             tAdvanceFrame();
01603             sn_SendPlanned();
01604             st_DoToDo();
01605 
01606 #ifndef DEDICATED
01607             rSysDep::SwapGL();
01608             rSysDep::ClearGL();
01609 #endif
01610 
01611             sn_Delay();
01612         }
01613         if (sg_currentGame){
01614             sr_con.autoDisplayAtNewline=false;
01615             sr_con.fullscreen=false;
01616 
01617             con << tOutput("$network_syncing_gamestate");
01618             sg_EnterGame( nCLIENT );
01619         }
01620         else{
01621             //con << "Timeout. Try again!\n";
01622             sg_NetworkError("$network_message_lateto_title", "$network_message_lateto_inter", 20);
01623         }
01624     }
01625 
01626     bool ret = true;
01627 
01628     if (!sg_RequestedDisconnection && !uMenu::quickexit)
01629         switch (sn_GetLastError())
01630         {
01631         case nOK:
01632             ret = sg_NetworkError("$network_message_abortconn_title",
01633                                   "$network_message_abortconn_inter", 20);
01634             break;
01635         default:
01636             ret = sg_NetworkError("$network_message_lostconn_title",
01637                                   "$network_message_lostconn_inter", 20);
01638             break;
01639         }
01640 
01641     sr_con.autoDisplayAtNewline=false;
01642     sr_con.fullscreen=false;
01643 
01644     sn_SetNetState(nSTANDALONE);
01645 
01646     sg_currentGame = NULL;
01647     nNetObject::ClearAll();
01648     ePlayerNetID::ClearAll();
01649 
01650     sr_textOut=to;
01651 
01652     return ret;
01653 }
01654 
01655 void ConnectToServer(nServerInfoBase *server)
01656 {
01657     bool okToRedirect = ConnectToServerCore( server );
01658 
01659     // REAL redirections = 0;
01660     // double lastTime = tSysTimeFloat();
01661 
01662     // check for redirection
01663     while( okToRedirect )
01664     {
01665         std::auto_ptr< nServerInfoBase > redirectTo( sn_GetRedirectTo() );
01666 
01667         // abort loop
01668         if ( !(&(*redirectTo)) )
01669         {
01670             break;
01671         }
01672 
01673         okToRedirect = ConnectToServerCore( redirectTo.get() );
01674 
01675         /*
01676         // redirection spam chain protection, allow one redirection every 30 seconds. Should
01677         // be short enough to allow hacky applications (server-to-server teleport), but
01678         // long enough to allow players to escape via the menu or at least shift-esc.
01679         static const REAL timeout = 30;
01680         static const REAL maxRedirections = 5;
01681 
01682         redirections = redirections + 1;
01683         if ( redirections > maxRedirections )
01684         {
01685             break;
01686         }
01687 
01688         // decay spam protection
01689         double newTime = tSysTimeFloat();
01690         REAL dt = newTime - lastTime;
01691         lastTime = newTime;
01692         redirections *= 1/(1 + dt * maxRedirections * timeout );
01693         */
01694     }
01695 }
01696 
01697 static tConfItem<int> mor("MAX_OUT_RATE",sn_maxRateOut);
01698 static tConfItem<int> mir("MAX_IN_RATE",sn_maxRateIn);
01699 
01700 
01701 static tConfItem<int> pc("PING_CHARITY",pingCharity);
01702 
01703 
01704 uMenu *sg_IngameMenu=NULL;
01705 uMenu *sg_HostMenu  =NULL;
01706 
01707 void ret_to_MainMenu(){
01708     sg_RequestedDisconnection = true;
01709 
01710     if (sg_HostMenu)
01711         sg_HostMenu->Exit();
01712 
01713     if (sg_IngameMenu)
01714         sg_IngameMenu->Exit();
01715 
01716     sr_con.fullscreen=true;
01717     sr_con.autoDisplayAtNewline=true;
01718 
01719     if (sg_currentGame)
01720         sg_currentGame->NoLongerGoOn();
01721 
01722     sn_SetNetState(nSTANDALONE);
01723 
01724     uMenu::SetIdle(NULL);
01725 }
01726 
01727 
01728 
01729 void net_options(){
01730     uMenu net_menu("$network_opts_text");
01731 
01732     uMenuItemInt high_port
01733     (&net_menu,"$network_opts_maxport_text",
01734      "$network_opts_maxport_help",
01735      gServerBrowser::highPort,1024,65536);
01736 
01737     uMenuItemInt low_port
01738     (&net_menu,"$network_opts_minport_text",
01739      "$network_opts_minport_help",
01740      gServerBrowser::lowPort,1024,65536);
01741 
01742     /*
01743         uMenuItemFunction delpw(&net_menu,
01744                                                         "$network_opts_deletepw_text",
01745                                                         "$network_opts_deletepw_help",
01746                                                         &se_DeletePasswords);
01747       
01748         uMenuItemSelection<int> storepw(&net_menu,
01749                                                                         "$login_storepw_text",
01750                                                                         "$login_storepw_help",
01751                                                                         se_PasswordStorageMode);
01752         storepw.NewChoice("$login_storepw_dont_text",
01753                                           "$login_storepw_dont_help",
01754                                           -1);
01755         storepw.NewChoice("$login_storepw_mem_text",
01756                                           "$login_storepw_mem_help",
01757                                           0);
01758         storepw.NewChoice("$login_storepw_disk_text",
01759                                           "$login_storepw_disk_help",
01760                                           1);
01761     */
01762 
01763     /*
01764       uMenuItemToggle master
01765       (&net_menu,"$network_opts_master_text",
01766       "$network_opts_master_help",
01767       sg_TalkToMaster);
01768     */
01769 
01770 
01771     uMenuItemInt out_rate
01772     (&net_menu,"$network_opts_outrate_text",
01773      "$network_opts_outrate_help",
01774      sn_maxRateOut,1,20);
01775 
01776 
01777     uMenuItemInt in_rate
01778     (&net_menu,"$network_opts_inrate_text",
01779      "$network_opts_inrate_help",
01780      sn_maxRateIn,1,20);
01781 
01782 
01783     uMenuItemToggle po2
01784     (&net_menu,"$network_opts_predict_text",
01785      "$network_opts_predict_help",
01786      sr_predictObjects);
01787 
01788     uMenuItemToggle lm2
01789     (&net_menu,"$network_opts_lagometer_text",
01790      "$network_opts_lagometer_help",
01791      sr_laggometer);
01792 
01793     uMenuItemToggle ai
01794     (&net_menu,"$network_opts_axesindicator_text",
01795      "$network_opts_axesindicator_help",
01796      sg_axesIndicator);
01797 
01798 
01799     uMenuItemInt p_s
01800     (&net_menu,"$network_opts_pingchar_text",
01801      "$network_opts_pingchar_help",
01802      pingCharity,0,300,20);
01803 
01804     net_menu.Enter();
01805 
01806     if (gServerBrowser::lowPort > gServerBrowser::highPort)
01807         gServerBrowser::highPort = gServerBrowser::lowPort;
01808 }
01809 
01810 void sg_HostGameMenu(){
01811     uMenu net_menu("$network_host_text");
01812 
01813     sg_HostMenu = &net_menu;
01814 
01815     uMenuItemInt port(&net_menu, "$network_host_port_text",
01816                       "$network_host_port_help"
01817                       ,reinterpret_cast<int &>(sn_serverPort), gServerBrowser::lowPort, gServerBrowser::highPort);
01818 
01819     uMenuItemString serverName
01820     (&net_menu,"$network_host_name_text",
01821      "$network_host_name_help",
01822      sn_serverName);
01823 
01824     uMenuItemFunction settings1
01825     (&net_menu,
01826      "$game_settings_menu_text",
01827      "$game_settings_menu_help",
01828      &GameSettingsMP);
01829 
01830     uMenuItemFunction serv
01831     (&net_menu,"$network_host_host_text",
01832      "$network_host_host_help",&sg_HostGame);
01833 
01834     net_menu.ReverseItems();
01835     net_menu.SetSelected(0);
01836     net_menu.Enter();
01837 
01838     sg_HostMenu = NULL;
01839 }
01840 
01841 #ifndef DEDICATED
01842 class gNetIdler: public rSysDep::rNetIdler
01843 {
01844 public:
01845     virtual bool Wait() 
01846     {
01847         return sn_BasicNetworkSystem.Select( 0.1 );
01848     }
01849     virtual void Do()  
01850     {
01851         tAdvanceFrame();
01852         sg_Receive();
01853         sn_SendPlanned();
01854     }
01855 };
01856 #endif
01857 
01858 void net_game(){
01859 #ifndef DEDICATED
01860     uMenu net_menu("$network_menu_text");
01861 
01862     uMenuItemFunction cust
01863     (&net_menu,"$network_custjoin_text",
01864      "$network_custjoin_help",&gServerFavorites::CustomConnectMenu);
01865 
01866     uMenuItemFunction mas
01867     (&net_menu,"$masters_menu",
01868      "$masters_menu_help",&gServerFavorites::AlternativesMenu);
01869 
01870     uMenuItemFunction fav
01871     (&net_menu,"$bookmarks_menu",
01872      "$bookmarks_menu_help",&gServerFavorites::FavoritesMenu);
01873 
01874     uMenuItemFunction bud
01875     (&net_menu,"$friends_menu",
01876      "$friends_menu_help",&gFriends::FriendsMenu);
01877 
01878     uMenuItemFunction opt
01879     (&net_menu,"$network_opts_text",
01880      "$network_opts_help",&net_options);
01881 
01882     /*
01883       uMenuItemFunction serv
01884       (&net_menu,"$network_host_text",
01885       "$network_host_help",&sg_HostGameMenu);
01886     */
01887 
01888     uMenuItemFunction inter
01889     (&net_menu,"$network_menu_internet_text",
01890      "$network_menu_internet_help",&gServerBrowser::BrowseMaster);
01891 
01892     uMenuItemFunction lan
01893     (&net_menu,"$network_menu_lan_text",
01894      "$network_menu_lan_help",&gServerBrowser::BrowseLAN);
01895 
01896     gNetIdler idler;
01897     // rSysDep::StartNetSyncThread( &idler );
01898     net_menu.Enter();
01899     rSysDep::StopNetSyncThread();
01900 #endif
01901 }
01902 
01903 
01904 
01905 static void StartNewMatch(){
01906     if (sg_currentGame)
01907         sg_currentGame->StartNewMatch();
01908     if (sn_GetNetState()!=nCLIENT){
01909         sn_CenterMessage("$gamestate_reset_center");
01910         sn_ConsoleOut("$gamestate_reset_console");
01911     }
01912 }
01913 
01914 static void StartNewMatch_conf(std::istream &){
01915     StartNewMatch();
01916 }
01917 
01918 static tConfItemFunc snm("START_NEW_MATCH",&StartNewMatch_conf);
01919 
01920 #ifdef DEDICATED
01921 static void Quit_conf(std::istream &){
01922 
01923     if ( sg_currentGame )
01924     {
01925         sg_currentGame->NoLongerGoOn();
01926     }
01927 
01928     // mark end of recording
01929     tRecorder::Playback("END");
01930     tRecorder::Record("END");
01931     uMenu::quickexit = true;
01932 }
01933 
01934 static tConfItemFunc quit_conf("QUIT",&Quit_conf);
01935 static tConfItemFunc exit_conf("EXIT",&Quit_conf);
01936 #endif
01937 
01938 void st_PrintPathInfo(tOutput &buf);
01939 
01940 static void PlayerLogIn()
01941 {
01942     ePlayer::LogIn();
01943 
01944     if ( sg_IngameMenu )
01945     {
01946         sg_IngameMenu->Exit();
01947     }
01948 
01949     con << tOutput( "$player_authenticate_action" );
01950 }
01951 
01952 void sg_DisplayVersionInfo() {
01953     tOutput versionInfo;
01954     versionInfo << "$version_info_version" << "\n";
01955     st_PrintPathInfo(versionInfo);
01956     versionInfo << "$version_info_misc_stuff";
01957     sg_FullscreenMessage("$version_info_title", versionInfo, 1000);
01958 }
01959 
01960 void MainMenu(bool ingame){
01961     //  update_settings();
01962 
01963     if (ingame)
01964         sr_con.SetHeight(2);
01965 
01966     //gLogo::SetDisplayed(true);
01967 
01968     tOutput gametitle;
01969     if (!ingame)
01970         gametitle << "$game_menu_text";
01971     else
01972         gametitle << "$game_menu_ingame_text";
01973 
01974     uMenu game_menu(gametitle);
01975 
01976     uMenuItemFunction *reset=NULL;
01977 
01978     if (ingame && sn_GetNetState()!=nCLIENT){
01979         reset=new uMenuItemFunction
01980               (&game_menu,"$game_menu_reset_text",
01981                "$game_menu_reset_help",
01982                &StartNewMatch);
01983     }
01984 
01985     uMenuItemFunction *settings1=NULL;
01986 
01987     if (!ingame)
01988         settings1=tNEW(uMenuItemFunction)
01989                   (&game_menu,
01990                    "$game_settings_menu_text",
01991                    "$game_settings_menu_help",
01992                    &GameSettingsSP);
01993     else
01994         settings1=tNEW(uMenuItemFunction)
01995                   (&game_menu,
01996                    "$game_settings_menu_text",
01997                    "$game_settings_menu_help",
01998                    &GameSettingsCurrent);
01999 
02000     uMenuItemFunction *connect=NULL,*start=NULL,*sound=NULL;
02001 
02002     if (!ingame){
02003         connect=new uMenuItemFunction
02004                 (&game_menu,
02005                  "$network_menu_text",
02006                  "$network_menu_help",
02007                  &net_game);
02008 
02009         start= new uMenuItemFunction(&game_menu,"$game_menu_start_text",
02010                                      "$game_menu_start_help",&singlePlayer_game);
02011     }
02012 
02013     tOutput title;
02014     title.SetTemplateParameter( 1, sn_programVersion );
02015     if (!ingame)
02016         title << "$main_menu_text";
02017     else
02018         title << "$ingame_menu_text";
02019 
02020     uMenu MainMenu(title,false);
02021 
02022     if (ingame)
02023         sg_IngameMenu = &MainMenu;
02024 
02025     char const * extitle,* exhelp;
02026     if (!ingame){
02027         extitle="$main_menu_exit_text";
02028         exhelp="$main_menu_exit_help";
02029     }
02030     else{
02031         extitle="$ingame_menu_exit_text";
02032         exhelp="$ingame_menu_exit_help";
02033     }
02034 
02035     uMenuItemExit exx(&MainMenu,extitle,
02036                       exhelp);
02037 
02038     uMenuItemFunction *return_to_main=NULL;
02039     if (ingame){
02040         if (sn_GetNetState()==nSTANDALONE)
02041             return_to_main=new uMenuItemFunction
02042                            (&MainMenu,"$game_menu_exit_text",
02043                             "$game_menu_exit_help",
02044                             &ret_to_MainMenu);
02045         else if (sn_GetNetState()==nCLIENT)
02046             return_to_main=new uMenuItemFunction
02047                            (&MainMenu,"$game_menu_disconnect_text",
02048                             "$game_menu_disconnect_help",
02049                             &ret_to_MainMenu);
02050         else
02051             return_to_main=new uMenuItemFunction
02052                            (&MainMenu,
02053                             "$game_menu_shutdown_text",
02054                             "game_menu_shutdown_help",
02055                             &ret_to_MainMenu);
02056     }
02057 
02058     uMenuItemFunction * auth = 0;
02059     static nVersionFeature authentication( 15 );
02060     if ( sn_GetNetState() == nCLIENT && ingame && authentication.Supported(0) )
02061     {
02062         auth =tNEW(uMenuItemFunction)(&MainMenu,
02063                                       "$player_authenticate_text",
02064                                       "$player_authenticate_help",
02065                                       &PlayerLogIn );
02066     }
02067 
02068     uMenuItemFunction abb(&MainMenu,
02069                           "$main_menu_about_text",
02070                           "$main_menu_about_help",
02071                           &sg_DisplayVersionInfo);
02072 
02073 
02074     uMenu Settings("$system_settings_menu_text");
02075 
02076     uMenuItemSubmenu subm_settings
02077     (&MainMenu,&Settings,
02078      "$system_settings_menu_help");
02079 
02080 
02081     uMenuItem* team = NULL;
02082     if ( ingame )
02083     {
02084         team = tNEW( uMenuItemFunction) ( &MainMenu,
02085                                           "$team_menu_title",
02086                                           "$team_menu_help",
02087                                           &gTeam::TeamMenu );
02088     }
02089 
02090     uMenuItemFunction *se_PlayerMenu=NULL;
02091 
02092     //   if (!ingame)
02093     se_PlayerMenu= new uMenuItemFunction
02094                    (&MainMenu,"$player_mainmenu_text",
02095                     "$player_mainmenu_help",
02096                     &sg_PlayerMenu);
02097 
02098     uMenuItemFunction *player_police=NULL;
02099     uMenuItemFunction *voting=NULL;
02100     if ( ingame && sn_GetNetState() != nSTANDALONE )
02101     {
02102         player_police = tNEW( uMenuItemFunction )( &MainMenu, "$player_police_text", "$player_police_help", ePlayerNetID::PoliceMenu );
02103 
02104         if ( eVoter::VotingPossible() )
02105             voting = tNEW( uMenuItemFunction )( &MainMenu, "$voting_menu_text", "$voting_menu_help", eVoter::VotingMenu );
02106     }
02107 
02108     uMenu misc("$misc_menu_text");
02109 
02110     //  misc.SetCenter(.25);
02111 
02112     uMenuItemFunction language
02113     (&misc,"$language_menu_title",
02114      "$language_menu_help",
02115      &sg_LanguageMenu);
02116 
02117     uMenuItemFunction global_key
02118     (&misc,"$misc_global_key_text",
02119      "$misc_global_key_help",
02120      &su_InputConfigGlobal);
02121 
02122     uMenuItemToggle wrap
02123     (&misc,"$misc_menuwrap_text",
02124      "$misc_menuwrap_help",
02125      uMenu::wrap);
02126 
02127     uMenuItemToggle to2
02128     (&misc,"$misc_textout_text",
02129      "$misc_textout_help",sr_textOut);
02130 
02131 
02132 
02133     uMenuItemToggle mp
02134     (&misc,"$misc_moviepack_text",
02135      "$misc_moviepack_help",sg_moviepackUse);
02136 
02137 
02138     uMenuItemSubmenu misc_sm
02139     (&Settings,&misc,
02140      "$misc_menu_help");
02141 
02142     sound = new uMenuItemFunction
02143             (&Settings,"$sound_menu_text",
02144              "$sound_menu_help",&se_SoundMenu);
02145 
02146     uMenuItemSubmenu subm
02147     (&Settings,&sg_screenMenu,
02148      "$display_settings_menu_help");
02149 
02150     uMenuItemSubmenu *gamemenuitem = NULL;
02151     if (sn_GetNetState() != nCLIENT)
02152     {
02153         char const * gamehelp;
02154         if (!ingame)
02155             gamehelp="$game_menu_main_help";
02156         else
02157             gamehelp="$game_menu_ingame_help";
02158 
02159         gamemenuitem = tNEW(uMenuItemSubmenu) (&MainMenu,
02160                                                &game_menu,
02161                                                gamehelp
02162                                               );
02163     }
02164 
02165     if (!ingame)
02166     {
02167         rViewport::Update(MAX_PLAYERS);
02168         // ePlayerNetID::Update();
02169     }
02170 
02171     MainMenu.Enter();
02172 
02173     if (settings1)
02174         delete settings1;
02175     if (team)
02176         delete team;
02177     if (gamemenuitem)
02178         delete gamemenuitem;
02179     if (sound)
02180         delete sound;
02181     if (connect)
02182         delete connect;
02183     if (start)
02184         delete start;
02185     if (return_to_main)
02186         delete return_to_main;
02187     if (se_PlayerMenu)
02188         delete se_PlayerMenu;
02189     if (reset)
02190         delete reset;
02191     if ( player_police )
02192         delete player_police;
02193     if ( voting )
02194         delete voting;
02195 
02196     if (ingame)
02197         sg_IngameMenu=NULL;
02198 
02199     if (ingame)
02200     {
02201         gLogo::SetDisplayed(false);
02202         sr_con.SetHeight(7);
02203     }
02204 
02205     if ( auth )
02206     {
02207         delete auth;
02208     }
02209 }
02210 
02211 
02212 
02213 // Game states:
02214 
02215 #define GS_CREATED 0        // newborn baby
02216 #define GS_TRANSFER_SETTINGS    7
02217 #define GS_CREATE_GRID                  10
02218 #define GS_CREATE_OBJECTS               20
02219 #define GS_TRANSFER_OBJECTS             30
02220 #define GS_CAMERA                               35
02221 #define GS_SYNCING                              40
02222 #define GS_SYNCING2                             41
02223 #define GS_SYNCING3                             42
02224 #define GS_PLAY                                 50
02225 #define GS_DELETE_OBJECTS               60
02226 #define GS_DELETE_GRID                  70
02227 #define GS_STATE_MAX                    80
02228 
02229 static bool sg_AbeforeB( int stateA, int stateB )
02230 {
02231     return ( ( GS_STATE_MAX + stateA - stateB ) % GS_STATE_MAX > GS_STATE_MAX >> 2 );
02232 }
02233 
02234 #ifndef DEDICATED
02235 static void ingame_menu_cleanup();
02236 static void ingame_menu()
02237 {
02238     //    globalingame=true;
02239     try
02240     {
02241         se_ChatState( ePlayerNetID::ChatFlags_Menu, true );
02242         if (sn_GetNetState()==nSTANDALONE)
02243             se_PauseGameTimer(true);
02244         MainMenu(true);
02245     }
02246     catch ( ... )
02247     {
02248         ingame_menu_cleanup();
02249         ret_to_MainMenu();
02250         sg_IngameMenu=NULL;
02251         sg_HostMenu=NULL;
02252         throw;
02253     }
02254     ingame_menu_cleanup();
02255 }
02256 
02257 static void ingame_menu_cleanup()
02258 {
02259     if (sn_GetNetState()==nSTANDALONE)
02260         se_PauseGameTimer(false);
02261     se_ChatState(ePlayerNetID::ChatFlags_Menu, false);
02262     if ((bool(sg_currentGame) && sg_currentGame->GetState()!=GS_PLAY))
02263         //      || se_PlayerNetIDs.Len()==0)
02264     {
02265         rViewport::Update(MAX_PLAYERS);
02266         ePlayerNetID::Update();
02267     }
02268     //    globalingame=false;
02269 }
02270 #endif
02271 
02272 
02273 static nNOInitialisator<gGame> game_init(310,"game");
02274 
02275 nDescriptor &gGame::CreatorDescriptor() const{
02276     return game_init;
02277 }
02278 
02279 
02280 void gGame::Init(){
02281     m_Mixer = eSoundMixer::GetMixer();
02282     grid = tNEW(eGrid());
02283     state=GS_CREATED;
02284     stateNext=GS_TRANSFER_SETTINGS;
02285     goon=true;
02286 
02287     sg_currentGame=this;
02288 #ifdef DEBUG
02289     // con << "Game created.\n";
02290 #endif
02291     aParser = tNEW(gParser)(&Arena, grid);
02292 
02293     rounds = 0;
02294     StartNewMatchNow();
02295 }
02296 
02297 
02298 void gGame::NoLongerGoOn(){
02299     goon=false;
02300     //  stateNext=GS_DELETE_OBJECTS;
02301     if (sn_GetNetState()==nSERVER)
02302         RequestSync();
02303 }
02304 
02305 // console with filter for remote admin output redirection
02306 class gMapLoadConsoleFilter:public tConsoleFilter{
02307 public:
02308     gMapLoadConsoleFilter()
02309     {
02310     }
02311 
02312     ~gMapLoadConsoleFilter()
02313     {
02314     }
02315 
02316     tColoredString message_; // the console log for the error message
02317 private:
02318     // we want to come first
02319     virtual int DoGetPriority() const{
02320         return -100;
02321     }
02322 
02323     // don't actually filter; take line and add it to the potential error message
02324     virtual void DoFilterLine( tString &line )
02325     {
02326         message_ << line << "\n";
02327     }
02328 };
02329 
02330 static void sg_ParseMap ( gParser * aParser, tString mapfile )
02331 {
02332     {
02333         gMapLoadConsoleFilter consoleLog;
02334 #ifdef DEBUG
02335         con << "Loading map " << mapfile << "...\n";
02336 #endif
02337         if (!aParser->LoadWithoutParsing(mapfile))
02338         {
02339             tOutput errorMessage( sn_GetNetState() == nCLIENT ? "$map_file_load_failure_server" : "$map_file_load_failure_self", mapfile );
02340 
02341 #ifndef DEDICATED
02342             errorMessage << "\nLog:\n" << consoleLog.message_;
02343 #endif
02344 
02345             con << errorMessage;
02346 
02347             tOutput errorTitle("$map_file_load_failure_title");
02348 
02349             if ( sn_GetNetState() != nSTANDALONE )
02350             {
02351                 throw tGenericException( errorMessage, errorTitle );
02352             }
02353 
02354             if (!aParser->LoadWithoutParsing(DEFAULT_MAP)) {
02355                 errorMessage << "$map_file_load_failure_default";
02356                 throw tGenericException( errorMessage, errorTitle );
02357             }
02358         }
02359     }
02360 }
02361 
02362 static void sg_ParseMap ( gParser * aParser )
02363 {
02364     sg_ParseMap(aParser, mapfile);
02365 }
02366 
02367 void gGame::Verify()
02368 {
02369     // test map and load map settings
02370     sg_ParseMap( aParser );
02371     init_game_grid(grid, aParser);
02372     exit_game_grid(grid);
02373 }
02374 
02375 gGame::gGame(){
02376     synced_ = true;
02377     gLogo::SetDisplayed(false);
02378     if (sn_GetNetState()!=nCLIENT)
02379         RequestSync();
02380     Init();
02381 }
02382 
02383 gGame::gGame(nMessage &m):nNetObject(m){
02384     synced_ = false;
02385     Init();
02386 }
02387 
02388 
02389 gGame::~gGame(){
02390 #ifdef DEBUG
02391     //con << "deleting game...\n";
02392 #endif
02393     //stateNext=GS_CREATE_GRID;
02394     //StateUpdate();
02395 
02396     tASSERT( sg_currentGame != this );
02397 
02398     exit_game_objects(grid);
02399     grid->Clear();
02400     ePlayerNetID::ThrowOutDisconnected();
02401 
02402     delete aParser;
02403 }
02404 
02405 
02406 void gGame::WriteSync(nMessage &m){
02407     nNetObject::WriteSync(m);
02408     m.Write(stateNext);
02409 #ifdef DEBUG
02410     //con << "Wrote game state " << stateNext << ".\n";
02411 #endif
02412 }
02413 
02414 void gGame::ReadSync(nMessage &m){
02415     nNetObject::ReadSync(m);
02416 
02417     unsigned short newState;
02418     m.Read(newState);
02419 
02420 #ifdef DEBUG
02421     con << "Read gamestate " << newState << ".\n";
02422 #endif
02423 
02424     // only update the state if it does not go back a few steps
02425     if ( sg_AbeforeB( stateNext, newState ) )
02426         stateNext = newState;
02427 
02428 #ifdef DEBUG
02429     //con << "Read game state " << stateNext << ".\n";
02430 #endif
02431 }
02432 
02433 
02434 void gGame::NetSync(){
02435     // find end of recording in playback
02436     if ( tRecorder::Playback("END") )
02437     {
02438         tRecorder::Record("END");
02439         uMenu::quickexit=true;
02440     }
02441 
02442 #ifdef DEDICATED
02443     if (!sr_glOut && ePlayer::PlayerConfig(0)->cam)
02444         tERR_ERROR_INT("Someone messed with the camera!");
02445 #endif
02446     sg_Receive();
02447     nNetObject::SyncAll();
02448     tAdvanceFrame();
02449     sn_SendPlanned();
02450 }
02451 
02452 void gGame::NetSyncIdle(){
02453     NetSync();
02454     sn_Delay();
02455 }
02456 
02457 unsigned short client_gamestate[MAXCLIENTS+2];
02458 
02459 static void client_gamestate_handler(nMessage &m){
02460     unsigned short state;
02461     m.Read( state );
02462     client_gamestate[m.SenderID()] = state;
02463 #ifdef DEBUG
02464     //  con << "User " << m.SenderID() << " is in Mode " << state << '\n';
02465 #endif
02466 }
02467 
02468 static nDescriptor client_gs(311,client_gamestate_handler,"client_gamestate");
02469 
02470 
02471 
02472 void gGame::SyncState(unsigned short state){
02473     if (sn_GetNetState()==nSERVER){
02474 
02475         bool firsttime=true;
02476         bool goon=true;
02477         REAL timeout=tSysTimeFloat()+sg_Timeout*.1;
02478 
02479         sn_Sync(sg_Timeout*.1,true);
02480         NetSyncIdle();
02481 
02482         while (goon && tSysTimeFloat()<timeout){
02483             /*
02484               if (sg_currentGame)
02485               sg_currentGame->RequestSync();
02486             */
02487 
02488             sn_Sync(sg_Timeout*.1,true);
02489             NetSyncIdle();
02490 
02491             goon=false;
02492             for (int i=MAXCLIENTS;i>0;i--)
02493                 if ( sn_Connections[i].socket )
02494                 {
02495                     int clientState = client_gamestate[i];
02496                     if ( sg_AbeforeB( clientState, state ) )
02497                     {
02498                         goon=true;
02499                     }
02500                 }
02501             if (goon && firsttime){
02502                 firsttime=false;
02503 #ifdef DEBUG
02504                 con << "Waiting for users to enter gamestate " << state << '\n';
02505                 if (sn_Connections[1].ackPending>2)
02506                     con << "Ack_pending=" << sn_Connections[1].ackPending << ".\n";
02507 #endif
02508             }
02509         }
02510     }
02511 }
02512 
02513 
02514 void gGame::SetState(unsigned short act,unsigned short next){
02515     state=act;
02516 #ifdef DEBUG
02517     //con << "Entering gamestate " << state
02518     //<< ", next state: " << next << '\n';
02519 #endif
02520 
02521     if (sn_GetNetState()==nSERVER){
02522         RequestSync();
02523         NetSyncIdle();
02524         SyncState(state);
02525     }
02526 
02527     if (stateNext!=next){
02528         if (sn_GetNetState()!=nCLIENT || goon==false){
02529 
02530             stateNext=next;
02531 
02532             if (sn_GetNetState()==nSERVER){
02533                 RequestSync();
02534                 NetSyncIdle();
02535             }
02536         }
02537     }
02538 }
02539 
02540 // from nNetwork.C
02541 extern REAL planned_rate_control[MAXCLIENTS+2];
02542 extern REAL sent_per_messid[100];
02543 
02544 static REAL lastdeath=0;
02545 static bool roundOver=false;   // flag set when the round winner is declared
02546 
02547 static void sg_VoteMenuIdle()
02548 {
02549     if ( !uMenu::MenuActive() )
02550     {
02551         se_ChatState( ePlayerNetID::ChatFlags_Menu, true );
02552         eVoter::VotingMenu();
02553         se_ChatState( ePlayerNetID::ChatFlags_Menu, false );
02554     }
02555 }
02556 
02557 void gGame::StateUpdate(){
02558 
02559     //  if (state==GS_CREATED)
02560     //          stateNext=GS_CREATE_GRID;
02561 
02562     while ( sg_AbeforeB( state, stateNext ) && goon )
02563     {
02564 #ifdef CONNECTION_STRESS
02565         if ( sg_ConnectionStress )
02566         {
02567             tRandomizer & randomizer = tRandomizer::GetInstance();
02568             int random = randomizer.Get( 16 );
02569             if ( random == 0 )
02570             {
02571                 sg_RequestedDisconnection = true;
02572                 //                                              sn_SetNetState( nSTANDALONE );
02573                 goon = false;
02574             }
02575 
02576             se_ChatState( ePlayerNetID::ChatFlags_Away, 1 );
02577         }
02578 #endif
02579 
02580         // unsigned short int mes1 = 1, mes2 = 1, mes3 = 1, mes4 = 1, mes5 = 1;
02581 
02582         switch (state){
02583         case GS_DELETE_GRID:
02584             // sr_con.autoDisplayAtNewline=true;
02585 
02586             con << tOutput("$gamestate_deleting_grid");
02587             //                          sn_ConsoleOut(sg_roundCenterMessage + "\n");
02588             sn_CenterMessage(sg_roundCenterMessage);
02589 
02590             //                          for (unsigned short int mycy = 0; mycy > sg_roundConsoleMessage5.Len(); c++)
02591 
02592             exit_game_objects(grid);
02593             nNetObject::ClearAllDeleted();
02594 
02595             if (goon)
02596                 SetState(GS_TRANSFER_SETTINGS,GS_CREATE_GRID);
02597             else
02598                 state=GS_CREATE_GRID;
02599             break;
02600         case GS_CREATED:
02601         case GS_TRANSFER_SETTINGS:
02602             // sr_con.autoDisplayAtNewline=true;
02603 
02604             // transfer game settings
02605             if ( nCLIENT != sn_GetNetState() )
02606             {
02607                 update_settings();
02608                 ePlayerNetID::RemoveChatbots();
02609             }
02610 
02611             rViewport::Update(MAX_PLAYERS);
02612 
02613             // log scores before players get renamed
02614             ePlayerNetID::LogScoreDifferences();
02615             se_SaveToLadderLog(tString("NEW_ROUND\n"));
02616             se_sendEventNotification(tString("New Round"), tString("Starting a new round"));
02617 
02618             // kick spectators
02619             nMachine::KickSpectators();
02620 
02621             // rename players as per request
02622             if ( synced_ && sn_GetNetState() != nSERVER )
02623                 ePlayerNetID::Update();
02624 
02625             // delete game objects again (in case new ones were spawned)
02626             exit_game_objects(grid);
02627 
02628             nConfItemBase::s_SendConfig(false);
02629 
02630             // wait extra long for the clients to delete the grid; they really need to be
02631             // synced this time
02632             sn_Sync( sg_Timeout*.4, true );
02633 
02634             SetState(GS_CREATE_GRID,GS_CAMERA);
02635             break;
02636 
02637         case GS_CREATE_GRID:
02638             // sr_con.autoDisplayAtNewline=true;
02639 
02640             sg_ParseMap( aParser );
02641 
02642             sn_Statistics();
02643             sg_Timestamp();
02644 
02645             con << tOutput("$gamestate_creating_grid");
02646 
02647             tAdvanceFrame();
02648 
02649             init_game_grid(grid, aParser);
02650 
02651             nNetObject::ClearAllDeleted();
02652 
02653             SetState(GS_CREATE_OBJECTS,GS_CAMERA);
02654             break;
02655         case GS_CREATE_OBJECTS:
02656             // con << "Creating objects...\n";
02657 
02658             lastdeath = -100;
02659             roundOver = false;
02660 
02661             // rename players as per request
02662             if ( synced_ )
02663                 ePlayerNetID::Update();
02664 
02665             init_game_objects(grid);
02666 
02667             ePlayerNetID::RankingLadderLog();
02668 
02669             // do round begin stuff
02670             {
02671                 const tList<eGameObject>& gameObjects = Grid()->GameObjects();
02672                 for (int i=gameObjects.Len()-1;i>=0;i--)
02673                 {
02674                     eGameObject * e = gameObjects(i);
02675                     if ( e )
02676                     {
02677                         e->OnRoundBegin();
02678                     }
02679                 }
02680             }
02681 
02682             // do the first analysis of the round, now is the time to get it used to the number of teams
02683             Analysis( -1000 );
02684 
02685             s_Timestep(grid, se_GameTime(), false);
02686             SetState(GS_TRANSFER_OBJECTS,GS_CAMERA);
02687 
02688             if (sn_GetNetState() == nCLIENT && just_connected){
02689                 sn_Sync(sg_Timeout*.1,true);
02690                 sn_Sync(sg_Timeout*.1,true);
02691             }
02692             just_connected=false;
02693 
02694 #ifdef ENABLE_ZONESV2
02695             init_second_pass_zones(grid, aParser);
02696 #endif
02697             break;
02698         case GS_TRANSFER_OBJECTS:
02699             // con << "Transferring objects...\n";
02700             rITexture::LoadAll();
02701             // se_ResetGameTimer();
02702             // se_PauseGameTimer(true);
02703 
02704 
02705             // push all data
02706             if (sn_GetNetState()==nSERVER){
02707                 bool goon=true;
02708                 double timeout=tSysTimeFloat()+sg_Timeout*.4;
02709                 while (goon && tSysTimeFloat()<timeout){
02710                     NetSyncIdle();
02711                     goon=false;
02712                     for (int i=MAXCLIENTS;i>0;i--)
02713                         if (sn_Connections[i].socket)
02714                             for (int j=sn_netObjects.Len()-1;j>=0;j--)
02715                                 if (sn_netObjects(j) &&
02716                                         !sn_netObjects(j)->HasBeenTransmitted(i) &&
02717                                         sn_netObjects(j)->syncRequested(i))
02718                                     goon=true;
02719                 }
02720                 if (tSysTimeFloat()<timeout)
02721                     con << tOutput("$gamestate_done");
02722                 else{
02723                     con << tOutput("$gamestate_timeout_intro");
02724                     for (int i=MAXCLIENTS;i>0;i--)
02725                         if (sn_Connections[i].socket)
02726                             for (int j=sn_netObjects.Len()-1;j>=0;j--)
02727                                 if (sn_netObjects(j) && !sn_netObjects(j)->HasBeenTransmitted(i))
02728                                 {
02729                                     tOutput o;
02730                                     tString name;
02731                                     sn_netObjects(j)->PrintName( name );
02732                                     o.SetTemplateParameter(1, i);
02733                                     o.SetTemplateParameter(2, j);
02734                                     o.SetTemplateParameter(3, name);
02735                                     o << "$gamestate_timeout_message";
02736                                     con << o;
02737                                 }
02738                     con << "\n\n\n";
02739                 }
02740             }
02741 
02742             // wait for players to ready
02743             if ( sn_GetNetState() == nSERVER )
02744                 while ( ePlayerNetID::WaitToLeaveChat() )
02745                 {
02746                     NetSyncIdle();
02747                     se_SyncGameTimer();
02748                 }
02749 
02750             SetState(GS_CAMERA,GS_SYNCING);
02751             break;
02752         case GS_CAMERA:
02753             // con << "Setting camera position...\n";
02754             rITexture::LoadAll();
02755             // se_ResetGameTimer(-PREPARE_TIME);
02756             // se_PauseGameTimer(true);
02757             init_game_camera(grid);
02758             SetState(GS_SYNCING,GS_PLAY);
02759             break;
02760         case GS_SYNCING:
02761             // con << "Syncing timer...\n";
02762             rITexture::LoadAll();
02763             SetState(GS_PLAY,GS_PLAY);
02764             if (sn_GetNetState()!=nCLIENT){
02765                 if (rounds<=0){
02766                     sn_ConsoleOut("$gamestate_resetnow_console");
02767                     StartNewMatchNow();
02768                     sn_CenterMessage("$gamestate_resetnow_center");
02769                     se_SaveToScoreFile("$gamestate_resetnow_log");
02770                 }
02771 
02772                 tOutput mess;
02773                 if (rounds < sg_currentSettings->limitRounds)
02774                 {
02775                     mess.SetTemplateParameter(1, rounds+1);
02776                     mess.SetTemplateParameter(2, sg_currentSettings->limitRounds);
02777                     mess << "$gamestate_newround_console";
02778 
02779                     if (strlen(sg_roundConsoleMessage) > 2)
02780                         sn_ConsoleOut(sg_roundConsoleMessage + "\n");
02781                 }
02782                 else
02783                     mess << "$gamestate_newround_goldengoal";
02784                 sn_ConsoleOut(mess);
02785 
02786                 se_SaveToScoreFile("$gamestate_newround_log");
02787             }
02788             //con << ePlayerNetID::Ranking();
02789 
02790             se_PauseGameTimer(false);
02791             se_SyncGameTimer();
02792             sr_con.fullscreen=false;
02793             sr_con.autoDisplayAtNewline=false;
02794 
02795             break;
02796         case GS_PLAY:
02797             sr_con.autoDisplayAtNewline=false;
02798 #ifdef DEDICATED
02799             {
02800                 // safe current players in a file
02801                 cp();
02802 
02803                 if ( sg_NumUsers() <= 0 )
02804                     goon = 0;
02805 
02806                 Analysis(0);
02807 
02808                 {
02809                     std::ifstream s;
02810 
02811                     // load contents of everytime.cfg for real
02812                     if ( tDirectories::Config().Open(s, "everytime.cfg" ) )
02813                         tConfItemBase::LoadAll(s);
02814 
02815                     s.close();
02816 
02817                     if ( tDirectories::Var().Open(s, "everytime.cfg" ) )
02818                         tConfItemBase::LoadAll(s);
02819 
02820                     // load contents of everytime.cfg from playback
02821                     tConfItemBase::LoadPlayback();
02822                 }
02823             }
02824 #endif
02825             // pings should not count as much in the between-round phase
02826             nPingAverager::SetWeight(1E-20);
02827 
02828             se_UserShowScores(false);
02829 
02830             // rotate, if rotate is once per round
02831             if (rotationtype == 1)
02832                 rotate();
02833             gRotation::HandleNewRound();
02834 
02835             //con.autoDisplayAtNewline=true;
02836             sr_con.fullscreen=true;
02837             SetState(GS_DELETE_OBJECTS,GS_DELETE_GRID);
02838             break;
02839         case GS_DELETE_OBJECTS:
02840 
02841             winDeathZone_ = NULL;
02842 
02843             rViewport::Update(MAX_PLAYERS);
02844             if ( synced_ && sn_GetNetState() != nSERVER )
02845                 ePlayerNetID::Update();
02846 
02847             // sr_con.autoDisplayAtNewline=true;
02848 
02849             //gStatistics - save all
02850 
02851             con << tOutput("$gamestate_deleting_objects");
02852             exit_game_objects(grid);
02853             st_ToDo( sg_VoteMenuIdle );
02854             nNetObject::ClearAllDeleted();
02855             SetState(GS_DELETE_GRID,GS_TRANSFER_SETTINGS);
02856             break;
02857         default:
02858             break;
02859         }
02860 
02861         // now would be a good time to tend for pending tasks
02862         nAuthentication::OnBreak();
02863 
02864         if (sn_GetNetState()==nSERVER){
02865             NetSyncIdle();
02866             RequestSync();
02867             NetSyncIdle();
02868         }
02869         else if (sn_GetNetState()==nCLIENT){ // inform the server of our progress
02870             NetSyncIdle();
02871             nMessage *m=new nMessage(client_gs);
02872             m->Write(state);
02873             m->Send(0);
02874 #ifdef DEBUG
02875             //                  con << "sending gamestate " << state << '\n';
02876 #endif
02877             NetSyncIdle();
02878         }
02879     }
02880 }
02881 
02882 // uncomment to activate respawning
02883 // #define RESPAWN_HACK
02884 
02885 #ifdef RESPAWN_HACK
02886 // Respawns cycles (crude test)
02887 static void sg_Respawn( REAL time, eGrid *grid, gArena & arena )
02888 {
02889     for ( int i = se_PlayerNetIDs.Len()-1; i >= 0; --i )
02890     {
02891         ePlayerNetID *p = se_PlayerNetIDs(i);
02892 
02893         if ( !p->CurrentTeam() )
02894             continue;
02895 
02896         eGameObject *e=p->Object();
02897 
02898         if ( ( !e || !e->Alive() && e->DeathTime() < time - .5 ) && sn_GetNetState() != nCLIENT )
02899         {
02900             sg_RespawnPlayer(time, grid, &arena, p);
02901         }
02902     }
02903 }
02904 #endif
02905 
02906 void sg_RespawnPlayer(eGrid *grid, gArena *arena, ePlayerNetID *p)
02907 {
02908     eGameObject *e=p->Object();
02909 
02910     if ( ( !e || !e->Alive()) && sn_GetNetState() != nCLIENT )
02911     {
02912         eCoord pos,dir;
02913         if ( e )
02914         {
02915             dir = e->Direction();
02916             pos = e->Position();
02917             eWallRim::Bound( pos, 1 );
02918             eCoord displacement = pos - e->Position();
02919             if ( displacement.NormSquared() > .01 )
02920             {
02921                 dir = displacement;
02922                 dir.Normalize();
02923             }
02924         }
02925         else
02926             arena->LeastDangerousSpawnPoint()->Spawn( pos, dir );
02927 #ifdef DEBUG
02928         //                std::cout << "spawning player " << pni->name << '\n';
02929 #endif
02930         gCycle * cycle = new gCycle(grid, pos, dir, p);
02931         p->ControlObject(cycle);
02932 
02933         sg_Timestamp();
02934     }
02935 }
02936 
02937 gArena * sg_GetArena() {
02938     return &Arena;
02939 }
02940 
02941 
02942 static REAL sg_timestepMax = .2;
02943 static tSettingItem<REAL> sg_timestepMaxConf( "TIMESTEP_MAX", sg_timestepMax );
02944 static int sg_timestepMaxCount = 10;
02945 static tSettingItem<int> sg_timestepMaxCountConf( "TIMESTEP_MAX_COUNT", sg_timestepMaxCount );
02946 
02947 void gGame::Timestep(REAL time,bool cam){
02948 #ifdef DEBUG
02949     tMemManBase::Check();
02950 #endif
02951 
02952 #ifdef RESPAWN_HACK
02953     sg_Respawn(time,grid,Arena);
02954 #endif
02955 
02956     // chop timestep into small, managable bits
02957     REAL dt = time - lastTimeTimestep;
02958     if ( dt < 0 )
02959         return;
02960     REAL lt = lastTimeTimestep;
02961 
02962     // determine the number of bits
02963     int number_of_steps=int(fabs((dt)/sg_timestepMax));
02964     if (number_of_steps<1)
02965         number_of_steps=1;
02966     if ( number_of_steps > sg_timestepMaxCount )
02967     {
02968         number_of_steps = sg_timestepMaxCount;
02969     }
02970 
02971     // chop
02972     for (int i=1;i<=number_of_steps;i++)
02973     {
02974         REAL stepTime = lt + i * dt/number_of_steps;
02975         s_Timestep(grid, stepTime, cam);
02976     }
02977 }
02978 
02979 // check if team has any enemies currently
02980 static bool sg_EnemyExists( int team )
02981 {
02982     // check if the win was legitimate: at least one enemy team needs to bo online
02983     for ( int i = eTeam::teams.Len()-1; i>= 0; --i )
02984     {
02985         if ( i != team && eTeam::Enemies( eTeam::teams[i], eTeam::teams[team] ) )
02986             return true;
02987     }
02988 
02989     return false;
02990 }
02991 
02992 static REAL sg_winZoneRandomness = .8;
02993 static tSettingItem< REAL > sg_winZoneSpreadConf( "WIN_ZONE_RANDOMNESS", sg_winZoneRandomness );
02994 
02995 void gGame::Analysis(REAL time){
02996     if ( nCLIENT == sn_GetNetState() )
02997         return;
02998 
02999     static REAL wintimer=0;
03000 
03001     // only do this expensive stuff once a second
03002     {
03003         static double nextTime = -1;
03004         if ( tSysTimeFloat() > nextTime || time < -10 )
03005         {
03006             nextTime = tSysTimeFloat() + 1.0;
03007         }
03008         else
03009         {
03010             return;
03011         }
03012     }
03013 
03014     // send timeout warnings
03015 
03016 
03017     if (tSysTimeFloat()-startTime>10){
03018         if ((startTime+sg_currentSettings->limitTime*60)-tSysTimeFloat()<10 && warning<6){
03019             tOutput o("$gamestate_tensecond_warn");
03020             sn_CenterMessage(o);
03021             sn_ConsoleOut(o);
03022             warning=6;
03023         }
03024 
03025 
03026         if ((startTime+sg_currentSettings->limitTime*60)-tSysTimeFloat()<30 && warning<5){
03027             tOutput o("$gamestate_30seconds_warn");
03028             sn_CenterMessage(o);
03029             sn_ConsoleOut(o);
03030             warning=5;
03031         }
03032 
03033         if ((startTime+sg_currentSettings->limitTime*60)-tSysTimeFloat()<60 && warning<4){
03034             tOutput o("$gamestate_minute_warn");
03035             sn_CenterMessage(o);
03036             sn_ConsoleOut(o);
03037             warning=4;
03038         }
03039 
03040         if ((startTime+sg_currentSettings->limitTime*60)-tSysTimeFloat()<2*60 && warning<3){
03041             tOutput o("$gamestate_2minutes_warn");
03042             sn_ConsoleOut(o);
03043             warning=3;
03044         }
03045 
03046         if ((startTime+sg_currentSettings->limitTime*60)-tSysTimeFloat()<5*60 && warning<2){
03047             tOutput o("$gamestate_5minutes_warn");
03048             sn_ConsoleOut(o);
03049             warning=2;
03050         }
03051 
03052         if ((startTime+sg_currentSettings->limitTime*60)-tSysTimeFloat()<10*60 && warning<1){
03053             tOutput o("$gamestate_10minutes_warn");
03054             sn_ConsoleOut(o);
03055             warning=1;
03056         }
03057     }
03058 
03059     // count active players
03060     int active = 0;
03061     int i;
03062     for (i=se_PlayerNetIDs.Len()-1;i>=0;i--){
03063         ePlayerNetID *pni=se_PlayerNetIDs(i);
03064         if (pni->IsActive())
03065             active ++;
03066     }
03067 
03068     // count other statistics
03069     int alive_and_not_disconnected = 0;
03070     int alive=0;
03071     int ai_alive=0;
03072     int human_teams=0;
03073     int teams_alive=0;
03074     int last_alive=-1;
03075     int last_team_alive=-1;
03076     int last_alive_and_not_disconnected=-1;
03077     int humans = 0;
03078     int active_humans = 0;
03079     int ais    = 0;
03080     REAL deathTime=0;
03081 
03082     bool notyetloggedin = true;  // are all current users not yet logged in?
03083 
03084     for (i=eTeam::teams.Len()-1;i>=0;i--){
03085         eTeam *t = eTeam::teams(i);
03086 
03087         humans += t->NumHumanPlayers();
03088         ais    += t->NumAIPlayers();
03089 
03090         if ( t->Alive() )
03091         {
03092             teams_alive++;
03093             last_team_alive = i;
03094         }
03095 
03096         if ( t->NumHumanPlayers() > 0 )
03097         { // human players
03098             human_teams++;
03099 
03100             for (int j=t->NumPlayers()-1; j>=0; --j)
03101             {
03102                 ePlayerNetID* p = t->Player(j);
03103                 if (p->IsActive())
03104                     active_humans++;
03105 
03106                 gCycle *g=dynamic_cast<gCycle *>(p->Object());
03107                 if (g){
03108                     notyetloggedin = false;
03109 
03110                     if (g->Alive())
03111                     {
03112 
03113                         if ( p->IsHuman() )
03114                         {
03115                             alive++;
03116                             if (p->IsActive())
03117                             {
03118                                 last_alive_and_not_disconnected=i;
03119                                 alive_and_not_disconnected++;
03120                             }
03121                         }
03122                         else
03123                             ai_alive++;
03124 
03125                         last_alive=i;
03126                     }
03127                     else
03128                     {
03129                         REAL dt=g->DeathTime();
03130                         if (dt>deathTime)
03131                             deathTime=dt;
03132                     }
03133                 }
03134 #ifdef KRAWALL_SERVER
03135                 else if (p->IsAuthenticated())
03136                     notyetloggedin = false;
03137 #endif
03138             }
03139         }
03140         else
03141         {
03142             for (int j=t->NumPlayers()-1; j>=0; --j)
03143             {
03144                 ePlayerNetID* p = t->Player(j);
03145 
03146                 gCycle *g=dynamic_cast<gCycle *>(p->Object());
03147                 if (g){
03148                     if (g->Alive())
03149                     {
03150                         ai_alive++;
03151                     }
03152                 }
03153             }
03154         }
03155     }
03156 
03157 #ifdef DEDICATED
03158     //activeHumans
03159     if (sg_NumUsers() <= 0)
03160         goon = false;
03161 #endif
03162 
03163 
03164     if (last_alive_and_not_disconnected >= 0)
03165         last_alive = last_alive_and_not_disconnected;
03166 
03167     // kill all disconnected players if they are the only reason the round goes on:
03168     if ( alive_and_not_disconnected <= 1 && alive > alive_and_not_disconnected )
03169     {
03170         for (int i=se_PlayerNetIDs.Len()-1;i>=0;i--)
03171         {
03172             gCycle *g=dynamic_cast<gCycle *>(se_PlayerNetIDs(i)->Object());
03173             if (g && !se_PlayerNetIDs(i)->IsActive())
03174             {
03175                 g->Kill();
03176             }
03177 
03178             //                  alive = alive_and_not_disconnected;
03179         }
03180     }
03181 
03182     // keep the game running when there are only login processes running
03183     if (notyetloggedin && humans > 0)
03184         alive++;
03185 
03186 
03187     static int all_alive_last=0;
03188     {
03189         int all_alive = ai_alive+alive;
03190         if (all_alive != all_alive_last)
03191         {
03192             all_alive_last = ai_alive+alive;
03193             lastdeath = time;
03194         }
03195     }
03196 
03197     static nVersionFeature winZone(2);
03198 
03199     /*
03200     ***************** ===================== ********************
03201     HACK
03202     THIS HAS SIMPLY BEEN DEACTIVATED.
03203     IT SHOULD BE REACTIVATED WITH THE NEW ZONE CODE
03204     ***************** ===================== ********************
03205     */
03206 #ifndef ENABLE_ZONESV2
03207     // activate instant win zone
03208     if ( winZone.Supported() && !bool( winDeathZone_ ) && winner == 0 && time - lastdeath > sg_currentSettings->winZoneMinLastDeath && time > sg_currentSettings->winZoneMinRoundTime )
03209     {
03210         winDeathZone_ = sg_CreateWinDeathZone( grid, Arena.GetRandomPos( sg_winZoneRandomness ) );
03211     }
03212 #endif
03213 
03214     bool holdBackNextRound = false;
03215 
03216     // start a new match if the number of teams changes from 1 to 2 or from 2 to 1
03217     {
03218         static int lastTeams = 0; // the number of teams when this was last called.
03219 
03220         // check for relevent status change, form 0 to 1 or 1 to 2 or 2 to 1 or 1 to 0 human teams.
03221         int humanTeamsClamp = human_teams;
03222         if ( humanTeamsClamp > 2 )
03223             humanTeamsClamp = 2;
03224         if ( humanTeamsClamp != lastTeams )
03225         {
03226             StartNewMatch();
03227             // if this is the beginning of a round, just start the match now
03228             if ( time < -100 )
03229             {
03230                 StartNewMatchNow();
03231             }
03232             else
03233             {
03234                 // start a new round and match.
03235                 winner=-1;
03236                 wintimer=time;
03237             }
03238         }
03239 
03240         lastTeams=humanTeamsClamp; // update last team count
03241     }
03242 
03243     // who is alive?
03244     if ( time-lastdeath < 1.0f )
03245     {
03246         holdBackNextRound = true;
03247     }
03248     else if (winner==0 && absolute_winner==0 ){
03249         if ( teams_alive <= 1 )
03250         {
03251             if ( sg_currentSettings->gameType!=gFREESTYLE )
03252             {
03253                 if ( eTeam::teams.Len()>1 && teams_alive<=1 ){
03254                     winner=last_team_alive+1;
03255                     wintimer=time;
03256                 }
03257             }
03258             else
03259             {
03260                 if ( teams_alive < 1 )
03261                     winner=-1;
03262                 wintimer=time;
03263             }
03264         }
03265 
03266         const char* survivor="$player_win_survivor";
03267         const char* messagetype = survivor;
03268 
03269         if ( wishWinner )
03270         {
03271             wintimer=time;
03272             winner = wishWinner;
03273             wishWinner = 0;
03274             messagetype = wishWinnerMessage;
03275         }
03276 
03277         if (winner <= 0 && alive <= 0 && ai_alive <= 0 && teams_alive <= 0){
03278             if ( se_mainGameTimer )
03279                 se_mainGameTimer->speed = 1;
03280 
03281             // emergency
03282             winner=-1;
03283             wintimer=time;
03284         }
03285         else
03286             if (winner){
03287                 if ( se_mainGameTimer )
03288                     se_mainGameTimer->speed = 1;
03289                 lastdeath = time;
03290 
03291                 tOutput message;
03292                 message << "$gamestate_winner_winner";
03293 
03294                 if ( last_team_alive >= 0 )
03295                     sg_currentSettings->AutoAI( eTeam::teams( last_team_alive )->NumHumanPlayers() > 0 );
03296 
03297 
03298                 if ( ( sg_currentSettings->scoreWin != 0 || sg_currentSettings->gameType != gFREESTYLE ) && winner > 0 )
03299                 {
03300                     // check if the win was legitimate: at least one enemy team needs to be online
03301                     if ( sg_EnemyExists( winner-1 ) || sg_currentSettings->gameType==gFREESTYLE )
03302                     {
03303 #ifdef KRAWALL_SERVER_LEAGUE
03304                         // send the result to the master server
03305                         if (!dynamic_cast<gAIPlayer*>(eTeam::teams(winner-1)))
03306                         {
03307                             tArray<tString> players;
03308                             for (int i = eTeam::teams.Len()-1; i>=0; i--)
03309                                 if (i != winner-1 &&
03310                                         eTeam::teams(i)->Alive() &&
03311                                         eTeam::teams(i)->IsHuman() )
03312                                 {
03313                                     players[players.Len()] = eTeam::teams(i)->Name();
03314                                 }
03315 
03316                             players[players.Len()] = eTeam::teams(winner-1)->Name();
03317                             if (players.Len() > 1)
03318                                 nKrawall::ServerRoundEnd(&players(0), players.Len());
03319                         }
03320 #endif
03321 
03322                         // scoring
03323                         eTeam::teams[winner-1]->AddScore
03324                         (sg_currentSettings->scoreWin,messagetype, tOutput());
03325                         if (!sg_singlePlayer && eTeam::teams(winner-1)->NumHumanPlayers() >= 1 && gStats &&
03326                                 eTeam::teams(winner-1)->NumPlayers() >= 1 && eTeam::teams[winner-1]->NumHumanPlayers() > 0)
03327                         {
03328                             //gStatistics - won rounds add
03329                             for (int i = eTeam::teams[winner-1]->NumPlayers() - 1; i>=0; --i) //count down in case of mid count changes?
03330                             {
03331                                 if (eTeam::teams[winner-1]->Player(i)->IsHuman())
03332                                 {
03333                                     gStats->won_rounds->add(eTeam::teams[winner-1]->Player(i)->GetName(), 1);
03334                                 }
03335                             }
03336                             //gStatistics - ladder add
03337                         }
03338 
03339                         // print winning message
03340                         tOutput message;
03341                         message << "$gamestate_winner_winner";
03342                         message << eTeam::teams[winner-1]->Name();
03343 
03344                         m_Mixer->PushButton(ROUND_WINNER);
03345 
03346                         sn_CenterMessage(message);
03347                         message << '\n';
03348                         se_SaveToScoreFile(message);
03349 
03350                         tString ladderLog;
03351                         ladderLog << "ROUND_WINNER " << ePlayerNetID::FilterName( eTeam::teams[winner-1]->Name() ) << "\n";
03352                         se_SaveToLadderLog( ladderLog );
03353                         tString notificationMessage( ePlayerNetID::FilterName( eTeam::teams[winner-1]->Name() ) );
03354                         notificationMessage << " has won the round";
03355                         se_sendEventNotification(tString("Round winner"), notificationMessage);
03356                     }
03357                 }
03358                 //gStatistics - highscore check
03359                 if (sg_singlePlayer && gStats && se_PlayerNetIDs.Len() > 0 && se_PlayerNetIDs(0)->IsHuman())
03360                 {
03361                     gStats->highscores->greater(se_PlayerNetIDs(0)->GetName(), se_PlayerNetIDs(0)->Score());
03362                 }
03363                 winner = -1;
03364             }
03365     }
03366 
03367     int winnerExtraRound = ( winner != 0 || alive == 0 ) ? 1 : 0;
03368 
03369 
03370     // do round end stuff one second after a winner was declared
03371     if ( winner && !roundOver && time-lastdeath >= 2.0f )
03372     {
03373         roundOver = true;
03374 
03375         const tList<eGameObject>& gameObjects = Grid()->GameObjects();
03376         for (int i=gameObjects.Len()-1;i>=0;i--)
03377         {
03378             eGameObject * e = gameObjects(i);
03379             if ( e )
03380             {
03381                 e->OnRoundEnd();
03382             }
03383         }
03384     }
03385 
03386     // analyze the ranking list
03387     if ( time-lastdeath < 2.0f )
03388     {
03389         holdBackNextRound = true;
03390     }
03391     else if (absolute_winner==0 &&
03392              sn_GetNetState()!=nCLIENT && se_PlayerNetIDs.Len()){
03393         ePlayerNetID::SortByScore();
03394         eTeam::SortByScore();
03395         if ( eTeam::teams.Len() > 0 )
03396             if (eTeam::teams.Len() <= 1
03397                     || ( eTeam::teams(0)->Score() > eTeam::teams(1)->Score() && sg_EnemyExists(0))){
03398 
03399                 // only then we can have a true winner:
03400                 if (eTeam::teams(0)->Score() >= sg_currentSettings->limitScore ||               // the score limit must be hit
03401                         rounds + winnerExtraRound >= sg_currentSettings->limitRounds ||     // or the round limit
03402                         tSysTimeFloat()>=startTime+sg_currentSettings->limitTime*60 ||      // or the time limit
03403                         (active <= 1 && eTeam::teams.Len() > 1)                                                         // or all but one players must have disconnected.
03404                    )
03405                 {
03406                     bool declareChampion = true;
03407                     if ( winner!=0 && wintimer > time - ( sg_currentSettings->finishType==gFINISH_EXPRESS ? 2.0f : 4.0 ) )
03408                     {
03409                         declareChampion = false;
03410                         holdBackNextRound= true;
03411                     }
03412 
03413                     if ( declareChampion )
03414                     {
03415                         lastdeath = time + ( sg_currentSettings->finishType==gFINISH_EXPRESS ? 2.0f : 6.0f );
03416 
03417                         {
03418                             tOutput message;
03419                             message.SetTemplateParameter(1, eTeam::teams[0]->Name() );
03420                             message << "$gamestate_champ_center";
03421                             sn_CenterMessage(message);
03422 
03423                             m_Mixer->PushButton(MATCH_WINNER);
03424                         }
03425 
03426                         tOutput message;
03427                         tColoredString name;
03428                         name << eTeam::teams[0]->Name();
03429                         name << tColoredString::ColorString(1,1,1);
03430 
03431                         tString ladderLog;
03432                         ladderLog << "MATCH_WINNER " << ePlayerNetID::FilterName( eTeam::teams[0]->Name() ) << "\n";
03433                         se_SaveToLadderLog( ladderLog );
03434                         tString notificationMessage( ePlayerNetID::FilterName( eTeam::teams[0]->Name() ) );
03435                         notificationMessage << " has won the match";
03436                         se_sendEventNotification(tString("Match winner"), notificationMessage);
03437 
03438 
03439                         message.SetTemplateParameter(1, name);
03440                         message << "$gamestate_champ_console";
03441 
03442                         if (eTeam::teams(0)->Score() >=sg_currentSettings->limitScore)
03443                         {
03444                             message.SetTemplateParameter(1, eTeam::teams(0)->Score());
03445                             message.SetTemplateParameter(2, sg_currentSettings->limitScore);
03446                             message << "$gamestate_champ_scorehit";
03447                         }
03448                         else if ( tSysTimeFloat()>=startTime+sg_currentSettings->limitTime*60)
03449                         {
03450                             message.SetTemplateParameter(1, sg_currentSettings->limitTime);
03451                             message << "$gamestate_champ_timehit";
03452                         }
03453                         else
03454                         {
03455                             message.SetTemplateParameter(1, rounds + 1);
03456                             message << "$gamestate_champ_default";
03457                         }
03458 
03459                         se_SaveToScoreFile(message);
03460                         se_SaveToScoreFile("$gamestate_champ_finalscores");
03461                         se_SaveToScoreFile(eTeam::Ranking( -1, false ));
03462                         se_SaveToScoreFile(ePlayerNetID::Ranking( -1, false ));
03463                         se_SaveToScoreFile(sg_GetCurrentTime( "Time: %Y/%m/%d %H:%M:%S\n" ));
03464                         se_SaveToScoreFile("\n\n");
03465 
03466                         eTeam* winningTeam = eTeam::teams(0);
03467                         if (!sg_singlePlayer && winningTeam->NumHumanPlayers() > 0 && winningTeam->NumHumanPlayers() > 0 && gStats)
03468                         {
03469                             //gStatistics - won matches add
03470                             for (int i = winningTeam->NumPlayers() - 1; i>=0; --i) //count down in case of mid count changes?
03471                             {
03472                                 if (winningTeam->Player(i)->IsHuman())
03473                                 {
03474                                     gStats->won_matches->add(winningTeam->Player(i)->GetName(), 1);
03475                                 }
03476                             }
03477                         }
03478 
03479                         sn_ConsoleOut(message);
03480 
03481                         m_Mixer->PushButton(MATCH_WINNER);
03482 
03483                         wintimer=time;
03484                         absolute_winner=1;
03485 
03486                         if ( se_mainGameTimer )
03487                             se_mainGameTimer->speed = 1;
03488 
03489                         //check for map rotation, new match...
03490                         if (rotationtype == 2)
03491                             rotate();
03492 
03493                         gRotation::HandleNewMatch();
03494 
03495                         StartNewMatch();
03496                     }
03497                 }
03498             }
03499     }
03500 
03501 
03502     // time to wait after last death til we start a new round
03503     REAL fintime=6;
03504 
03505     if (sg_currentSettings->finishType==gFINISH_EXPRESS)
03506         fintime=2.5;
03507 
03508     if (( ( winner || absolute_winner ) && wintimer+fintime < time)
03509             || (((alive==0 && eTeam::teams.Len()>=
03510 #ifndef DEDICATED
03511                   1
03512 #else
03513                   0
03514 #endif
03515                  )) && time-lastdeath >fintime-2
03516 #ifndef DEDICATED
03517                 && humans > 0
03518 #endif
03519                )){
03520 #ifdef DEBUG
03521         //con << "winner=" << winner << ' ';
03522         //con << "wintimer=" << wintimer << ' ';
03523         //con << "time=" << time << ' ';
03524         //con << "dt=" << deathTime << '\n';
03525 #endif
03526         if (!holdBackNextRound &&
03527                 (
03528                     ( sg_currentSettings->finishType==gFINISH_IMMEDIATELY ||
03529                       sg_currentSettings->finishType==gFINISH_EXPRESS ||
03530                       absolute_winner || ( teams_alive <= 1 && time-lastdeath>4.0f ) ) ||
03531                     ( winner && time - wintimer> 4.0f )
03532                 )
03533            )
03534         {
03535             rounds++;
03536             SetState(GS_PLAY,GS_DELETE_OBJECTS);
03537         }
03538 
03539         if ( !winner && !absolute_winner && sg_currentSettings->finishType==gFINISH_SPEEDUP && se_mainGameTimer)
03540         {
03541             se_mainGameTimer->speed*=1.01;
03542             if (se_mainGameTimer->speed>16)
03543                 se_mainGameTimer->speed=16;
03544         }
03545 
03546     }
03547 }
03548 
03549 void rotate()
03550 {
03551     if ( sg_mapRotation.Size() > 0 )
03552     {
03553         conf_mapfile.Set( sg_mapRotation.Current() );
03554         sg_mapRotation.Rotate();
03555     }
03556 
03557     if ( sg_configRotation.Size() > 0 )
03558     {
03559         st_Include( sg_configRotation.Current() );
03560         sg_configRotation.Rotate();
03561     }
03562 }
03563 
03564 void gGame::StartNewMatch(){
03565     //gStatistics - highscore check
03566     if (sg_singlePlayer && gStats && se_PlayerNetIDs.Len() > 0 && se_PlayerNetIDs(0)->IsHuman())
03567     {
03568         gStats->highscores->greater(se_PlayerNetIDs(0)->GetName(), se_PlayerNetIDs(0)->Score());
03569     }
03570 
03571     rounds=-100;
03572 }
03573 
03574 void gGame::StartNewMatchNow(){
03575     if ( rounds != 0 )
03576     {
03577         se_SaveToLadderLog(tString("NEW_MATCH\n"));
03578         se_sendEventNotification(tString("New match"), tString("Starting a new match"));
03579     }
03580 
03581 
03582     rounds=0;
03583     warning=0;
03584     startTime=tSysTimeFloat()-10;
03585 
03586     ePlayerNetID::ThrowOutDisconnected();
03587     ePlayerNetID::ResetScore();
03588 }
03589 
03590 #ifdef DEBUG
03591 extern bool debug_grid;
03592 // from display.cpp
03593 bool simplify_grid=1;
03594 #endif
03595 
03596 #ifndef DEDICATED
03597 // mouse grab toggling
03598 static uActionGlobal togglemousegrab( "TOGGLE_MOUSEGRAB" );
03599 static bool togglemousegrab_func(REAL x){
03600     if (x>0){
03601         su_mouseGrab = !su_mouseGrab;
03602     }
03603 
03604     return true;
03605 }
03606 static uActionGlobalFunc togglemousegrab_action(&togglemousegrab,&togglemousegrab_func, true );
03607 
03608 // pause game
03609 static uActionGlobal pausegame( "PAUSE_GAME" );
03610 static bool pausegame_func(REAL x){
03611     static bool paused=false;
03612 
03613     if (x>0){
03614         paused=!paused;
03615         se_PauseGameTimer(paused);
03616     }
03617 
03618     return true;
03619 }
03620 static uActionGlobalFunc pausegame_action(&pausegame,&pausegame_func, true );
03621 
03622 // texture reloading
03623 static uActionGlobal reloadtextures( "RELOAD_TEXTURES" );
03624 static bool reloadtextures_func(REAL x){
03625     if (x>0){
03626         rITexture::UnloadAll();
03627     }
03628 
03629     return true;
03630 }
03631 static uActionGlobalFunc reloadtextures_action(&reloadtextures,&reloadtextures_func, true );
03632 
03633 // menu
03634 static uActionGlobal ingamemenu( "INGAME_MENU" );
03635 static bool ingamemenu_func(REAL x){
03636     if (x>0){
03637         st_ToDo(&ingame_menu);
03638     }
03639 
03640     return true;
03641 }
03642 static uActionGlobalFunc ingamemenu_action(&ingamemenu,&ingamemenu_func, true );
03643 #endif // dedicated
03644 
03645 bool gGame::GameLoop(bool input){
03646     nNetState netstate = sn_GetNetState();
03647 
03648 #ifdef DEBUG
03649     grid->Check();
03650     if (simplify_grid)
03651 #endif
03652         grid->SimplifyAll(10);
03653 
03654 #ifdef DEBUG
03655     grid->Check();
03656 #endif
03657 
03658     //if (std::cin.good() && !std::cin.underflow())
03659     //tConfItemBase::LoadAll(std::cin);
03660     // network syncing
03661     REAL gtime=0;
03662     REAL time=0;
03663     se_SyncGameTimer();
03664     if (state==GS_PLAY){
03665         if ( netstate != sn_GetNetState() )
03666         {
03667             return false;
03668         }
03669         gtime=se_GameTime();
03670         time=gtime;
03671 
03672         if (sn_GetNetState()==nSTANDALONE && sg_IngameMenu)
03673             se_PauseGameTimer(true);
03674 
03675         static int lastcountdown=0;
03676         int cd=int(floor(-time))+1;
03677         if (cd>=0 && cd<PREPARE_TIME && cd!=lastcountdown && se_mainGameTimer && se_mainGameTimer->IsSynced() ){
03678             lastcountdown=cd;
03679             tString s;
03680             s << cd;
03681 
03682             switch (cd) {
03683             case 3:
03684                 m_Mixer->PushButton(ANNOUNCER_3);
03685                 break;
03686             case 2:
03687                 m_Mixer->PushButton(ANNOUNCER_2);
03688                 break;
03689             case 1:
03690                 m_Mixer->PushButton(ANNOUNCER_1);
03691                 break;
03692             case 0:
03693                 m_Mixer->PushButton(ANNOUNCER_GO);
03694                 break;
03695             }
03696             con.CenterDisplay(s,0);
03697         }
03698     }
03699     //con << sg_netPlayerWalls.Len() << '\n';
03700 
03701 #ifndef DEDICATED
03702     if (input){
03703         su_HandleDelayedEvents();
03704 
03705         SDL_Event tEvent;
03706 
03707         uInputProcessGuard inputProcessGuard;
03708         while (su_GetSDLInput(tEvent,time)){
03709             if (time>gtime) time=gtime;
03710             if (time>lastTime_gameloop){
03711                 Timestep(time);
03712                 lastTime_gameloop=time;
03713             }
03714 
03715 
03716             if (!su_HandleEvent(tEvent, false))
03717                 switch (tEvent.type){
03718                 case SDL_MOUSEBUTTONDOWN:
03719                     break;
03720                 case SDL_KEYDOWN:
03721                     switch (tEvent.key.keysym.sym){
03722 
03723                     case(27):
03724                                     //                                case('q'):
03725                                     st_ToDo(&ingame_menu);
03726                         break;
03727 #ifdef DEBUG
03728                     case('d'):
03729                                     debug_grid=!debug_grid;
03730                         break;
03731 
03732                     case('a'):
03733                                     simplify_grid=!simplify_grid;
03734                         break;
03735 
03736                     case('l'):
03737                                     sr_glOut=!sr_glOut;
03738                         break;
03739 
03740                     case('b'):
03741                                     st_Breakpoint();
03742                         break;
03743 
03744                     case('t'):
03745                                     think=!think;
03746                         break;
03747                         /* #ifndef WIN32
03748                            case('f'):
03749                            fullscreen=(!fullscreen);
03750                            con << fullscreen << "x!\n";
03751                            XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
03752                            break;
03753                            #endif */
03754 #endif
03755 
03756                     default:
03757                         break;
03758                     }
03759                     break;
03760 
03761                 default:
03762                     break;
03763                 }
03764         }
03765 
03766         su_InputSync();
03767     }
03768 #endif
03769 
03770     if ( netstate != sn_GetNetState() )
03771     {
03772         return false;
03773     }
03774 
03775     // do basic network receiving and sending. This pushes out all input the player makes as fast as possible.
03776     sg_Receive();
03777     sn_SendPlanned();
03778 
03779     bool synced = se_mainGameTimer && ( se_mainGameTimer->IsSynced() || ( stateNext >= GS_DELETE_OBJECTS || stateNext <= GS_CREATE_GRID ) );
03780 
03781     if  (!synced)
03782     {
03783         // see if there is a game object owned by this client, if so, declare emergency sync
03784         for (int pi = MAX_PLAYERS-1; pi >= 0; --pi )
03785         {
03786             ePlayer * p = ePlayer::PlayerConfig(pi);
03787             if ( !p )
03788                 break;
03789             ePlayerNetID * np = p->netPlayer;
03790             if ( !np )
03791                 break;
03792             if ( np->Object() )
03793             {
03794                 synced = true;
03795                 break;
03796             }
03797         }
03798     }
03799     else if ( !synced_ )
03800     {
03801         // synced finally. Send our player info over so we can join the game.
03802         ePlayerNetID::Update();
03803 
03804         // and trigger the scheduled auto-logons.
03805         ePlayer::SendAuthNames();
03806 
03807         synced_ = true;
03808     }
03809 
03810     static float lastTime = -1;
03811 
03812     if (sg_gameTimeInterval >= 0 && (gtime >= lastTime + sg_gameTimeInterval || (gtime < lastTime && gtime >= 0))) {
03813         tOutput out;
03814         out << "GAME_TIME " << gtime << '\n';
03815         se_SaveToLadderLog(out);
03816         lastTime = gtime;
03817     }
03818 
03819     if (state==GS_PLAY){
03820         if (gtime<0 && gtime>-PREPARE_TIME+.3)
03821             eCamera::s_Timestep(grid, gtime);
03822         else{
03823             // keep ping weight high while playing, that gives the best meassurements
03824             nPingAverager::SetWeight(1);
03825 
03826             if (gtime>=lastTime_gameloop){
03827 
03828 #ifdef CONNECTION_STRESS
03829                 if ( sg_ConnectionStress )
03830                 {
03831                     tRandomizer & randomizer = tRandomizer::GetInstance();
03832                     int random = randomizer.Get( 1000 );
03833                     if ( random == 0 )
03834                     {
03835                         sg_RequestedDisconnection = true;
03836                         //                                              sn_SetNetState( nSTANDALONE );
03837                         goon = false;
03838                     }
03839                 }
03840 #endif
03841 
03842 
03843                 Timestep(gtime,true);
03844                 lastTime_gameloop=gtime;
03845             }
03846             lastTime_gameloop=gtime;
03847         }
03848         //    else if (lastTime_gameloop>gtime+10)
03849         // lastTime_gameloop=gtime;
03850 
03851 
03852 
03853         if (sn_GetNetState()!=nCLIENT)
03854         {
03855             // simulate IAs
03856             for (int i=se_PlayerNetIDs.Len()-1;i>=0;i--)
03857             {
03858                 gAIPlayer *ai = dynamic_cast<gAIPlayer*>(se_PlayerNetIDs(i));
03859                 if (ai && think)
03860                     ai->Timestep(gtime);
03861             }
03862 
03863             Analysis(gtime);
03864 
03865             // wait for chatting players
03866             if ( sn_GetNetState()==nSERVER && gtime < sg_lastChatBreakTime + 1 )
03867                 se_PauseGameTimer( gtime < sg_lastChatBreakTime && ePlayerNetID::WaitToLeaveChat() );
03868         }
03869 
03870         // send game object updates
03871         nNetObject::SyncAll();
03872         sn_SendPlanned();
03873 
03874         if ( gtime<=-PREPARE_TIME+.5 || !goon || !synced )
03875         {
03876 #ifndef DEDICATED
03877             if (input)
03878             {
03879                 if ( !synced )
03880                 {
03881                     con.CenterDisplay(tString(tOutput("$network_login_sync")),0);
03882                 }
03883 
03884                 if ( sr_glOut )
03885                     rSysDep::ClearGL();
03886             }
03887 
03888             if ( input )
03889                 rSysDep::SwapGL();
03890 #endif
03891         }
03892         else
03893             Render(grid, gtime, input);
03894 
03895         if ( netstate != sn_GetNetState() )
03896         {
03897             return false;
03898         }
03899 
03900         return goon;
03901     }
03902     else{
03903         // between rounds, assume we're synced
03904         //if ( !synced_ && sn_GetNetState() != nSERVER )
03905         //    ePlayerNetID::Update();
03906         // synced_ = true;
03907 
03908 #ifndef DEDICATED
03909         // send game object updates
03910         nNetObject::SyncAll();
03911         sn_SendPlanned();
03912 
03913         if (input)
03914         {
03915             if (sr_glOut)
03916                 rSysDep::ClearGL();
03917             rSysDep::SwapGL();
03918         }
03919 #endif
03920         tDelay( 10000 );
03921         return goon;
03922     }
03923 }
03924 
03925 
03926 bool gGame::GridIsReady(int client){
03927     return HasBeenTransmitted(client) &&
03928            (client_gamestate[client]>=GS_TRANSFER_OBJECTS &&
03929             client_gamestate[client]<=GS_DELETE_OBJECTS);
03930 }
03931 
03932 #include <fcntl.h>
03933 #include <stdio.h>
03934 #include <errno.h>
03935 
03936 bool GameLoop(bool input=true){
03937     /*
03938       int oldflags = fcntl (fileno(stdin), F_GETFD, 0);
03939       if (oldflags<0)
03940       std::cout << errno << '\n';
03941        
03942       if (fcntl(fileno(stdin), F_SETFL, oldflags | O_NONBLOCK)<0)
03943       std::cout << errno << '\n';
03944       
03945     //if (std::cin && std::cin.good() && !std::cin.eof() && !std::cin.fail() && !std::cin.bad()){
03946     //if (std::cin.rdbuf()->overflow()!=EOF){
03947     //if (std::cin.rdbuf()->in_avail()>0){
03948 
03949     char c[10];
03950     int in=0;
03951     in=read (fileno(stdin),c,9);
03952     for (int i=0;i<in;i++)
03953     std::cout << c;
03954      */
03955 
03956     // see if pings have dramatically changed
03957     if (sn_GetNetState()==nSERVER){
03958         REAL t=tSysTimeFloat();
03959         for (int i=se_PlayerNetIDs.Len()-1;i>=0;i--){
03960             ePlayerNetID *p=se_PlayerNetIDs(i);
03961 
03962             // get average and variance (increased a bit) of this player's ping
03963             nPingAverager const & averager = sn_Connections[p->Owner()].ping;
03964             REAL realping = averager.GetPing();
03965             REAL pingvariance = averager.GetSlowAverager().GetDataVariance() + realping * realping * .01;
03966 
03967             // deviation of real ping and synced ping
03968             REAL deviation = realping - p->ping;
03969 
03970             // measured against the variance, this player's ping deviates this much
03971             // from the communicated value
03972             REAL relativedeviation = deviation * deviation / pingvariance;
03973 
03974             if (0 == p->Owner())
03975                 realping = 0;
03976 
03977             if ( ( t - p->lastSync - 5 ) * relativedeviation > 5 ){
03978                 // if yes, send a message about it
03979                 p->ping = realping;
03980                 p->RequestSync(false);
03981             }
03982         }
03983     }
03984 
03985     bool goon=false;
03986     if (sg_currentGame){
03987         tControlledPTR< nNetObject > keep( sg_currentGame );
03988         sg_currentGame->StateUpdate();
03989         goon=!uMenu::quickexit && bool(sg_currentGame) && sg_currentGame->GameLoop(input);
03990     }
03991     return goon;
03992 }
03993 
03994 void gameloop_idle()
03995 {
03996     se_UserShowScores( false );
03997     sg_Receive();
03998     nNetObject::SyncAll();
03999     sn_SendPlanned();
04000     GameLoop(false);
04001 }
04002 
04003 static void sg_EnterGameCleanup();
04004 
04005 void sg_EnterGameCore( nNetState enter_state ){
04006     gLogo::SetBig(false);
04007 
04008     sg_RequestedDisconnection = false;
04009 
04010     sr_con.SetHeight(7);
04011 
04012     //  exit_game_objects(grid);
04013     eSoundMixer* mixer = eSoundMixer::GetMixer();
04014     mixer->SetMode(GRID_TRACK);
04015 
04016     // enter single player settings
04017     if ( sn_GetNetState() != nCLIENT )
04018     {
04019         sg_currentSettings = &singlePlayer;
04020         sg_copySettings();
04021 
04022         // initiate rotation
04023         rotate();
04024         gRotation::HandleNewRound();
04025         gRotation::HandleNewMatch();
04026     }
04027 
04028     //gStatistics - original load call
04029 
04030     uMenu::SetIdle(gameloop_idle);
04031     sr_con.autoDisplayAtSwap=true;
04032     bool goon=true;
04033     while (bool(sg_currentGame) && goon && sn_GetNetState()==enter_state){
04034 #ifdef DEDICATED // read input
04035         sr_Read_stdin();
04036 
04037         if ( sn_BasicNetworkSystem.Select( 1.0 / ( sg_dedicatedFPSIdleFactor * sg_dedicatedFPS )  ) )
04038         {
04039             // new network data arrived, do the most urgent work now
04040             tAdvanceFrame();
04041             sg_Receive();
04042             se_SyncGameTimer();
04043             REAL time=se_GameTime();
04044             sg_currentGame->StateUpdate();
04045             if ( time > 0 )
04046             {
04047                 // only simulate the objects that have pending events to execute
04048                 eGameObject::s_Timestep(sg_currentGame->Grid(), time, 1E+10 );
04049 
04050                 // send out updates immediately
04051                 nNetObject::SyncAll();
04052                 tAdvanceFrame();
04053                 sn_SendPlanned();
04054             }
04055         }
04056 #endif
04057 
04058         // do the regular simulation
04059         tAdvanceFrame();
04060 
04061         goon=GameLoop();
04062 
04063         st_DoToDo();
04064     }
04065 
04066     sg_EnterGameCleanup();
04067 }
04068 
04069 void sg_EnterGameCleanup()
04070 {
04071     //gStatistics - save high scores
04072 
04073     eSoundMixer* mixer = eSoundMixer::GetMixer();
04074     mixer->SetMode(GUI_TRACK);
04075 
04076     sn_SetNetState( nSTANDALONE );
04077 
04078     // delete all AI players
04079     gAIPlayer::ClearAll();
04080     // gAIPlayer::SetNumberOfAIs(0, 0, 0, -1);
04081     // gAITeam::BalanceWithAIs( false );
04082     // gAIPlayer::ClearAll();
04083 
04084     gLogo::SetDisplayed(true);
04085     uMenu::SetIdle(NULL);
04086     sr_con.autoDisplayAtSwap=false;
04087     sr_con.fullscreen=false;
04088 
04089     //  exit_game_objects(grid);
04090     nNetObject::ClearAll();
04091     ePlayerNetID::ClearAll();
04092     sg_currentGame = NULL;
04093     uMenu::exitToMain = false;
04094 }
04095 
04096 void sg_EnterGame( nNetState enter_state )
04097 {
04098     try
04099     {
04100         // enter the game
04101         sg_EnterGameCore( enter_state );
04102     }
04103     catch (tException const & e)
04104     {
04105         // cleanup
04106         sg_EnterGameCleanup();
04107 
04108         // inform user of generic errors
04109         tConsole::Message( e.GetName(), e.GetDescription(), 120000 );
04110     }
04111     // again: VC6 does not catch tGenericException with above statement
04112 #ifdef _MSC_VER
04113 #pragma warning ( disable : 4286 )
04114     catch (tGenericException const & e)
04115     {
04116         // cleanup
04117         sg_EnterGameCleanup();
04118 
04119         // inform user of generic errors
04120         tConsole::Message( e.GetName(), e.GetDescription(), 120000 );
04121     }
04122 #endif
04123 
04124     // bounce teams
04125     for ( int i = eTeam::teams.Len()-1; i>=0; --i )
04126     {
04127         tJUST_CONTROLLED_PTR< eTeam > t = eTeam::teams(i);
04128     }
04129 }
04130 
04131 bool GridIsReady(int c){
04132     return bool(sg_currentGame) && sg_currentGame->GridIsReady(c);
04133 }
04134 
04135 
04136 // avoid transfer of game objects if the grid is not yes constructed
04137 static bool notrans(){
04138     return !GridIsReady(eTransferInhibitor::User());
04139 }
04140 
04141 static eTransferInhibitor inh(&notrans);
04142 
04143 // are we active?
04144 void Activate(bool act){
04145 #ifdef DEBUG
04146     return;
04147 #endif
04148 
04149 // another fullscreen fix ammendmend: avoid the short screen flicker
04150 // by ignoring deactivation events in fullscreen mode completely.
04151 #ifndef WIN32
04152 #ifndef MACOSX
04153     if ( currentScreensetting.fullscreen && !act )
04154     {
04155         return;
04156     }
04157 #endif
04158 #endif
04159 
04160     sr_Activate( act );
04161 
04162     if (!tRecorder::IsRunning() )
04163     {
04164         if (sn_GetNetState()==nSTANDALONE)
04165         {
04166             se_PauseGameTimer(!act);
04167         }
04168 
04169         se_ChatState( ePlayerNetID::ChatFlags_Away, !act);
04170     }
04171 }
04172 
04173 // ************************************
04174 // full screen messages from the server
04175 // ************************************
04176 
04177 static nVersionFeature sg_fullscreenMessages(14);
04178 
04179 static void sg_FullscreenIdle()
04180 {
04181     tAdvanceFrame();
04182     se_SyncGameTimer();
04183     gGame::NetSync();
04184     if ( sg_currentGame )
04185         sg_currentGame->StateUpdate();
04186 }
04187 
04188 void sg_ClientFullscreenMessage( tOutput const & title, tOutput const & message, REAL timeout ){
04189     // keep syncing the network
04190     rPerFrameTask idle( sg_FullscreenIdle );
04191 
04192     // put players into idle mode
04193     ePlayerNetID::SpectateAll();
04194     se_ChatState( ePlayerNetID::ChatFlags_Menu, true );
04195 
04196     // show message
04197     uMenu::Message( title, message, timeout );
04198 
04199     // and print it to the console
04200 #ifndef DEDICATED
04201     con <<  title << "\n" << message << "\n";
04202 #endif
04203 
04204     // get players out of idle mode again
04205     ePlayerNetID::SpectateAll(false);
04206     se_ChatState( ePlayerNetID::ChatFlags_Menu, false );
04207 }
04208 
04209 static tString sg_fullscreenMessageTitle;
04210 static tString sg_fullscreenMessageMessage;
04211 static REAL sg_fullscreenMessageTimeout;
04212 static void sg_TodoClientFullscreenMessage()
04213 {
04214     sg_ClientFullscreenMessage( sg_fullscreenMessageTitle, sg_fullscreenMessageMessage, sg_fullscreenMessageTimeout );
04215 }
04216 
04217 static void sg_ClientFullscreenMessage(nMessage &m){
04218     if (sn_GetNetState()!=nSERVER){
04219         sg_fullscreenMessageTimeout = 60;
04220 
04221         m >> sg_fullscreenMessageTitle;
04222         m >> sg_fullscreenMessageMessage;
04223         m >> sg_fullscreenMessageTimeout;
04224 
04225         st_ToDo( sg_TodoClientFullscreenMessage );
04226     }
04227 }
04228 
04229 static nDescriptor sg_clientFullscreenMessage(312,sg_ClientFullscreenMessage,"client_fsm");
04230 
04231 // causes the connected clients to break and print a fullscreen message
04232 void sg_FullscreenMessage(tOutput const & title, tOutput const & message, REAL timeout, int client){
04233     tJUST_CONTROLLED_PTR< nMessage > m=new nMessage(sg_clientFullscreenMessage);
04234     *m << title;
04235     *m << message;
04236     *m << timeout;
04237 
04238     tString complete( title );
04239     complete << "\n" << message << "\n";
04240 
04241     if (client <= 0){
04242         if ( sg_fullscreenMessages.Supported() )
04243             m->BroadCast();
04244         else
04245         {
04246             for (int c = MAXCLIENTS; c > 0; --c)
04247             {
04248                 if ( sn_Connections[c].socket )
04249                 {
04250                     if ( sg_fullscreenMessages.Supported(c) )
04251                         m->Send(c);
04252                     else
04253                         sn_ConsoleOut(complete, c);
04254                 }
04255             }
04256         }
04257 
04258         // display the message locally, waiting for the clients to have seen it
04259         {
04260             // stop the game
04261             bool paused = se_mainGameTimer && se_mainGameTimer->speed < .0001;
04262             se_PauseGameTimer(true);
04263             gGame::NetSyncIdle();
04264 
04265             REAL waitTo = tSysTimeFloat() + timeout;
04266             REAL waitToMin = tSysTimeFloat() + 1.0;
04267             sg_ClientFullscreenMessage( title, message, timeout );
04268 
04269             // wait for players to see it
04270             bool goon = true;
04271             while ( goon && waitTo > tSysTimeFloat() )
04272             {
04273                 sg_FullscreenIdle();
04274                 gameloop_idle();
04275                 if ( se_GameTime() > sg_lastChatBreakTime )
04276                     se_PauseGameTimer(true);
04277 
04278                 // give the clients a second to enter chat state
04279                 if ( tSysTimeFloat() > waitToMin )
04280                 {
04281                     goon = false;
04282                     for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
04283                     {
04284                         ePlayerNetID* player = se_PlayerNetIDs(i);
04285                         if ( player->IsChatting() )
04286                             goon = true;
04287                     }
04288                 }
04289             }
04290 
04291             // continue the game
04292             se_PauseGameTimer(paused);
04293             gGame::NetSyncIdle();
04294         }
04295     }
04296     else
04297     {
04298         if ( sg_fullscreenMessages.Supported(client) )
04299             m->Send(client);
04300         else
04301             sn_ConsoleOut(complete, client);
04302     }
04303 }
04304 
04305 static void sg_FullscreenMessageConf(std::istream &s)
04306 {
04307     // read the timeout
04308     REAL timeout;
04309     s >> timeout;
04310 
04311     if ( !s.good() || s.eof() )
04312     {
04313         con << "Usage: FULLSCREEN_MESSAGE <timeout> <message>\n";
04314         return;
04315     }
04316 
04317     // read the message
04318     tString message;
04319     message.ReadLine( s, true );
04320 
04321     message += "\n";
04322 
04323     // display it
04324     sg_FullscreenMessage( "$fullscreen_message_title", message , timeout );
04325 }
04326 
04327 static tConfItemFunc sg_fullscreenMessageConf("FULLSCREEN_MESSAGE",&sg_FullscreenMessageConf);
04328 
04329 // **************
04330 // Login callback
04331 // **************
04332 
04333 // message of day presented to clients logging in
04334 tString sg_greeting("");
04335 static tConfItemLine a_mod("MESSAGE_OF_DAY",sg_greeting);
04336 
04337 tString sg_greetingTitle("");
04338 static tConfItemLine a_tod("TITLE_OF_DAY",sg_greetingTitle);
04339 
04340 REAL sg_greetingTimeout=60;
04341 static tSettingItem< REAL > a_modt("MESSAGE_OF_DAY_TIMEOUT",sg_greetingTimeout);
04342 
04343 static void LoginCallback(){
04344     client_gamestate[nCallbackLoginLogout::User()]=0;
04345     if ( nCallbackLoginLogout::Login() && nCallbackLoginLogout::User() > 0 )
04346     {
04347         if ( sg_greeting.Len()>1 )
04348         {
04349             if ( sg_greetingTitle.Len() <= 1 )
04350                 sg_greetingTitle = "Server message";
04351 
04352             sg_FullscreenMessage( sg_greetingTitle, sg_greeting, sg_greetingTimeout, nCallbackLoginLogout::User() );
04353         }
04354     }
04355 }
04356 
04357 #ifdef ENABLE_ZONESV2
04358 void oldFortressAutomaticAssignment(zZone *zone, zMonitorPtr monitor);
04359 
04360 void init_second_pass_zones(eGrid *grid, gParser *parser)
04361 {
04362     const tList<eGameObject>& gameObjects = grid->GameObjects();
04363     for (int i=gameObjects.Len()-1;i>=0;i--)
04364     {
04365         zZone *zone=dynamic_cast<zZone *>(gameObjects(i));
04366 
04367         if (zone && zone->getOldFortressAutomaticAssignmentBehavior() == true)
04368         {
04369             zMonitorPtr monitor = parser->getMonitor(zone->getName());
04370             oldFortressAutomaticAssignment(zone, monitor);
04371         }
04372     }
04373 }
04374 
04375 void oldFortressAutomaticAssignment(zZone *zone, zMonitorPtr monitor)
04376 {
04377     if (zone->getOldFortressAutomaticAssignmentBehavior() == true)
04378     {      // Recreate the automatic assignment of zones to teams as found in Arthemis
04379 
04380         // Do only once
04381         zone->setOldFortressAutomaticAssignmentBehavior( false );
04382 
04383         //      teamDistance_ = 0;
04384         const tList<eGameObject>& gameObjects = zone->Grid()->GameObjects();
04385         gCycle * closest = NULL;
04386         REAL closestDistance = 0;
04387         eTeam * team;
04388         for (int i=gameObjects.Len()-1;i>=0;i--)
04389         {
04390             gCycle *other=dynamic_cast<gCycle *>(gameObjects(i));
04391 
04392             if (other )
04393             {
04394                 // eTeam * otherTeam = other->Player()->CurrentTeam();
04395                 eCoord otherpos = other->Position() - zone->GetPosition();
04396                 REAL distance = otherpos.NormSquared();
04397                 if ( !closest || distance < closestDistance )
04398                 {
04399                     // check whether other zones are already registered to that team
04400                     /*
04401                     zZone * farthest = NULL;
04402                     int count = 0;
04403                     if ( sg_baseZonesPerTeam > 0 )
04404                       CountZonesOfTeam( Grid(), otherTeam, count, farthest );
04405 
04406                     // only set team if not too many closer other zones are registered
04407                     //            if ( sg_baseZonesPerTeam == 0 || count < sg_baseZonesPerTeam || farthest->teamDistance_ > distance )
04408                     */
04409                     {
04410                         closest = other;
04411                         closestDistance = distance;
04412                     }
04413                 }
04414             }
04415         }
04416 
04417         if ( closest )
04418         {
04419             // take over team and color
04420             team = closest->Player()->CurrentTeam();
04421             rColor teamColor;
04422             teamColor.r_ = team->R()/15.0;
04423             teamColor.g_ = team->G()/15.0;
04424             teamColor.b_ = team->B()/15.0;
04425             zone->getShape()->setColor(teamColor);
04426             // teamDistance_ = closestDistance;
04427 
04428             { // Build the monitor influence objects for this zone
04429 
04430 
04431                 // Load the associated monitor
04432                 // Its name is the same as the zone, as both are generated in the same way
04433                 // through a series of #
04434 
04435 
04436                 //
04437                 zEffectGroupPtr currentZoneEffect;
04438 
04439                 // The part for the defender
04440                 zValidatorPtr validator;
04441                 if (sg_singlePlayer) {
04442                     // In single player mode, all the players teams have the ID 0, making team logic fail
04443                     gVectorExtra< nNetObjectID > playerOwners;
04444                     playerOwners.push_back(closest->Player()->ID());
04445                     currentZoneEffect = zEffectGroupPtr(new zEffectGroup(playerOwners, gVectorExtra< nNetObjectID >()));
04446                     validator = zValidatorPtr( new zValidatorOwner(_ignore, _ignore) );
04447                 }
04448                 else {
04449                     gVectorExtra< nNetObjectID > teamOwners;
04450                     teamOwners.push_back(team->ID());
04451                     currentZoneEffect = zEffectGroupPtr(new zEffectGroup(gVectorExtra< nNetObjectID >(), teamOwners));
04452                     validator = zValidatorPtr( new zValidatorOwnerTeam(_ignore, _ignore) );
04453                 }
04454 
04455                 zMonitorInfluencePtr inflDefender = zMonitorInfluencePtr(new zMonitorInfluence( monitor ));
04456 
04457                 tPolynomial<nMessage> tpInfluenceSlide(2);
04458                 tpInfluenceSlide[0] = -1.0 * sg_defendRate;
04459                 inflDefender->setInfluenceSlide( tpInfluenceSlide );
04460                 //                inflDefender->setInfluenceSlide( tFunction(-1.0 * sg_defendRate, 0.0) );
04461 
04462                 // Store all the objects
04463                 validator->addMonitorInfluence( inflDefender );
04464                 currentZoneEffect->addValidator( validator );
04465 
04466                 // The part for the attaquer
04467                 if (sg_singlePlayer) {
04468                     // In single player mode, all the players teams have the ID 0, making team logic fail
04469                     validator = zValidatorPtr( new zValidatorAllButOwner(_ignore, _ignore) );
04470                 }
04471                 else {
04472                     validator = zValidatorPtr( new zValidatorAllButTeamOwner(_ignore, _ignore) );
04473                 }
04474 
04475                 zMonitorInfluencePtr inflAttaquer = zMonitorInfluencePtr(new zMonitorInfluence( monitor ));
04476 
04477                 tpInfluenceSlide[0] = -1.0 * sg_defendRate;
04478                 inflAttaquer->setInfluenceSlide( tpInfluenceSlide );
04479                 //                inflAttaquer->setInfluenceSlide(  tFunction(sg_conquestRate, 0.0) );
04480                 // Store all the objects
04481                 validator->addMonitorInfluence( inflAttaquer );
04482                 currentZoneEffect->addValidator( validator );
04483 
04484 
04485 
04486                 zone->addEffectGroupInside( currentZoneEffect );
04487 
04488             }
04489 
04490             zone->RequestSync();
04491         }
04492 
04493         /*
04494         // if this zone does not belong to a team, discard it.
04495         if ( !team )
04496           {
04497         return true;
04498           }
04499 
04500         // check other zones owned by the same team. Discard the one farthest away
04501         // if the max count is exceeded
04502         if ( team && sg_baseZonesPerTeam > 0 )
04503           {
04504         gBaseZoneHack * farthest = 0;
04505         int count = 0;
04506         CountZonesOfTeam( Grid(), team, count, farthest );
04507 
04508         // discard team of farthest zone
04509         if ( count > sg_baseZonesPerTeam )
04510         farthest->team = NULL;
04511           }
04512         */
04513     }
04514 }
04515 #endif
04516 
04517 
04518 static nCallbackLoginLogout lc(LoginCallback);
04519 
04520 

Generated on Sat Mar 15 22:56:08 2008 for Armagetron Advanced by  doxygen 1.5.4