OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Application.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Main class to initialize configuration and execute the game */
19 
20 #include "C4Include.h"
22 #include "game/C4Application.h"
23 
24 #include "C4Version.h"
25 #include "editor/C4Console.h"
26 #include "game/C4FullScreen.h"
27 #include "game/C4GraphicsSystem.h"
28 #include "graphics/C4Draw.h"
30 #include "graphics/StdPNG.h"
31 #include "gui/C4GameLobby.h"
32 #include "gui/C4GfxErrorDlg.h"
33 #include "gui/C4MessageInput.h"
34 #ifdef _WIN32
35 #include "gui/C4UpdateDlg.h"
36 #endif
37 #include "gui/C4Startup.h"
38 #include "landscape/C4Particles.h"
39 #include "network/C4Network2.h"
40 #include "network/C4Network2IRC.h"
41 #include "platform/C4GamePadCon.h"
42 
43 #include <getopt.h>
44 
45 static C4Network2IRCClient ApplicationIRCClient;
46 const std::string C4Application::Revision{ C4REVISION };
47 
49  IRCClient(ApplicationIRCClient)
50 {
51 }
52 
54 {
55  // clear gamepad
56  if (pGamePadControl) delete pGamePadControl;
57  // Close log
58  CloseLog();
59 }
60 
61 bool C4Application::DoInit(int argc, char * argv[])
62 {
63  assert(AppState == C4AS_None);
64  // Config overwrite by parameter
65  StdStrBuf sConfigFilename;
66  for (int32_t iPar=0; iPar < argc; iPar++)
67  if (SEqual2NoCase(argv[iPar], "--config="))
68  sConfigFilename.Copy(argv[iPar] + 9);
69  // Config check
70  Config.Init();
71  Config.Load(sConfigFilename.getData());
72  Config.Save();
73  // sometimes, the configuration can become corrupted due to loading errors or w/e
74  // check this and reset defaults if necessary
75  if (Config.IsCorrupted())
76  {
77  if (sConfigFilename)
78  {
79  // custom config corrupted: Fail
80  Log("ERROR: Custom configuration corrupted - program abort!\n");
81  return false;
82  }
83  else
84  {
85  // default config corrupted: Restore default
86  Log("Warning: Configuration corrupted - restoring default!\n");
87  Config.Default();
88  Config.Save();
89  Config.Load();
90  }
91  }
92  // Open log
93  OpenLog();
94 
95  // Engine header message
96  Log(C4ENGINECAPTION);
97  LogF("Version: %s %s (%s - %s)", C4VERSION, C4_OS, GetRevision(), C4REVISION_TS);
98  LogF(R"(ExePath: "%s")", Config.General.ExePath.getData());
99  LogF(R"(SystemDataPath: "%s")", Config.General.SystemDataPath);
100  LogF(R"(UserDataPath: "%s")", Config.General.UserDataPath);
101 
102  // Init C4Group
106 
107  // Cleanup temp folders left behind
109 
110  // Initialize game data paths
111  Reloc.Init();
112 
113  // init system group
115  {
116  // Error opening system group - no LogFatal, because it needs language table.
117  // This will *not* use the FatalErrors stack, but this will cause the game
118  // to instantly halt, anyway.
119  const char *szMessage = "Error opening system group file (System.ocg)!";
120  Log(szMessage);
121  // Fatal error, game cannot start - have player notice
122  MessageDialog(szMessage);
123  return false;
124  }
125  // Parse command line
126  ParseCommandLine(argc, argv);
127 
128  // Open additional logs that depend on command line
129  OpenExtraLogs();
130 
131  // Init external language packs
132  Languages.Init();
133  // Load language string table
135  // No language table was loaded - bad luck...
136  if (!Languages.HasStringTable())
137  Log("WARNING: No language string table loaded!");
138 
139 #if defined(WIN32) && defined(WITH_AUTOMATIC_UPDATE)
140  // Windows: handle incoming updates directly, even before starting up the gui
141  // because updates will be applied in the console anyway.
142  if (!Application.IncomingUpdate.empty())
143  if (C4UpdateDlg::ApplyUpdate(Application.IncomingUpdate.c_str(), false, nullptr))
144  return true;
145 #endif
146 
147  // Fixup resolution
148  if (!Config.Graphics.Windowed)
150 
151  // activate
152  Active=true;
153 
154  // Init carrier window
155  if (!isEditor)
156  {
157  if (!(pWindow = FullScreen.Init(this)))
158  { Clear(); ShowGfxErrorDialog(); return false; }
159  }
160  else
161  {
162  if (!(pWindow = Console.Init(this)))
163  { Clear(); return false; }
164  }
165 
166  // init timers (needs window)
168 
169  // Initialize OpenGL
170  bool success = DDrawInit(this, GetConfigWidth(), GetConfigHeight(), Config.Graphics.Monitor);
171  if (!success) { LogFatal(LoadResStr("IDS_ERR_DDRAW")); Clear(); ShowGfxErrorDialog(); return false; }
172 
173  if (!isEditor)
174  {
177  }
178 
179  // Initialize gamepad
182 
183  AppState = C4AS_PreInit;
184 
185  return true;
186 }
187 
189 {
190  *Game.PlayerFilenames = 0;
191 }
192 
193 void C4Application::ParseCommandLine(int argc, char * argv[])
194 {
195 
196  StdStrBuf CmdLine("Command line:");
197  for(int i = 0; i < argc; ++i) {
198  CmdLine.Append(" ");
199  CmdLine.Append(argv[i]);
200  }
201  Log(CmdLine.getData());
202 
204  Game.NetworkActive = false;
205  isEditor = 2;
206  int c;
207  while (true)
208  {
209 
210  static struct option long_options[] =
211  {
212  // option, w/ argument?, set directly, set to...
213  {"editor", no_argument, &isEditor, 1},
214  {"fullscreen", no_argument, &isEditor, 0},
215  {"debugwait", no_argument, &Game.DebugWait, 1},
216  {"update", no_argument, &CheckForUpdates, 1},
217  {"noruntimejoin", no_argument, &Config.Network.NoRuntimeJoin, 1},
218  {"runtimejoin", no_argument, &Config.Network.NoRuntimeJoin, 0},
219  {"noleague", no_argument, &Config.Network.LeagueServerSignUp, 0},
220  {"league", no_argument, &Config.Network.LeagueServerSignUp, 1},
221  {"nosignup", no_argument, &Config.Network.MasterServerSignUp, 0},
222  {"signup", no_argument, &Config.Network.MasterServerSignUp, 1},
223 
224  {"debugrecread", required_argument, nullptr, 'K'},
225  {"debugrecwrite", required_argument, nullptr, 'w'},
226 
227  {"client", required_argument, nullptr, 'c'},
228  {"host", no_argument, nullptr, 'h'},
229  {"debughost", required_argument, nullptr, 'H'},
230  {"debugpass", required_argument, nullptr, 'P'},
231  {"debug", required_argument, nullptr, 'D'},
232  {"data", required_argument, nullptr, 'd'},
233  {"startup", required_argument, nullptr, 's'},
234  {"stream", required_argument, nullptr, 'e'},
235  {"recdump", required_argument, nullptr, 'R'},
236  {"comment", required_argument, nullptr, 'm'},
237  {"pass", required_argument, nullptr, 'p'},
238  {"udpport", required_argument, nullptr, 'u'},
239  {"tcpport", required_argument, nullptr, 't'},
240  {"join", required_argument, nullptr, 'j'},
241  {"language", required_argument, nullptr, 'L'},
242  {"scenpar", required_argument, nullptr, 'S'},
243 
244  {"observe", no_argument, nullptr, 'o'},
245  {"nonetwork", no_argument, nullptr, 'N'},
246  {"network", no_argument, nullptr, 'n'},
247  {"record", no_argument, nullptr, 'r'},
248 
249  {"lobby", optional_argument, nullptr, 'l'},
250 
251  {"debug-opengl", no_argument, &Config.Graphics.DebugOpenGL, 1},
252  {"config", required_argument, nullptr, 0},
253  {nullptr, 0, nullptr, 0}
254  };
255  int option_index = 0;
256  c = getopt_long (argc, argv, "abc:d:f:",
257  long_options, &option_index);
258  // no more options
259  if (c == -1)
260  break;
261  switch (c)
262  {
263  case 0:
264  // Signup
265  if (SEqualNoCase(long_options[option_index].name, "signup"))
266  {
267  Game.NetworkActive = true;
268  }
269  // League
270  if (SEqualNoCase(long_options[option_index].name, "league"))
271  {
272  Game.NetworkActive = true;
274  }
275  // Config: Already handled earlier.
276  break;
277  // Lobby
278  case 'l':
279  Game.fLobby = true;
280  // lobby timeout specified? (e.g. --lobby=120)
281  if (optarg)
282  {
283  Game.iLobbyTimeout = atoi(optarg);
284  if (Game.iLobbyTimeout < 0) Game.iLobbyTimeout = 0;
285  }
286  break;
287  case 'o': Game.fObserve = true; break;
288  // Direct join
289  case 'j':
290  Game.NetworkActive = true;
292  break;
293  case 'K':
294  if (optarg && optarg[0])
295  {
296  LogF("Reading from DebugRec file '%s'", optarg);
298  }
299  else
300  Log("Reading DebugRec from CtrlRec file in scenario record");
301  Config.General.DebugRec = 1;
303  break;
304  case 'w':
305  if (optarg && optarg[0])
306  {
307  LogF("Writing to DebugRec file '%s'", optarg);
309  }
310  else
311  Log("Writing DebugRec to CtrlRec file in scenario record");
312  Config.General.DebugRec = 1;
314  break;
315  case 'r': Game.Record = true; break;
316  case 'n': Game.NetworkActive = true; break;
317  case 'N': Game.NetworkActive = false; break;
318  // Language override by parameter
319  case 'L': SCopy(optarg, Config.General.LanguageEx, CFG_MaxString);
320  // port overrides
321  case 't': Config.Network.PortTCP = atoi(optarg); break;
322  case 'u': Config.Network.PortUDP = atoi(optarg); break;
323  // network game password
324  case 'p': Network.SetPassword(optarg); break;
325  // network game comment
326  case 'm': Config.Network.Comment.CopyValidated(optarg); break;
327  // record dump
328  case 'R': Game.RecordDumpFile.Copy(optarg); break;
329  // record stream
330  case 'e': Game.RecordStream.Copy(optarg); break;
331  // startup start screen
332  case 's': C4Startup::SetStartScreen(optarg); break;
333  // additional read-only data path
334  case 'd': Reloc.AddPath(optarg); break;
335  // debug options
336  case 'D': Game.DebugPort = atoi(optarg); break;
337  case 'P': Game.DebugPassword = optarg; break;
338  case 'H': Game.DebugHost = optarg; break;
339  // set custom scenario parameter by command line
340  case 'S':
341  {
342  StdStrBuf sopt, soptval; sopt.Copy(optarg);
343  int32_t val=1;
344  if (sopt.SplitAtChar('=', &soptval)) val=atoi(soptval.getData());
345  Game.StartupScenarioParameters.SetValue(sopt.getData(), val, false);
346  }
347  break;
348  // debug configs
349  case 'h':
350  Game.NetworkActive = true;
351  Game.fLobby = true;
352  Config.Network.PortTCP = 11112;
353  Config.Network.PortUDP = 11113;
355  break;
356  case 'c':
357  Game.NetworkActive = true;
358  SCopy("localhost", Game.DirectJoinAddress, _MAX_PATH);
359  Game.fLobby = true;
360  Config.Network.PortTCP = 11112 + 2*(atoi(optarg)+1);
361  Config.Network.PortUDP = 11113 + 2*(atoi(optarg)+1);
362  break;
363  case '?': /* getopt_long already printed an error message. */ break;
364  default: assert(!"unexpected getopt_long return value");
365  }
366  }
369  if (Game.fObserve || Game.fLobby)
370  Game.NetworkActive = true;
371 
372  while (optind < argc)
373  {
374  char * szParameter = argv[optind++];
375  { // Strip trailing / that result from tab-completing unpacked c4groups
376  int iLen = SLen(szParameter);
377  if (iLen > 5 && szParameter[iLen-1] == '/' && szParameter[iLen-5] == '.' && szParameter[iLen-4] == 'o' && szParameter[iLen-3] == 'c')
378  {
379  szParameter[iLen-1] = '\0';
380  }
381  }
382  // Scenario file
383  if (SEqualNoCase(GetExtension(szParameter),"ocs"))
384  {
385  if(IsGlobalPath(szParameter))
386  Game.SetScenarioFilename(szParameter);
387  else
388  Game.SetScenarioFilename((std::string(GetWorkingDirectory()) + DirSep + szParameter).c_str());
389 
390  continue;
391  }
392  if (SEqualNoCase(GetFilename(szParameter),"scenario.txt"))
393  {
394  Game.SetScenarioFilename(szParameter);
395  continue;
396  }
397  // Player file
398  if (SEqualNoCase(GetExtension(szParameter),"ocp"))
399  {
400  if(IsGlobalPath(szParameter))
401  SAddModule(Game.PlayerFilenames, szParameter);
402  else
403  SAddModule(Game.PlayerFilenames, (std::string(GetWorkingDirectory()) + DirSep + szParameter).c_str());
404 
405  continue;
406  }
407  // Definition file
408  if (SEqualNoCase(GetExtension(szParameter),"ocd"))
409  {
410  SAddModule(Game.DefinitionFilenames,szParameter);
411  continue;
412  }
413  // Key file
414  if (SEqualNoCase(GetExtension(szParameter),"c4k"))
415  {
416  Application.IncomingKeyfile = szParameter;
417  continue;
418  }
419  // Update file
420  if (SEqualNoCase(GetExtension(szParameter),"ocu"))
421  {
422  Application.IncomingUpdate = szParameter;
423  continue;
424  }
425  // record stream
426  if (SEqualNoCase(GetExtension(szParameter),"c4r"))
427  {
428  Game.RecordStream.Copy(szParameter);
429  }
430  // Direct join by URL
431  if (SEqual2NoCase(szParameter, "clonk:"))
432  {
433  // Store address
434  SCopy(szParameter + 6, Game.DirectJoinAddress, _MAX_PATH);
436  // Special case: if the target address is "update" then this is used for update initiation by url
437  if (SEqualNoCase(Game.DirectJoinAddress, "update"))
438  {
440  Game.DirectJoinAddress[0] = 0;
441  continue;
442  }
443  // Self-enable network
444  Game.NetworkActive = true;
445  continue;
446  }
447  }
448 
449 #ifdef _WIN32
450  // Clean up some forward/backward slach confusion since many internal OC file functions cannot handle both
457 #endif
458 
459  // Default to editor if scenario given, player mode otherwise
460  if (isEditor == 2)
462 
463  // record?
465 
466  // startup dialog required?
468 }
469 
471 {
472  // Not changing the resolution always works anyway
473  if (Config.Graphics.ResX == -1 && Config.Graphics.ResY == -1)
474  return;
475  // Enumerate display modes
476  int32_t idx = -1, iXRes, iYRes, iBitDepth, iRefreshRate;
477  int32_t best_match = -1;
478  uint32_t best_delta = ~0;
479  while (GetIndexedDisplayMode(++idx, &iXRes, &iYRes, &iBitDepth, &iRefreshRate, Config.Graphics.Monitor))
480  {
481  if (iBitDepth != C4Draw::COLOR_DEPTH) continue;
482  uint32_t delta = std::abs(Config.Graphics.ResX*Config.Graphics.ResY - iXRes*iYRes);
483  if (!delta && iBitDepth == C4Draw::COLOR_DEPTH && iRefreshRate == Config.Graphics.RefreshRate)
484  return; // Exactly the expected mode
485  if (delta < best_delta)
486  {
487  // Better match than before
488  best_match = idx;
489  best_delta = delta;
490  }
491  }
492  if (best_match != -1)
493  {
494  // Apply next-best mode
495  GetIndexedDisplayMode(best_match, &iXRes, &iYRes, &iBitDepth, &iRefreshRate, Config.Graphics.Monitor);
496  if (iXRes != Config.Graphics.ResX || iYRes != Config.Graphics.ResY)
497  // Don't warn if only bit depth changes
498  // Also, lang table not loaded yet
499  LogF("Warning: The selected resolution %dx%d is not available and has been changed to %dx%d.", Config.Graphics.ResX, Config.Graphics.ResY, iXRes, iYRes);
500  Config.Graphics.ResX = iXRes; Config.Graphics.ResY = iYRes;
501  Config.Graphics.RefreshRate = iRefreshRate;
502  }
503 }
504 
506 {
507  // startup dialog: Only use if no next mission has been provided
508  bool fUseStartupDialog = !Game.HasScenario();
509 
510  // Load graphics early, before we draw anything, since we need shaders
511  // loaded to draw.
512  Game.SetInitProgress(0.0f);
513  Log(LoadResStr("IDS_PRC_GFXRES"));
514  if (!GraphicsResource.Init()) return false;
515  Game.SetInitProgress(fUseStartupDialog ? 10.0f : 1.0f);
516 
517  // Startup message board
518  if (!isEditor)
520  {
522  GraphicsSystem.MessageBoard->Init(cgo,true);
523  }
524 
525  // init loader: Black screen for first start if a video is to be shown; otherwise default spec
526  if (fUseStartupDialog && !isEditor)
527  {
529  { LogFatal(LoadResStr("IDS_PRC_ERRLOADER")); return false; }
530  }
531  Game.SetInitProgress(fUseStartupDialog ? 20.0f : 2.0f);
532 
533  if (!Game.PreInit()) return false;
534 
535  // Music
536  if (!MusicSystem.Init("frontend"))
537  Log(LoadResStr("IDS_PRC_NOMUSIC"));
538 
539  Game.SetInitProgress(fUseStartupDialog ? 34.0f : 2.0f);
540 
541  // Sound
542  if (!SoundSystem.Init())
543  Log(LoadResStr("IDS_PRC_NOSND"));
544 
545  // Play some music! - after sound init because sound system might be needed by music system
546  if (fUseStartupDialog && !isEditor && Config.Sound.FEMusic)
547  MusicSystem.Play();
548 
549  Game.SetInitProgress(fUseStartupDialog ? 35.0f : 3.0f);
550 
551  if (fUseStartupDialog)
552  {
553  AppState = C4AS_Startup;
554  // default record?
556  // if no scenario or direct join has been specified, get game startup parameters by startup dialog
557  if (!isEditor)
559  }
560  // directly launch scenario / network game
561  else
562  {
563  AppState = C4AS_StartGame;
564  }
565 
566  return true;
567 }
568 
569 bool C4Application::ProcessCallback(const char *szMessage, int iProcess)
570 {
571  Console.Out(szMessage);
572  return true;
573 }
574 
576 {
577  Game.Clear();
578  NextMission.clear();
579  // stop timer
580  if (pGameTimer)
581  {
583  delete pGameTimer; pGameTimer = nullptr;
584  }
585  // quit irc
586  IRCClient.Close();
587  // close system group (System.ocg)
588  SystemGroup.Close();
589  // Log
590  if (::Languages.HasStringTable()) // Avoid (double and undefined) message on (second?) shutdown...
591  Log(LoadResStr("IDS_PRC_DEINIT"));
592  // Clear external language packs and string table
593  Languages.Clear();
595  // gamepad clear
596  if (pGamePadControl) { delete pGamePadControl; pGamePadControl=nullptr; }
597  // music system clear
598  MusicSystem.Clear();
599  SoundSystem.Clear();
601  // clear editcursor holding graphics before clearing draw
603  // Clear direct draw (late, because it's needed for e.g. Log)
604  if (pDraw) { delete pDraw; pDraw=nullptr; }
605  // Close window
606  FullScreen.Clear();
607  Console.Clear();
608  // There might be pending saves - do them after the fullscreen windows got closed
609  // so the app just remains as a lingering process until saving is done
611  // The very final stuff
613 }
614 
616 {
617  // Participants should not be cleared for usual startup dialog
618 
619  // Save config if there was no loading error
621  // make sure startup data is unloaded
623  // fonts are loaded at start and never unloaded
625  // quit app
627  AppState = C4AS_Quit;
628 }
629 
630 void C4Application::OpenGame(const char * scenario)
631 {
632  if (AppState == C4AS_Startup)
633  {
634  if (scenario) Game.SetScenarioFilename(scenario);
635  AppState = C4AS_StartGame;
636  }
637  else
638  {
639  SetNextMission(scenario);
640  AppState = C4AS_AfterGame;
641  }
642 
643 }
644 
646 {
647  // reinit desired? Do restart
648  if (!QuitAfterGame || !NextMission.empty())
649  {
650  AppState = C4AS_AfterGame;
651  }
652  else
653  {
654  Quit();
655  }
656 }
657 
659 {
660  // Exec depending on game state
661  switch (AppState)
662  {
663  case C4AS_None:
664  assert(AppState != C4AS_None);
665  break;
666  case C4AS_Quit:
667  // Do nothing, the main loop will exit soon
668  break;
669  case C4AS_PreInit:
670  if (!PreInit()) Quit();
671  break;
672  case C4AS_Startup:
676  // wait for the user to start a game
677  break;
678  case C4AS_StartGame:
679  // immediate progress to next state; OpenGame will enter HandleMessage-loops in startup and lobby!
681  AppState = C4AS_Game;
682 #ifdef WITH_QT_EDITOR
683  // Notify console
685 #endif
686  // first-time game initialization
687  if (!Game.Init())
688  {
689  // set error flag (unless this was a lobby user abort)
691  Game.fQuitWithError = true;
692  // no start: Regular QuitGame; this may reset the engine to startup mode if desired
693  QuitGame();
694  break;
695  }
696  if(Config.Graphics.Windowed == 2 && FullScreenMode())
698  if (!isEditor)
699  pWindow->GrabMouse(true);
700  // Gamepad events have to be polled here so that the controller
701  // connection state is always up-to-date before players are
702  // joining.
704  break;
705  case C4AS_AfterGame:
706  // stop game
707  Game.Clear();
708  if(Config.Graphics.Windowed == 2 && NextMission.empty() && !isEditor)
710  if (!isEditor)
711  pWindow->GrabMouse(false);
712  AppState = C4AS_PreInit;
713  // if a next mission is desired, set to start it
714  if (!NextMission.empty())
715  {
716  Game.SetScenarioFilename(NextMission.c_str());
718  Game.fObserve = false;
719  NextMission.clear();
720  }
721  break;
722  case C4AS_Game:
723  // Game
724  if (Game.IsRunning)
725  Game.Execute();
726  // Sound
729  // Gamepad
731  break;
732  }
733 }
734 
736 {
737  // Graphics
738 
739  // Fullscreen mode
740  if (!isEditor)
742  // Console mode
743  else
744  Console.Execute();
745 }
746 
748 {
749  if (!pGameTimer) return;
750  pGameTimer->SetGameTickDelay(iDelay);
751 }
752 
753 void C4Application::OnResolutionChanged(unsigned int iXRes, unsigned int iYRes)
754 {
755  // notify game
756  if (pDraw)
757  {
758  Game.OnResolutionChanged(iXRes, iYRes);
759  pDraw->OnResolutionChanged(iXRes, iYRes);
760  }
761  if (pWindow)
762  {
763  if (pWindow->pSurface)
764  pWindow->pSurface->UpdateSize(iXRes, iYRes);
765  if (!FullScreenMode())
766  {
767  C4Rect r;
768  pWindow->GetSize(&r);
771  }
772  }
773 }
774 
776 {
777  // re-resolve all keys
780 }
781 
782 bool C4Application::SetGameFont(const char *szFontFace, int32_t iFontSize)
783 {
784 #ifndef USE_CONSOLE
785  // safety
786  if (!szFontFace || !*szFontFace || iFontSize<1 || SLen(szFontFace)>=static_cast<int>(sizeof Config.General.RXFontName)) return false;
787  // first, check if the selected font can be created at all
788  // check regular font only - there's no reason why the other fonts couldn't be created
789  CStdFont TestFont;
790  if (!::FontLoader.InitFont(&TestFont, szFontFace, C4FontLoader::C4FT_Main, iFontSize, &::GraphicsResource.Files))
791  return false;
792  // OK; reinit all fonts
793  StdStrBuf sOldFont; sOldFont.Copy(Config.General.RXFontName);
794  int32_t iOldFontSize = Config.General.RXFontSize;
795  SCopy(szFontFace, Config.General.RXFontName);
796  Config.General.RXFontSize = iFontSize;
798  {
799  // failed :o
800  // shouldn't happen. Better restore config.
801  SCopy(sOldFont.getData(), Config.General.RXFontName);
802  Config.General.RXFontSize = iOldFontSize;
803  return false;
804  }
805 #endif
806  // save changes
807  return true;
808 }
809 
810 void C4Application::OnCommand(const char *szCmd)
811 {
812  if (AppState == C4AS_Game)
814  else if (AppState == C4AS_Startup)
815  {
816  AppState = C4AS_PreInit;
817  Game.SetScenarioFilename(szCmd);
818  }
819 }
820 
822 {
823 #ifdef USE_WIN32_WINDOWS
824  BringWindowToTop(FullScreen.hWindow);
825  ShowWindow(FullScreen.hWindow, SW_SHOW);
826 #endif
827 }
828 
829 void C4Application::SetNextMission(const char *szMissionFilename)
830 {
831  // set next mission if any is desired
832  if (szMissionFilename)
833  {
834  NextMission = szMissionFilename;
835  // scenarios tend to use the wrong slash
836  std::replace(begin(NextMission), end(NextMission), AltDirectorySeparator, DirectorySeparator);
837  }
838  else
839  NextMission.clear();
840 }
841 
843 {
844  if (!pGameTimer) return;
845  pGameTimer->Set();
846 }
847 
849 {
850  if(isEditor)
851  return false;
853  return true;
855  return true;
856  return false;
857 }
858 
859 // *** C4ApplicationGameTimer
860 
863  tLastGameTick(C4TimeMilliseconds::NegativeInfinity)
864 {
865 }
866 
868 {
869  // Remember delay
870  iGameTickDelay = iDelay;
871  // Smaller than minimum refresh delay?
872  if (iDelay < uint32_t(Config.Graphics.MaxRefreshDelay))
873  {
874  // Set critical timer
875  SetDelay(iDelay);
876  // No additional breaking needed
877  iExtraGameTickDelay = 0;
878  }
879  else
880  {
881  // Set critical timer
882  SetDelay(Config.Graphics.MaxRefreshDelay);
883  // Slow down game tick
884  iExtraGameTickDelay = iDelay;
885  }
886 }
887 
888 bool C4ApplicationGameTimer::Execute(int iTimeout, pollfd *)
889 {
890  // Check timer and reset
891  if (!CheckAndReset()) return true;
893  // Execute
894  if (tNow >= tLastGameTick + iExtraGameTickDelay || Game.GameGo)
895  {
896  if (iGameTickDelay)
897  tLastGameTick += iGameTickDelay;
898  else
899  tLastGameTick = tNow;
900 
901  // Compensate if things get too slow
902  if (tNow > tLastGameTick + iGameTickDelay)
903  tLastGameTick += (tNow - tLastGameTick) / 2;
904 
906  }
907  // Draw
908  if (!Game.DoSkipFrame)
909  {
911 
912  Application.Draw();
913 
914  // Automatic frame skip if graphics are slowing down the game (skip max. every 2nd frame)
915  Game.DoSkipFrame = Game.Parameters.AutoFrameSkip && (tPreGfxTime + iGameTickDelay < C4TimeMilliseconds::Now());
916  } else {
917  Game.DoSkipFrame=false;
918  }
919  return true;
920 }
921 
void Execute()
Definition: C4Console.cpp:581
char * GetFilename(char *szPath)
Definition: StdFile.cpp:45
const char * getData() const
Definition: StdBuf.h:442
C4SoundSystem SoundSystem
Definition: C4Application.h:42
int32_t OpenScenarioInGameMode
Definition: C4Config.h:40
C4EditCursor EditCursor
Definition: C4Console.h:90
int32_t RefreshRate
Definition: C4Config.h:105
void SetInitProgress(float fToProgress)
Definition: C4Game.cpp:3383
void Execute(bool force_buffer_checks=false)
void Default()
Definition: C4Config.cpp:283
void ShowGfxErrorDialog()
bool IsRunning
Definition: C4Game.h:139
void SetPassword(const char *szToPassword)
Definition: C4Network2.cpp:771
void OpenGame(const char *scenario=nullptr)
int32_t DebugOpenGL
Definition: C4Config.h:117
int32_t iLobbyTimeout
Definition: C4Game.h:119
char ScenarioFilename[_MAX_PATH+1]
Definition: C4Game.h:102
C4Config Config
Definition: C4Config.cpp:833
void GrabMouse(bool grab)
Definition: C4AppT.cpp:104
bool GetSize(C4Rect *pRect)
Definition: C4AppT.cpp:105
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:152
StdStrBuf RecordDumpFile
Definition: C4Game.h:124
C4Console Console
Definition: C4Globals.cpp:45
bool IsGlobalPath(const char *szPath)
Definition: StdFile.cpp:227
C4Game Game
Definition: C4Globals.cpp:52
void MessageDialog(const char *message)
Definition: C4AppMac.mm:62
bool SplitAtChar(char cSplit, StdStrBuf *psSplit)
Definition: StdBuf.h:619
bool IsLowPriority() override
C4ConfigGeneral General
Definition: C4Config.h:251
void OnResolutionChanged(unsigned int iXRes, unsigned int iYRes) override
static constexpr int COLOR_DEPTH
Definition: C4Draw.h:89
int32_t FEMusic
Definition: C4Config.h:128
bool Execute(int iTimeout, pollfd *) override
bool HasStringTable() const
Definition: C4Language.h:70
void C4Group_SetSortList(const char **ppSortList)
Definition: C4Group.cpp:69
C4Surface * pSurface
Definition: C4Window.h:274
void ClearLanguage()
Definition: C4Language.cpp:410
int32_t Windowed
Definition: C4Config.h:106
bool OpenExtraLogs()
Definition: C4Log.cpp:83
bool SEqualNoCase(const char *szStr1, const char *szStr2, int iLen)
Definition: Standard.cpp:207
static void Unload()
Definition: C4Startup.cpp:301
ValidatedStdCopyStrBuf< C4InVal::VAL_Comment > Comment
Definition: C4Config.h:146
C4FullScreen FullScreen
Definition: C4Globals.cpp:46
bool SetVideoMode(int iXRes, int iYRes, unsigned int iRefreshRate, unsigned int iMonitor, bool fFullScreen)
Definition: C4AppSDL.cpp:354
void SetGameTickDelay(uint32_t iDelay)
StdStrBuf DebugHost
Definition: C4Game.h:148
const char * C4CFN_FLS[]
Definition: C4Group.cpp:32
bool Init(const char *PlayList=nullptr)
static void WaitForSaves()
Definition: StdPNG.cpp:360
bool Execute()
Definition: C4Game.cpp:709
Definition: C4Rect.h:27
int32_t GetScreenWdt()
Definition: C4Gui.h:2821
void CleanupTempUpdateFolder()
Definition: C4Config.cpp:804
char DebugRecExternalFile[_MAX_PATH+1]
Definition: C4Config.h:64
C4MessageInput MessageInput
enum C4Application::State C4AS_None
void OnKeyboardLayoutChanged()
Definition: C4Startup.cpp:348
const char * GetRevision() const
Definition: C4Application.h:72
static bool SetStartScreen(const char *szScreen)
Definition: C4Startup.cpp:320
bool GamepadEnabled
Definition: C4Config.h:58
#define _MAX_PATH
bool IsCorrupted()
Definition: C4Config.h:284
bool DoSkipFrame
Definition: C4Game.h:137
size_t SLen(const char *sptr)
Definition: Standard.h:74
void OnStartGame()
Definition: C4ConsoleGUI.h:114
void Set(C4Surface &rSfc)
Definition: C4Facet.cpp:459
C4GraphicsResource GraphicsResource
StdStrBuf DebugPassword
Definition: C4Game.h:148
C4GameParameters & Parameters
Definition: C4Game.h:67
void Add(StdSchedulerProc *pProc)
bool Close() override
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
#define AltDirectorySeparator
void C4Group_SetProcessCallback(bool(*fnCallback)(const char *, int))
Definition: C4Group.cpp:64
C4ConfigGraphics Graphics
Definition: C4Config.h:253
void Clear() override
Definition: C4Console.cpp:418
int32_t Wdt
Definition: C4Rect.h:30
void SetSize(unsigned int cx, unsigned int cy)
Definition: C4AppT.cpp:110
bool Init()
Definition: C4Game.cpp:328
uint16_t DebugPort
Definition: C4Game.h:148
void Clear() override
C4Network2 Network
Definition: C4Globals.cpp:53
bool UpdateSize(int wdt, int hgt)
Definition: C4Surface.cpp:301
bool Active
Definition: C4App.h:63
void OnCommand(const char *szCmd) override
bool InitLoaderScreen(const char *szLoaderSpec)
char UserDataPath[CFG_MaxString+1]
Definition: C4Config.h:54
C4Language Languages
Definition: C4Language.cpp:42
const char * GetWorkingDirectory()
Definition: StdFile.cpp:603
C4ApplicationGameTimer * pGameTimer
Definition: C4Application.h:87
C4GraphicsSystem GraphicsSystem
Definition: C4Globals.cpp:51
int32_t DefRec
Definition: C4Config.h:47
int32_t MaxRefreshDelay
Definition: C4Config.h:113
std::string IncomingUpdate
Definition: C4Application.h:77
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:519
bool SetGameFont(const char *szFontFace, int32_t iFontSize)
int32_t WindowX
Definition: C4Config.h:104
C4ConfigNetwork Network
Definition: C4Config.h:255
#define CStdMultimediaTimerProc
Definition: StdScheduler.h:216
bool fQuitWithError
Definition: C4Game.h:142
char SystemDataPath[CFG_MaxString+1]
Definition: C4Config.h:55
void Out(const char *message)
Definition: C4Console.cpp:684
bool Close()
Definition: C4Group.cpp:755
C4Draw * pDraw
Definition: C4Draw.cpp:42
void Clear() override
bool Open(C4Group &hGroup, const char *filename) const
Definition: C4Reloc.cpp:82
bool LogFatal(const char *szMessage)
Definition: C4Log.cpp:237
static bool ProcessCallback(const char *szMessage, int iProcess)
char * GetExtension(char *szFilename)
Definition: StdFile.cpp:121
bool NetworkActive
Definition: C4Game.h:122
char LanguageEx[CFG_MaxString+1]
Definition: C4Config.h:37
int32_t GetScreenHgt()
Definition: C4Gui.h:2822
void ParseCommandLine(int argc, char *argv[])
void SetScenarioFilename(const char *)
Definition: C4Game.cpp:528
int ReplaceChar(char cOld, char cNew)
Definition: StdBuf.cpp:336
bool PreInit()
Definition: C4Game.cpp:282
C4Reloc Reloc
Definition: C4Reloc.cpp:21
int GetConfigWidth()
Definition: C4Application.h:82
bool fObserve
Definition: C4Game.h:120
void Init()
Definition: C4Reloc.cpp:23
int32_t LeagueServerSignUp
Definition: C4Config.h:151
virtual void Quit()
Definition: C4AppSDL.cpp:110
int32_t MasterServerSignUp
Definition: C4Config.h:147
static void InitStartup()
Definition: C4Startup.cpp:307
void Quit() override
bool DDrawInit(C4AbstractApp *pApp, unsigned int iXRes, unsigned int iYRes, unsigned int iMonitor)
Definition: C4Draw.cpp:796
void Remove(StdSchedulerProc *pProc)
bool GetIndexedDisplayMode(int32_t iIndex, int32_t *piXRes, int32_t *piYRes, int32_t *piBitDepth, int32_t *piRefreshRate, uint32_t iMonitor)
Definition: C4AppSDL.cpp:335
int32_t Monitor
Definition: C4Config.h:112
virtual bool OnResolutionChanged(unsigned int iXRes, unsigned int iYRes)=0
bool AddPath(const char *path, PathType pathType=PATH_Regular)
Definition: C4Reloc.cpp:60
bool LoadLanguage(const char *strLanguages)
Definition: C4Language.cpp:361
int32_t WindowY
Definition: C4Config.h:104
char RXFontName[CFG_MaxString+1]
Definition: C4Config.h:41
StdCopyStrBuf TempPath
Definition: C4Config.h:53
void OnResolutionChanged(unsigned int iXRes, unsigned int iYRes)
Definition: C4Game.cpp:3404
char PlayerFilenames[20 *_MAX_PATH+1]
Definition: C4Game.h:104
C4FontLoader FontLoader
bool OpenLog()
Definition: C4Log.cpp:48
int SClearFrontBack(char *szString, char cClear)
Definition: Standard.cpp:455
bool HasScenario()
Definition: C4Game.h:162
class C4ScenarioParameters & StartupScenarioParameters
Definition: C4Game.h:68
void SetGameTickDelay(int iDelay)
int32_t RXFontSize
Definition: C4Config.h:42
int32_t ResX
Definition: C4Config.h:103
void RestoreVideoMode()
Definition: C4AppSDL.cpp:443
bool Init()
Definition: C4Language.cpp:55
virtual void Clear()
Definition: C4AppSDL.cpp:105
std::unique_ptr< C4MessageBoard > MessageBoard
#define C4_OS
int32_t ResY
Definition: C4Config.h:103
std::string IncomingKeyfile
Definition: C4Application.h:98
bool Log(const char *szMessage)
Definition: C4Log.cpp:202
bool GameGo
Definition: C4Game.h:135
static C4Startup * Get()
Definition: C4Startup.h:133
bool Record
Definition: C4Game.h:123
int32_t DebugRecWrite
Definition: C4Config.h:62
StdStrBuf RecordStream
Definition: C4Game.h:125
bool SEqual2NoCase(const char *szStr1, const char *szStr2, int iLen)
Definition: Standard.cpp:220
bool Save()
Definition: C4Config.cpp:400
char DefinitionFilenames[20 *_MAX_PATH+1]
Definition: C4Game.h:105
int32_t NoRuntimeJoin
Definition: C4Config.h:142
bool fConfigLoaded
Definition: C4Config.h:262
static void CloseStartup()
Definition: C4Startup.cpp:280
void C4Group_SetTempPath(const char *szPath)
Definition: C4Group.cpp:74
bool Load(const char *szConfigFile=nullptr)
Definition: C4Config.cpp:311
bool DoInit(int argc, char *argv[]) override
StdCopyStrBuf ExePath
Definition: C4Config.h:52
virtual C4Window * Init(C4AbstractApp *app)
Definition: C4Console.cpp:58
int32_t DebugRec
Definition: C4Config.h:60
void ClearCommandLine()
int GetConfigHeight()
Definition: C4Application.h:83
bool Init()
Definition: C4Config.cpp:708
void Clear()
Definition: C4Game.cpp:537
int32_t Hgt
Definition: C4Rect.h:30
char DirectJoinAddress[_MAX_PATH+1]
Definition: C4Game.h:106
void Clear()
Definition: C4Language.cpp:114
#define C4CFN_System
Definition: C4Components.h:29
#define DirSep
void ApplyResolutionConstraints()
C4GamePadControl * pGamePadControl
Definition: C4Application.h:43
bool CloseLog()
Definition: C4Log.cpp:107
C4Window * Init(C4AbstractApp *pApp)
C4ConfigSound Sound
Definition: C4Config.h:254
bool fLobby
Definition: C4Game.h:118
void SetNextMission(const char *szMissionFilename)
#define DirectorySeparator
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:260
void Copy()
Definition: StdBuf.h:467
void OnKeyboardLayoutChanged() override
int32_t PortTCP
Definition: C4Config.h:153
void CopyValidated(const char *szFromVal)
C4StartupGraphics Graphics
Definition: C4Startup.h:100
bool SAddModule(char *szList, const char *szModule, bool fCaseSensitive)
Definition: Standard.cpp:557
C4Window * pWindow
Definition: C4App.h:80
C4Group SystemGroup
Definition: C4Application.h:40
C4Application Application
Definition: C4Globals.cpp:44
static C4TimeMilliseconds Now()
~C4Application() override
C4Network2IRCClient & IRCClient
Definition: C4Application.h:47
#define C4CFN_StartupBackgroundMain
Definition: C4Startup.h:23
void SReplaceChar(char *str, char fc, char tc)
Definition: Standard.cpp:348
void OnKeyboardLayoutChanged()
Definition: C4Game.cpp:3416
bool InitFont(CStdFont *Font, const char *szFontName, FontType eType, int32_t iSize, C4GroupSet *pGfxGroups, bool fDoShadow=true)
int32_t ShowStartupMessages
Definition: C4Config.h:98
int32_t PortUDP
Definition: C4Config.h:153
void SetValue(const char *id, int32_t value, bool only_if_larger)
bool Play(const char *szSongname=nullptr, bool fLoop=false, int fadetime_ms=0, double max_resume_time=0.0, bool allow_break=false)
bool ProcessInput(const char *szText)
int DebugWait
Definition: C4Game.h:148
C4MusicSystem MusicSystem
Definition: C4Application.h:41