4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file game_core.cpp Implementation of Game. */
12 #include "../stdafx.h"
13 #include "../core/backup_type.hpp"
14 #include "../company_base.h"
15 #include "../company_func.h"
16 #include "../network/network.h"
17 #include "../window_func.h"
18 #include "../framerate_type.h"
20 #include "game_scanner.hpp"
21 #include "game_config.hpp"
22 #include "game_instance.hpp"
23 #include "game_info.hpp"
25 #include "../safeguards.h"
27 /* static */ uint
Game::frame_counter
= 0;
28 /* static */ GameInfo
*Game::info
= nullptr;
29 /* static */ GameInstance
*Game::instance
= nullptr;
30 /* static */ GameScannerInfo
*Game::scanner_info
= nullptr;
31 /* static */ GameScannerLibrary
*Game::scanner_library
= nullptr;
33 /* static */ void Game::GameLoop()
35 if (_networking
&& !_network_server
) {
36 PerformanceMeasurer::SetInactive(PFE_GAMESCRIPT
);
39 if (Game::instance
== nullptr) {
40 PerformanceMeasurer::SetInactive(PFE_GAMESCRIPT
);
44 PerformanceMeasurer
framerate(PFE_GAMESCRIPT
);
46 Game::frame_counter
++;
48 Backup
<CompanyByte
> cur_company(_current_company
, FILE_LINE
);
49 cur_company
.Change(OWNER_DEITY
);
50 Game::instance
->GameLoop();
51 cur_company
.Restore();
53 /* Occasionally collect garbage */
54 if ((Game::frame_counter
& 255) == 0) {
55 Game::instance
->CollectGarbage();
59 /* static */ void Game::Initialize()
61 if (Game::instance
!= nullptr) Game::Uninitialize(true);
63 Game::frame_counter
= 0;
65 if (Game::scanner_info
== nullptr) {
66 TarScanner::DoScan(TarScanner::GAME
);
67 Game::scanner_info
= new GameScannerInfo();
68 Game::scanner_info
->Initialize();
69 Game::scanner_library
= new GameScannerLibrary();
70 Game::scanner_library
->Initialize();
74 /* static */ void Game::StartNew()
76 if (Game::instance
!= nullptr) return;
78 /* Clients shouldn't start GameScripts */
79 if (_networking
&& !_network_server
) return;
81 GameConfig
*config
= GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME
);
82 GameInfo
*info
= config
->GetInfo();
83 if (info
== nullptr) return;
85 config
->AnchorUnchangeableSettings();
87 Backup
<CompanyByte
> cur_company(_current_company
, FILE_LINE
);
88 cur_company
.Change(OWNER_DEITY
);
91 Game::instance
= new GameInstance();
92 Game::instance
->Initialize(info
);
94 cur_company
.Restore();
96 InvalidateWindowData(WC_AI_DEBUG
, 0, -1);
99 /* static */ void Game::Uninitialize(bool keepConfig
)
101 Backup
<CompanyByte
> cur_company(_current_company
, FILE_LINE
);
103 delete Game::instance
;
104 Game::instance
= nullptr;
105 Game::info
= nullptr;
107 cur_company
.Restore();
112 delete Game::scanner_info
;
113 delete Game::scanner_library
;
114 Game::scanner_info
= nullptr;
115 Game::scanner_library
= nullptr;
117 if (_settings_game
.game_config
!= nullptr) {
118 delete _settings_game
.game_config
;
119 _settings_game
.game_config
= nullptr;
121 if (_settings_newgame
.game_config
!= nullptr) {
122 delete _settings_newgame
.game_config
;
123 _settings_newgame
.game_config
= nullptr;
128 /* static */ void Game::Pause()
130 if (Game::instance
!= nullptr) Game::instance
->Pause();
133 /* static */ void Game::Unpause()
135 if (Game::instance
!= nullptr) Game::instance
->Unpause();
138 /* static */ bool Game::IsPaused()
140 return Game::instance
!= nullptr? Game::instance
->IsPaused() : false;
143 /* static */ void Game::NewEvent(ScriptEvent
*event
)
145 /* AddRef() and Release() need to be called at least once, so do it here */
148 /* Clients should ignore events */
149 if (_networking
&& !_network_server
) {
154 /* Check if Game instance is alive */
155 if (Game::instance
== nullptr) {
160 /* Queue the event */
161 Backup
<CompanyByte
> cur_company(_current_company
, OWNER_DEITY
, FILE_LINE
);
162 Game::instance
->InsertEvent(event
);
163 cur_company
.Restore();
168 /* static */ void Game::ResetConfig()
170 /* Check for both newgame as current game if we can reload the GameInfo inside
171 * the GameConfig. If not, remove the Game from the list. */
172 if (_settings_game
.game_config
!= nullptr && _settings_game
.game_config
->HasScript()) {
173 if (!_settings_game
.game_config
->ResetInfo(true)) {
174 DEBUG(script
, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_game
.game_config
->GetName());
175 _settings_game
.game_config
->Change(nullptr);
176 if (Game::instance
!= nullptr) {
177 delete Game::instance
;
178 Game::instance
= nullptr;
179 Game::info
= nullptr;
181 } else if (Game::instance
!= nullptr) {
182 Game::info
= _settings_game
.game_config
->GetInfo();
185 if (_settings_newgame
.game_config
!= nullptr && _settings_newgame
.game_config
->HasScript()) {
186 if (!_settings_newgame
.game_config
->ResetInfo(false)) {
187 DEBUG(script
, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_newgame
.game_config
->GetName());
188 _settings_newgame
.game_config
->Change(nullptr);
193 /* static */ void Game::Rescan()
195 TarScanner::DoScan(TarScanner::GAME
);
197 Game::scanner_info
->RescanDir();
198 Game::scanner_library
->RescanDir();
201 InvalidateWindowData(WC_AI_LIST
, 0, 1);
202 SetWindowClassesDirty(WC_AI_DEBUG
);
203 InvalidateWindowClassesData(WC_AI_SETTINGS
);
207 /* static */ void Game::Save()
209 if (Game::instance
!= nullptr && (!_networking
|| _network_server
)) {
210 Backup
<CompanyByte
> cur_company(_current_company
, OWNER_DEITY
, FILE_LINE
);
211 Game::instance
->Save();
212 cur_company
.Restore();
214 GameInstance::SaveEmpty();
218 /* static */ void Game::Load(int version
)
220 if (Game::instance
!= nullptr && (!_networking
|| _network_server
)) {
221 Backup
<CompanyByte
> cur_company(_current_company
, OWNER_DEITY
, FILE_LINE
);
222 Game::instance
->Load(version
);
223 cur_company
.Restore();
225 /* Read, but ignore, the load data */
226 GameInstance::LoadEmpty();
230 /* static */ char *Game::GetConsoleList(char *p
, const char *last
, bool newest_only
)
232 return Game::scanner_info
->GetConsoleList(p
, last
, newest_only
);
235 /* static */ char *Game::GetConsoleLibraryList(char *p
, const char *last
)
237 return Game::scanner_library
->GetConsoleList(p
, last
, true);
240 /* static */ const ScriptInfoList
*Game::GetInfoList()
242 return Game::scanner_info
->GetInfoList();
245 /* static */ const ScriptInfoList
*Game::GetUniqueInfoList()
247 return Game::scanner_info
->GetUniqueInfoList();
250 /* static */ GameInfo
*Game::FindInfo(const char *name
, int version
, bool force_exact_match
)
252 return Game::scanner_info
->FindInfo(name
, version
, force_exact_match
);
255 /* static */ GameLibrary
*Game::FindLibrary(const char *library
, int version
)
257 return Game::scanner_library
->FindLibrary(library
, version
);
261 * Check whether we have an Game (library) with the exact characteristics as ci.
262 * @param ci the characteristics to search on (shortname and md5sum)
263 * @param md5sum whether to check the MD5 checksum
264 * @return true iff we have an Game (library) matching.
266 /* static */ bool Game::HasGame(const ContentInfo
*ci
, bool md5sum
)
268 return Game::scanner_info
->HasScript(ci
, md5sum
);
271 /* static */ bool Game::HasGameLibrary(const ContentInfo
*ci
, bool md5sum
)
273 return Game::scanner_library
->HasScript(ci
, md5sum
);
276 /* static */ GameScannerInfo
*Game::GetScannerInfo()
278 return Game::scanner_info
;
280 /* static */ GameScannerLibrary
*Game::GetScannerLibrary()
282 return Game::scanner_library
;