00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pent_include.h"
00020
00021 #include "CoreApp.h"
00022
00023 #include "FileSystem.h"
00024 #include "ConfigFileManager.h"
00025 #include "SettingManager.h"
00026
00027 #include "IDataSource.h"
00028 #include "Args.h"
00029 #include "GameInfo.h"
00030 #include "GameDetector.h"
00031
00032 #if defined(WIN32) && defined(WIN32_USE_MY_DOCUMENTS)
00033 #include <shlobj.h>
00034 #endif
00035
00036 using std::string;
00037
00038 static void ToLower(std::string& str);
00039
00040
00041
00042 DEFINE_RUNTIME_CLASSTYPE_CODE_BASE_CLASS(CoreApp);
00043
00044 CoreApp* CoreApp::application = 0;
00045
00046 CoreApp::CoreApp(int argc_, const char* const* argv_)
00047 : isRunning(false), gameinfo(0), filesystem(0),
00048 configfileman(0), settingman(0), argc(argc_),
00049 argv(argv_), oHelp(false), oQuiet(false), oVQuiet(false)
00050 {
00051 assert(application == 0);
00052 application = this;
00053 }
00054
00055 CoreApp::~CoreApp()
00056 {
00057 std::map<Pentagram::istring, GameInfo*>::iterator i;
00058 for (i = games.begin(); i != games.end(); ++i)
00059 delete i->second;
00060
00061 games.clear();
00062
00063 FORGET_OBJECT(filesystem);
00064 FORGET_OBJECT(settingman);
00065 FORGET_OBJECT(configfileman);
00066 FORGET_OBJECT(gameinfo);
00067
00068 application = 0;
00069 }
00070
00071 void CoreApp::startup()
00072 {
00073 DeclareArgs();
00074
00075 ParseArgs(argc, argv);
00076
00077
00078
00079 if(oHelp) { oQuiet=oVQuiet=true; }
00080 if(oQuiet)
00081 con.setMsgMask(static_cast<MsgMask>(MM_ALL & ~MM_INFO &
00082 ~MM_MINOR_WARN));
00083 if(oVQuiet)
00084 con.setMsgMask(static_cast<MsgMask>(MM_ALL & ~MM_INFO & ~MM_MINOR_WARN
00085 & ~MM_MAJOR_WARN & ~MM_MINOR_ERR));
00086
00087 if (oHelp) {
00088 helpMe();
00089 exit(0);
00090 }
00091
00092
00093 sysInit();
00094
00095 setupVirtualPaths();
00096 loadConfig();
00097 }
00098
00099 void CoreApp::DeclareArgs()
00100 {
00101 parameters.declare("--game", &oGamename, "");
00102 parameters.declare("-h", &oHelp, true);
00103 parameters.declare("--help", &oHelp, true);
00104 parameters.declare("-q", &oQuiet, true);
00105 parameters.declare("-qq", &oVQuiet, true);
00106 }
00107
00108 void CoreApp::sysInit()
00109 {
00110 gameinfo = 0;
00111
00112 filesystem = new FileSystem;
00113
00114 configfileman = new ConfigFileManager();
00115 settingman = new SettingManager();
00116 settingman->setDomainName(SettingManager::DOM_GLOBAL, "pentagram");
00117 settingman->setCurrentDomain(SettingManager::DOM_GLOBAL);
00118
00119 }
00120
00121 void CoreApp::setupVirtualPaths()
00122 {
00123
00124
00125
00126
00127
00128
00129 bool ok;
00130 std::string home;
00131 #ifdef HAVE_HOME
00132 home = getenv("HOME");
00133 home += "/.pentagram";
00134 #elif defined(WIN32) && defined(WIN32_USE_MY_DOCUMENTS)
00135 TCHAR MyDocumentsPath[MAX_PATH];
00136 SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, MyDocumentsPath);
00137 home = MyDocumentsPath;
00138 home += "\\Pentagram";
00139
00140
00141 #elif defined(MACOSX)
00142 home = getenv("HOME");
00143 home += "/Library/Application Support/Pentagram";
00144 #else
00145
00146 home = ".";
00147 #endif
00148 ok = filesystem->AddVirtualPath("@home", home, true);
00149 if (!ok) {
00150 pout << "Error opening default home directory: " << home << std::endl;
00151 } else {
00152 pout << "Default home path: " << home << std::endl;
00153 }
00154
00155 std::string data;
00156 #ifdef DATA_PATH
00157 data = DATA_PATH;
00158 #elif defined(MACOSX)
00159 data = macosxResourcePath();
00160 #else
00161 data = "data";
00162 #endif
00163 ok = filesystem->AddVirtualPath("@data", data);
00164 if (!ok) {
00165 #ifndef BUILTIN_DATA
00166 pout << "Error opening default data directory: " << data << std::endl;
00167 pout << "Trying custom data path specified in configuration file."
00168 << std::endl;
00169 #endif
00170 } else {
00171 pout << "Default data path: " << data << std::endl;
00172 }
00173 }
00174
00175
00176 void CoreApp::loadConfig()
00177 {
00178 pout << "Loading configuration files:" << std::endl;
00179
00180 bool dataconf, homeconf;
00181
00182
00183 dataconf = settingman->readConfigFile("@data/pentagram.ini", true);
00184
00185
00186 homeconf = settingman->readConfigFile("@home/pentagram.ini");
00187
00188 if (!homeconf && !dataconf) {
00189 pout << "No configuration files found." << std::endl;
00190 } else {
00191
00192 if (dataconf)
00193 pout << "@data/pentagram.ini" << std::endl;
00194 if (homeconf)
00195 pout << "@home/pentagram.ini" << std::endl;
00196 }
00197
00198
00199 std::string data;
00200 if (settingman->get("data", data, SettingManager::DOM_GLOBAL)) {
00201 pout << "Setting custom data path: " << data << std::endl;
00202 bool ok = filesystem->AddVirtualPath("@data", data);
00203 if (!ok) {
00204 perr << "Error opening data directory." << std::endl;
00205 }
00206 }
00207 }
00208
00209 void CoreApp::setupGameList()
00210 {
00211 std::vector<Pentagram::istring> gamelist;
00212 gamelist = settingman->listGames();
00213 con.Print(MM_INFO, "Scanning config file for games:\n");
00214 std::vector<Pentagram::istring>::iterator iter;
00215 Pentagram::istring gamename;
00216
00217 for (iter = gamelist.begin(); iter != gamelist.end(); ++iter) {
00218 Pentagram::istring game = *iter;
00219 GameInfo* info = new GameInfo;
00220 bool detected = getGameInfo(game, info);
00221
00222
00223 con.Printf(MM_INFO, "%s: ", game.c_str());
00224 if (detected) {
00225
00226 games[game] = info;
00227
00228 std::string details = info->getPrintDetails();
00229 con.Print(MM_INFO, details.c_str());
00230 } else {
00231 con.Print(MM_INFO, "unknown, skipping");
00232 }
00233 con.Print(MM_INFO, "\n");
00234 }
00235 }
00236
00237 GameInfo* CoreApp::getDefaultGame()
00238 {
00239 Pentagram::istring gamename;
00240
00241 std::string defaultgame;
00242 bool defaultset = settingman->get("defaultgame", defaultgame,
00243 SettingManager::DOM_GLOBAL);
00244
00245 if (oGamename != "") {
00246
00247 gamename = oGamename;
00248 } else if (defaultset) {
00249
00250 gamename = defaultgame;
00251 } else if (games.size() == 2) {
00252
00253 std::map<Pentagram::istring, GameInfo*>::iterator i;
00254 for (i = games.begin(); i != games.end(); ++i) {
00255 if (i->second->name != "pentagram")
00256 gamename = i->second->name;
00257 }
00258 } else if (games.size() == 1) {
00259 perr << "----------------------------------------" << std::endl
00260 << "No games set up in configuration. " << std::endl
00261 << "Please read the README for instructions." << std::endl
00262 << "----------------------------------------" << std::endl;
00263
00264 return 0;
00265 } else {
00266 perr << "Multiple games found in configuration, but no default "
00267 << "game is selected." << std::endl
00268 << "Either start Pentagram with the \"--game <gamename>\","
00269 << std::endl
00270 << "or set pentagram/defaultgame in pentagram.ini"
00271 << std::endl;
00272 return 0;
00273 }
00274
00275 pout << "Default game: " << gamename << std::endl;
00276
00277 GameInfo* info = getGameInfo(gamename);
00278
00279 if (!info) {
00280 perr << "Game \"" << gamename << "\" not found." << std::endl;
00281 }
00282
00283
00284 return info;
00285 }
00286
00287 bool CoreApp::setupGame(GameInfo* info)
00288 {
00289 if (!info) return false;
00290 assert(info->name != "");
00291
00292 gameinfo = info;
00293
00294 if (info->name == "pentagram") return false;
00295
00296 pout << "Selected game: " << info->name << std::endl;
00297 pout << info->getPrintDetails() << std::endl;
00298
00299 setupGamePaths();
00300
00301 return true;
00302 }
00303
00304 void CoreApp::killGame()
00305 {
00306 filesystem->RemoveVirtualPath("@game");
00307 filesystem->RemoveVirtualPath("@work");
00308 filesystem->RemoveVirtualPath("@save");
00309
00310 configfileman->clearRoot("bindings");
00311 configfileman->clearRoot("language");
00312 configfileman->clearRoot("weapons");
00313 configfileman->clearRoot("armour");
00314 configfileman->clearRoot("monsters");
00315 configfileman->clearRoot("game");
00316 settingman->setCurrentDomain(SettingManager::DOM_GLOBAL);
00317
00318 gameinfo = 0;
00319 }
00320
00321
00322 bool CoreApp::getGameInfo(Pentagram::istring& game, GameInfo* gameinfo)
00323 {
00324
00325
00326
00327 gameinfo->name = game;
00328 gameinfo->type = GameInfo::GAME_UNKNOWN;
00329 gameinfo->version = 0;
00330 gameinfo->language = GameInfo::GAMELANG_UNKNOWN;
00331
00332 Pentagram::istring gamekey = "settings/";
00333 gamekey += game;
00334
00335 if (game == "pentagram") {
00336 gameinfo->type = GameInfo::GAME_PENTAGRAM_MENU;
00337 gameinfo->language = GameInfo::GAMELANG_ENGLISH;
00338 }
00339 else {
00340 std::string gametype;
00341 if (!configfileman->get(gamekey+"/type", gametype))
00342 gametype = "unknown";
00343 ToLower(gametype);
00344
00345 if (gametype == "u8") {
00346 gameinfo->type = GameInfo::GAME_U8;
00347 } else if (gametype == "remorse") {
00348 gameinfo->type = GameInfo::GAME_REMORSE;
00349 }
00350 }
00351
00352 std::string version;
00353 if (!configfileman->get(gamekey+"/version", version))
00354 version = "unknown";
00355
00356 std::string language;
00357 if (!configfileman->get(gamekey+"/language", language))
00358 language = "unknown";
00359 ToLower(language);
00360
00361
00363
00364 if (language == "english") {
00365 gameinfo->language = GameInfo::GAMELANG_ENGLISH;
00366 } else if (language == "french") {
00367 gameinfo->language = GameInfo::GAMELANG_FRENCH;
00368 } else if (language == "german") {
00369 gameinfo->language = GameInfo::GAMELANG_GERMAN;
00370 } else if (language == "spanish") {
00371 gameinfo->language = GameInfo::GAMELANG_SPANISH;
00372 } else if (language == "japanese") {
00373 gameinfo->language = GameInfo::GAMELANG_JAPANESE;
00374 }
00375
00376 if (gameinfo->type == GameInfo::GAME_UNKNOWN ||
00377
00378 gameinfo->language == GameInfo::GAMELANG_UNKNOWN)
00379 {
00380 std::string path;
00381 if (!configfileman->get(gamekey+"/path", path)) return false;
00382
00383 return GameDetector::detect(path, gameinfo);
00384 }
00385
00386 if (gameinfo->type == GameInfo::GAME_UNKNOWN) {
00387 return false;
00388 }
00389
00390 return true;
00391 }
00392
00393 void CoreApp::setupGamePaths()
00394 {
00395 assert(gameinfo);
00396 assert(gameinfo->name != "pentagram");
00397 Pentagram::istring game = gameinfo->name;
00398
00399 settingman->setDomainName(SettingManager::DOM_GAME, game);
00400 settingman->setCurrentDomain(SettingManager::DOM_GAME);
00401
00402
00403 std::string gpath;
00404 settingman->get("path", gpath, SettingManager::DOM_GAME);
00405 filesystem->AddVirtualPath("@game", gpath);
00406 con.Printf(MM_INFO, "Game Path: %s\n", gpath.c_str());
00407
00408
00409
00410
00411 std::string work;
00412 if (!settingman->get("work", work, SettingManager::DOM_GAME))
00413 work = "@home/"+game+"-work";
00414
00415 #if 0
00416
00417
00418
00419
00420
00421 filesystem->AddVirtualPath("@work", work, true);
00422 con.Printf(MM_INFO, "U8 Workdir: %s\n", work.c_str());
00423
00424
00425 filesystem->MkDir("@work/usecode");
00426 filesystem->MkDir("@work/usecode/obj");
00427 filesystem->MkDir("@work/usecode/src");
00428 filesystem->MkDir("@work/usecode/asm");
00429 #endif
00430
00431
00432 std::string save;
00433 if (!settingman->get("save", save, SettingManager::DOM_GAME))
00434 save = "@home/"+game+"-save";
00435
00436
00437 filesystem->AddVirtualPath("@save", save, true);
00438 con.Printf(MM_INFO, "Savegame directory: %s\n", save.c_str());
00439 }
00440
00441 void CoreApp::ParseArgs(const int argc, const char * const * const argv)
00442 {
00443 parameters.process(argc, argv);
00444 }
00445
00446 void CoreApp::helpMe()
00447 {
00448 con.Print("\t-h\t\t- quick help menu (this)\n");
00449 con.Print("\t-q\t\t- silence general logging messages\n");
00450 con.Print("\t-qq\t\t- silence general logging messages and\n\t\t\t non-critical warnings/errors\n");
00451 con.Print("\t--game {name}\t- select a game\n");
00452 }
00453
00454 GameInfo* CoreApp::getGameInfo(Pentagram::istring game) const
00455 {
00456 std::map<Pentagram::istring, GameInfo*>::const_iterator i;
00457 i = games.find(game);
00458
00459 if (i != games.end())
00460 return i->second;
00461 else
00462 return 0;
00463 }
00464
00465
00466 static void ToLower(std::string& str)
00467 {
00468 for (unsigned int i = 0; i < str.size(); ++i)
00469 {
00470 #if (defined(BEOS) || defined(OPENBSD) || defined(CYGWIN) || defined(__MORPHOS__))
00471 if ((str[i] >= 'A') && (str[i] <= 'Z')) str[i] += 32;
00472 #else
00473 str[i] = static_cast<char>(std::tolower(str[i]));
00474 #endif
00475 }
00476
00477 }