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