Files
commandergenius/project/jni/application/enigma/src/main.cpp

860 lines
29 KiB
C++
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (C) 2002,2003,2004,2005 Daniel Heck
*
* This program 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; either version 2
* of the License, or (at your option) any later version.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "main.hh"
#include "display.hh"
#include "lua.hh"
#include "gui/MainMenu.hh"
#include "gui/ErrorMenu.hh"
#include "gui/LevelPreviewCache.hh"
#include "options.hh"
#include "oxyd.hh"
#include "sound.hh"
#include "video.hh"
#include "ecl_argp.hh"
#include "ecl_system.hh"
#include "errors.hh"
#include "world.hh"
#include "nls.hh"
#include "LocalToXML.hh"
#include "PreferenceManager.hh"
#include "Utf8ToXML.hh"
#include "XMLtoUtf8.hh"
#include "XMLtoLocal.hh"
#include "lev/RatingManager.hh"
#include "lev/VolatileIndex.hh"
#include "lev/PersistentIndex.hh"
#include "lev/ScoreManager.hh"
#include "enet/enet.h"
#include <locale.h>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/framework/XMLRecognizer.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XercesVersion.hpp>
#include <SDL_image.h>
#include <SDL_mixer.h>
#include <SDL_ttf.h>
#ifdef MACOSX
// for search paths
#include "NSSystemDirectories.h"
#endif
using namespace std;
using namespace ecl;
using namespace enigma;
XERCES_CPP_NAMESPACE_USE
#ifdef WIN32
// LoadImage is a Syscall on Windows, which gets defined to LoadImageA
// or LoadImageW in winuser.h so we simply undefine it to use this
// name for one of the methods
#undef LoadImage
#endif
namespace
{
class Nulbuf : public std::streambuf {};
Nulbuf* nullbuffer = new Nulbuf;
}
/* -------------------- Variables -------------------- */
namespace enigma
{
Application app;
bool noAssert = true; // block expensive assert evaluations by default
bool WizardMode = false;
//! If true, do not ``grab'' the mouse and keyboard
bool Nograb = false;
}
/*! The stream object that is used for logging messages. As defined
here, it is not connected to any file or buffer.
(Note: I think writing to a stream without a streambuffer *should*
be a no-op, but it leads to crashes with g++ 2.95. to circumvent
this, Log is initialized with a dummy streambuf in init(). ) */
std::ostream enigma::Log(0);
/*! This is the stream object that is used when logging to a file. In
this case, enigma::Log uses this object's streambuffer. */
static std::fstream logfile;
/* -------------------- Functions -------------------- */
static void usage()
{
printf("Usage: %s [options] [level files]\n\n"
"Available options :\n\n"
" --nosound Disable music and sound\n"
" --nomusic Disable music\n"
" --window -w Run in a window; do not enter fullscreen mode\n"
" --help -h Show this help\n"
" --version Print the executable's version number\n"
" --nograb Do not use exclusive mouse/keyboard access\n"
" --data -d path Load data from additional directory\n"
" --lang -l lang Set game language\n"
" --pref -p file Use filename or dirname for preferences\n"
"\n",
app.progCallPath.c_str()
);
}
namespace
{
struct AP : public ecl::ArgParser {
public:
// Constructor
AP();
// Variables.
bool nosound, nomusic, show_help, show_version, do_log, do_assert, force_window;
bool dumpinfo, makepreview;
string gamename;
string datapath;
string preffilename;
std::vector<string> levelnames;
private:
enum {
OPT_WINDOW, OPT_GAME, OPT_DATA, OPT_LANG, OPT_PREF
};
// ArgParser interface.
void on_error (ErrorType t, const string &option) {
cout << errormsg(t, option) << endl;
show_help = true;
}
void on_option (int id, const string &param);
void on_argument (const string &arg);
};
}
AP::AP() : ArgParser (app.args.begin(), app.args.end())
{
nosound = nomusic = show_help = show_version = do_log = do_assert = force_window = false;
dumpinfo = makepreview = false;
gamename = "";
datapath = "";
preffilename = PREFFILENAME;
def (&nosound, "nosound");
def (&nomusic, "nomusic");
def (&show_version, "version");
def (&show_help, "help", 'h');
def (&WizardMode, "wizard");
def (&Nograb, "nograb");
def (&do_log, "log");
def (&do_assert, "assert");
def (&dumpinfo, "dumpinfo");
def (&makepreview, "makepreview");
def (&force_window, "window", 'w');
def (OPT_GAME, "game", true);
def (OPT_DATA, "data", 'd', true);
def (OPT_LANG, "lang", 'l', true);
def (OPT_PREF, "pref", 'p', true);
}
void AP::on_option (int id, const string &param)
{
switch (id) {
case OPT_GAME:
gamename = param;
break;
case OPT_DATA:
// we should be able to add several paths -- file.cc has does not yet support this
// if (datapath.empty())
datapath = param;
// else
// datapath = param + ":" + datapath;
break;
case OPT_LANG:
app.argumentLanguage = param;
break;
case OPT_PREF:
preffilename = param;
break;
}
}
void AP::on_argument (const string &arg)
{
levelnames.push_back (arg);
}
/*! Initialize enough of the game to be able to show error messages in
the window, not on the console. */
/* -------------------- Application -------------------- */
Application::Application() : wizard_mode (false), nograb (false), language (""),
defaultLanguage (""), argumentLanguage (""), errorInit (false),
isMakePreviews (false) {
}
void Application::init(int argc, char **argv)
{
progCallPath = argv[0];
copy(argv+1, argv+argc, back_inserter(args));
// parse commandline arguments -- needs args
AP ap;
ap.parse();
// ----- Evaluate command line arguments.
// start with simple actions that do not need further initialization
if (ap.show_help || ap.show_version) {
printf("Enigma %s\n", getVersionInfo().c_str());
if (ap.show_help) usage();
exit(0);
}
//
if (ap.makepreview) {
ap.force_window = true;
ap.nosound = true;
ap.nomusic = true;
isMakePreviews = true;
}
// initialize logfile -- needs ap
if (ap.do_log)
enigma::Log.rdbuf(cout.rdbuf());
else
enigma::Log.rdbuf(::nullbuffer);
// initialize assertion stop flag
if (ap.do_assert)
enigma::noAssert = false;
// initialize system datapaths -- needs ap, log
systemCmdDataPath = ap.datapath;
initSysDatapaths(ap.preffilename);
// initialize XML -- needs log, datapaths
initXerces();
// initialize LUA - Run initialization scripts
lua_State *L = lua::GlobalState();
lua::CheckedDoFile(L, app.systemFS, "startup.lua");
// initialize preferences -- needs LUA, XML
if (!options::Load()) {
fprintf(stderr, _("Error in configuration file.\n"));
fprintf(stderr, lua::LastError (lua::GlobalState()).c_str());
}
prefs = PreferenceManager::instance();
if (ap.force_window) {
options::SetOption("FullScreen", false);
}
if (isMakePreviews) {
options::SetOption("VideoMode", 0);
}
// initialize user data paths -- needs preferences, system datapaths
initUserDatapaths();
// set message language
init_i18n();
// ----- Initialize object repositories
world::Init();
if (ap.dumpinfo) {
world::DumpObjectInfo();
exit(0);
}
// ----- Initialize SDL library
#ifdef WIN32
// SDL_putenv("SDL_VIDEODRIVER=directx"); //needed for SDL 1.2.12 that favors GDI which crashes on SetGamma
#endif
int sdl_flags = SDL_INIT_VIDEO;
#ifdef ANDROID
sdl_flags |= SDL_INIT_JOYSTICK;
#endif
if (enigma::WizardMode)
sdl_flags |= SDL_INIT_NOPARACHUTE;
if (SDL_Init(sdl_flags) < 0) {
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
exit(1);
}
atexit(SDL_Quit);
SDL_EnableUNICODE(1);
const SDL_version* vi = SDL_Linked_Version();
Log << ecl::strf("SDL Version: %u.%u.%u\n", vi->major, vi->minor, vi->patch);
vi = TTF_Linked_Version();
Log << ecl::strf("SDL_ttf Version: %u.%u.%u\n", vi->major, vi->minor, vi->patch);
if(TTF_Init() == -1) {
fprintf(stderr, "Couldn't initialize SDL_ttf: %s\n", TTF_GetError());
exit(1);
}
vi = IMG_Linked_Version();
Log << ecl::strf("SDL_image Version: %u.%u.%u\n", vi->major, vi->minor, vi->patch);
#ifdef SDL_IMG_INIT
int img_flags = IMG_INIT_PNG | IMG_INIT_JPG;
if (IMG_Init(img_flags) & img_flags != img_flags) {
fprintf(stderr, "Couldn't initialize SDL_image: %s\n", IMG_GetError());
exit(1);
}
#endif
// ----- Initialize video subsystem
video::Init();
video::SetCaption ("Enigma v" PACKAGE_VERSION);
video::SetMouseCursor(enigma::LoadImage("cur-magic"), 4, 4);
video::ShowMouse();
SDL_ShowCursor(0);
errorInit = true;
// ----- Initialize sound subsystem
sound::Init(!ap.nomusic, !ap.nosound);
lua::CheckedDoFile (L, app.systemFS, "sound-defaults.lua");
lua::DoSubfolderfile (L, "soundsets", "soundset.lua");
// ----- Initialize network layer
if (enet_initialize () != 0) {
fprintf (stderr, "An error occurred while initializing ENet.\n");
exit (1);
}
// ----- Load models
display::Init();
// initialize application state
state = StateManager::instance();
// ----- Load level packs -- needs state
lev::Index::initGroups();
oxyd::Init(!isMakePreviews); // Load oxyd data files - must be first to create correct proxies
lev::PersistentIndex::registerPersistentIndices(ap.makepreview);
if (!isMakePreviews) {
lua::Dofile(L, "levels/index.lua");
lua::DoSubfolderfile(L, "levels", "index.lua");
lua::Dofile(L, "levels/index_user.lua");
if (!ap.levelnames.empty()) {
lev::Index::registerIndex(new lev::VolatileIndex(INDEX_STARTUP_PACK_NAME,
INDEX_EVERY_GROUP, ap.levelnames, INDEX_STARTUP_PACK_LOCATION));
lev::Index::setCurrentIndex(INDEX_STARTUP_PACK_NAME);
}
#ifndef ANDROID
std::vector<std::string> emptyList;
lev::Index::registerIndex(new lev::VolatileIndex(INDEX_SEARCH_PACK_NAME,
INDEX_DEFAULT_GROUP, emptyList, INDEX_SEARCH_PACK_LOCATION));
#endif
}
lev::Proxy::countLevels();
// ----- Initialize sound tables -- needs sound, oxyd, video (error messages!)
sound::InitSoundSets();
#if MACOSX
updateMac1_00();
#endif
// initialize random
enigma::Randomize();
//
if (isMakePreviews) {
std::set<lev::Proxy *> proxies = lev::Proxy::getProxies();
int size = proxies.size();
std::set<lev::Proxy *>::iterator it;
std::string message = ecl::strf("Make %d previews on system path '%s'",
size, systemAppDataPath.c_str());
Log << message;
Screen *scr = video::GetScreen();
GC gc (scr->get_surface());
Font *f = enigma::GetFont("menufont");
f->render (gc, 80, 240, message.c_str());
set_color(gc, 200,200,200);
hline(gc, 170, 280, 300);
hline(gc, 170, 300, 300);
vline(gc, 170, 280, 20);
vline(gc, 470, 280, 20);
scr->update_all ();
scr->flush_updates();
int i = 0;
for (it = proxies.begin(); it != proxies.end(); it++, i++) {
gui::LevelPreviewCache::makeSystemPreview(*it, systemAppDataPath);
vline(gc, 170 + i*300 / size, 280, 20);
scr->update_all ();
scr->flush_updates();
}
return;
}
// initialize score -- needs random init
lev::ScoreManager::instance();
}
std::string Application::getVersionInfo() {
std::string versionInfo;
double enigmaVersion;
sscanf(PACKAGE_VERSION,"%4lf",&enigmaVersion);
if (enigmaVersion >= ENIGMACOMPATIBITLITY)
versionInfo = "v" PACKAGE_VERSION;
else {
versionInfo = "v" PACKAGE_VERSION
" (development version - v" +
ecl::strf("%.2f",ENIGMACOMPATIBITLITY) + " compatibility branch)";
}
return versionInfo;
}
void Application::initSysDatapaths(const std::string &prefFilename)
{
std::string progDir; // directory path part of args[0]
std::string progName; // filename part of args[0]
bool progDirExists = split_path(progCallPath, &progDir, &progName);
std::string systemPath = SYSTEM_DATA_DIR; // substituted by configure.ac
bool haveHome = (getenv("HOME") != 0);
#ifdef __MINGW32__
// windows standard user specific application data directory path
std::string winAppDataPath = ecl::ApplicationDataPath() + "/Enigma";
#endif
// systemFS
systemFS = new GameFS();
#ifdef __MINGW32__
if (!progDirExists) {
// filename only -- working dir should be on enigma as enigma
// should never be located on exec path on windows
systemAppDataPath = "./data";
} else {
// a call from elsewhere -- absolute or relative path does not matter.
// this enables calls from a commandline.
systemAppDataPath = progDir + "/data";
}
#elif MACOSX
// Mac OS X applications are self-contained bundles,
// i.e., directories like "Enigma.app". Resources are
// placed in those bundles under "Enigma.app/Contents/Resources",
// the main executable would be "Enigma.app/Contents/MacOS/enigma".
// Here, we get the executable name, clip off the last bit, chdir into it,
// then chdir to ../Resources. The original SDL implementation chdirs to
// "../../..", i.e. the directory the bundle is placed in. This breaks
// the self-containedness.
systemAppDataPath = progDir + "/../Resources/data";
#else
// Unix -- we get our data path from the installation
systemAppDataPath = systemPath;
#endif
systemFS->append_dir(systemAppDataPath);
if (!systemCmdDataPath.empty())
systemFS->prepend_dir(systemCmdDataPath);
Log << "systemFS = \"" << systemFS->getDataPath() << "\"\n";
// l10nPath
l10nPath = LOCALEDIR; // defined in src/Makefile.am
#ifdef __MINGW32__
if (progDirExists) {
l10nPath = progDir + "/" + l10nPath;
}
#elif MACOSX
l10nPath = progDir + "/../Resources/locale";
#endif
Log << "l10nPath = \"" << l10nPath << "\"\n";
// prefPath
if (prefFilename.find_first_of(ecl::PathSeparators) != std::string::npos) {
// pref is a path - absolute or home relative
prefPath = ecl::ExpandPath(prefFilename);
if (!ecl::FolderExists(prefPath))
if(!ecl::FolderCreate(prefPath)) {
fprintf(stderr, ("Error cannot create pref directory.\n"));
exit(1);
}
userStdPath = prefPath; // default if pref is a path
prefPath = prefPath + ecl::PathSeparator + "." + PREFFILENAME; // include pref in user data path
} else if (haveHome) {
prefPath = ecl::ExpandPath("~");
if (!ecl::FolderExists(prefPath))
// may happen on Windows
if(!ecl::FolderCreate(prefPath)) {
fprintf(stderr, _("Error Home directory does not exist.\n"));
exit(1);
}
#ifdef MACOSX
userStdPathMac1_00 = prefPath + "/.enigma";
userStdPath = prefPath + "/Library/Application Support/Enigma";
#else
userStdPath = prefPath + "/.enigma";
#endif
prefPath = prefPath + ecl::PathSeparator + "." + prefFilename;
#ifdef __MINGW32__
} else if (!winAppDataPath.empty()) {
if (!ecl::FolderExists(winAppDataPath))
// may happen on Windows
if(!ecl::FolderCreate(winAppDataPath)) {
fprintf(stderr, _("Error Application Data directory does not exist.\n"));
exit(1);
}
Log << "winAppDataPath " << winAppDataPath << "\n";
userStdPath = winAppDataPath;
prefPath = winAppDataPath + ecl::PathSeparator + "." + prefFilename;
#endif
} else {
fprintf(stderr, _("Error Home directory does not exist.\n"));
exit(1);
}
Log << "prefPath = \"" << prefPath << "\"\n";
}
void Application::initXerces() {
// init XML
try {
// Initialize to en_US - we don't know the user prefs yet
// If more than the error messages should be influenced we would
// have to terminate and reinit after reading the user prefs.
XMLPlatformUtils::Initialize();
// Initialize transcoding service for XML <-> utf8
XMLTransService::Codes initResult;
xmlUtf8Transcoder = XMLPlatformUtils::fgTransService->
makeNewTranscoderFor(XMLRecognizer::UTF_8, initResult,
4096); // the block size is irrelevant for utf-8
if (initResult != XMLTransService::Ok) {
fprintf(stderr, _("Error in XML initialization.\n"));
exit(1);
}
static const XMLCh ls[] = { chLatin_L, chLatin_S, chNull };
static const XMLCh core[] = { chLatin_C, chLatin_O, chLatin_R, chLatin_E, chNull };
domImplementationLS = (DOMImplementationLS*)
(DOMImplementationRegistry::getDOMImplementation(ls));
domImplementationCore = (DOMImplementation*)
(DOMImplementationRegistry::getDOMImplementation(core));
domParserErrorHandler = new DOMErrorReporter(&Log);
domParserSchemaResolver = new DOMSchemaResolver();
domSerErrorHandler = new DOMErrorReporter(&Log);
#if _XERCES_VERSION >= 30000
domParser = domImplementationLS->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
DOMConfiguration *config = domParser->getDomConfig();
config->setParameter(XMLUni::fgDOMNamespaces, true);
config->setParameter(XMLUni::fgXercesSchema, true);
config->setParameter(XMLUni::fgXercesSchemaFullChecking, true);
config->setParameter(XMLUni::fgDOMValidate, true);
config->setParameter(XMLUni::fgDOMDatatypeNormalization, true);
config->setParameter(XMLUni::fgDOMErrorHandler, domParserErrorHandler);
config->setParameter(XMLUni::fgDOMResourceResolver, domParserSchemaResolver);
domSer = domImplementationLS->createLSSerializer();
config = domSer->getDomConfig();
config->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);
config->setParameter(XMLUni::fgDOMErrorHandler, domSerErrorHandler);
#else
domParser = domImplementationLS->createDOMBuilder(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
domParser->setFeature(XMLUni::fgDOMNamespaces, true);
domParser->setFeature(XMLUni::fgXercesSchema, true);
domParser->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
domParser->setFeature(XMLUni::fgDOMValidation, true);
domParser->setFeature(XMLUni::fgDOMDatatypeNormalization, true);
domParser->setErrorHandler(domParserErrorHandler);
domParser->setEntityResolver(domParserSchemaResolver);
domSer = domImplementationLS->createDOMWriter();
domSer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
domSer->setErrorHandler(domSerErrorHandler);
#endif
}
catch (...) {
fprintf(stderr, _("Error in XML initialization.\n"));
exit(1);
}
}
void Application::initUserDatapaths() {
// userPath
userPath = prefs->getString("UserPath");
if (userPath.empty()) {
#ifdef MACOSX
if (prefs->getInt("_MacUpdate1.00") != 1)
userPath = userStdPathMac1_00; // empty prefs user path is 1.00 std user path
else {
// first installation of Enigma on a Mac
userPath = userStdPath; // use the new path
prefs->setProperty("UserPath", std::string(XMLtoUtf8(LocalToXML(&userPath).x_str()).c_str()));
prefs->setProperty("UserImagePath", std::string(XMLtoUtf8(LocalToXML(&userPath).x_str()).c_str()));
prefs->setProperty("_MacUpdate1.00", 2);
}
#else
userPath = userStdPath;
#endif
} else {
userPath = XMLtoLocal(Utf8ToXML(userPath.c_str()).x_str()).c_str();
}
Log << "userPath = \"" << userPath << "\"\n";
// userImagePath
userImagePath = prefs->getString("UserImagePath");
if (userImagePath.empty()) {
#ifdef MACOSX
userImagePath = userStdPathMac1_00; // empty prefs user path is 1.00 std user path
#else
userImagePath = userStdPath;
#endif
} else {
userImagePath = XMLtoLocal(Utf8ToXML(userImagePath.c_str()).x_str()).c_str();
}
Log << "userImagePath = \"" << userImagePath << "\"\n";
// resourceFS
resourceFS = new GameFS();
resourceFS->append_dir(systemAppDataPath);
#ifdef MACOSX
// set user-visible data paths -- use it for resource paths
NSSearchPathEnumerationState cur=NSStartSearchPathEnumeration(NSLibraryDirectory, NSAllDomainsMask);
char path[PATH_MAX];
while(cur) {
cur=NSGetNextSearchPathEnumeration(cur, path);
resourceFS->prepend_dir(std::string(path)+"/Application Support/Enigma");
}
#endif
if (!systemCmdDataPath.empty())
resourceFS->prepend_dir(systemCmdDataPath);
resourceFS->prepend_dir(userPath);
if (userImagePath != userPath)
resourceFS->prepend_dir(userImagePath);
Log << "resourceFS = \"" << resourceFS->getDataPath() << "\"\n";
// create levels/auto, levels/cross, levels/legacy_dat on userPath
if (!ecl::FolderExists(userPath + "/levels/auto"))
ecl::FolderCreate (userPath + "/levels/auto");
if (!ecl::FolderExists(userPath + "/levels/cross"))
ecl::FolderCreate (userPath + "/levels/cross");
if (!ecl::FolderExists(userPath + "/levels/legacy_dat"))
ecl::FolderCreate (userPath + "/levels/legacy_dat");
if (!ecl::FolderExists(userPath + "/backup"))
ecl::FolderCreate (userPath + "/backup");
}
#ifdef MACOSX
void Application::updateMac1_00() {
if (prefs->getInt("_MacUpdate1.00") == 0 &&
prefs->getString("UserPath").empty() &&
prefs->getString("UserImagePath").empty()) {
gui::ErrorMenu m(ecl::strf(N_("Mac OS X upgrade from Enigma 1.00\n\nThe default user data path has changed from\n %s \n\nto the visible data path\n %s \n\nIf ok Enigma will move your data to this new location.\nNote that you have to restart Enigma once for completion of this update."), userStdPathMac1_00.c_str(), userStdPath.c_str()),
N_("OK"), N_("Never"), N_("Remind"));
m.manage();
if (m.isRejectQuit()) {
prefs->setProperty("_MacUpdate1.00", 2);
} else if (m.isLaterQuit()) {
prefs->setProperty("_MacUpdate1.00", 0);
} else { // OK move now
Log << "Mac update\n";
// move
std::system(ecl::strf("mkdir '%s' && cd ~/.enigma && tar -cf - * | (cd '%s' && tar -xf -) && cd ~ && rm -rf ~/.enigma", userStdPath.c_str(), userStdPath.c_str()).c_str());
setUserPath("");
setUserImagePath("");
prefs->setProperty("_MacUpdate1.00", 2);
prefs->shutdown();
exit(0);
}
}
}
#endif
void Application::init_i18n()
{
// Initialize the internationalization subsystem
// priorities:
// language: command-line --- user option --- system (environment)
// defaultLanguage: command-line --- system (environment)
app.language = app.argumentLanguage;
app.defaultLanguage = app.argumentLanguage;
if (app.language == "") {
options::GetOption("Language", app.language);
}
if (app.defaultLanguage == "") {
app.defaultLanguage = ecl::SysMessageLocaleName();
if (app.language == "") {
app.language = app.defaultLanguage;
}
}
#if defined(ENABLE_NLS)
nls::SetMessageLocale (app.language);
bindtextdomain (PACKAGE_NAME, app.l10nPath.c_str());
// SDL_ttf does not handle arbitrary encodings, so use UTF-8
bind_textdomain_codeset (PACKAGE_NAME, "utf-8");
textdomain (PACKAGE_NAME);
#endif
}
void Application::setLanguage(std::string newLanguage)
{
if (newLanguage == "") {
language = defaultLanguage;
}
else {
language = newLanguage;
}
nls::SetMessageLocale(language);
}
void Application::setUserPath(std::string newPath) {
std::string prefUserPath = (newPath == userStdPath) ? "" : newPath;
if ((prefUserPath.empty() && userPath != userStdPath) || (!prefUserPath.empty() && prefUserPath != userPath)) {
// set the new userPath - used for saves
if (prefUserPath.empty())
userPath = userStdPath;
else
userPath = prefUserPath;
// load all resources primarily from the new path but keep the old user path
// because the user could not yet copy his user data to the new location
resourceFS->prepend_dir(userPath);
// set the new path as the users preference - the standard path is saved as ""
#ifdef MACOSX
// 1.00 uses "" as "~/.enigma" - we have to store the complete path
if (prefUserPath.empty()) prefUserPath = userStdPath;
#endif
prefs->setProperty("UserPath", std::string(XMLtoUtf8(LocalToXML(&prefUserPath).x_str()).c_str()));
}
}
void Application::setUserImagePath(std::string newPath) {
std::string prefUserImagePath = (newPath == userStdPath) ? "" : newPath;
if ((prefUserImagePath.empty() && userImagePath != userStdPath) || (!prefUserImagePath.empty() && prefUserImagePath != userImagePath)) {
// set the new userImagePath - used for saves
if (prefUserImagePath.empty())
userImagePath = userStdPath;
else
userImagePath = prefUserImagePath;
// load all resources primarily from the new path but keep the old user path
// because the user could not yet copy his user data to the new location
if (userImagePath != userPath)
resourceFS->prepend_dir(userImagePath);
// set the new path as the users preference - the standard path is saved as ""
#ifdef MACOSX
// 1.00 uses "" as "~/.enigma" - we have to store the complete path
if (prefUserImagePath.empty()) prefUserImagePath = userStdPath;
#endif
prefs->setProperty("UserImagePath", std::string(XMLtoUtf8(LocalToXML(&prefUserImagePath).x_str()).c_str()));
}
}
/* -------------------- Functions -------------------- */
void Application::shutdown()
{
oxyd::Shutdown();
world::Shutdown();
display::Shutdown();
if (!isMakePreviews) { // avoid saves on preview generation
lev::RatingManager::instance()->save();
if (lev::PersistentIndex::historyIndex != NULL)
lev::PersistentIndex::historyIndex->save();
lev::ScoreManager::instance()->shutdown();
app.state->shutdown();
app.prefs->shutdown();
}
// now we shutdown SDL - no error reports will be possible!
app.errorInit = false;
video::Shutdown();
sound::Shutdown();
enet_deinitialize();
lua::ShutdownGlobal();
XMLPlatformUtils::Terminate();
#ifdef SDL_IMG_INIT
IMG_Quit();
#endif
ClearFontCache();
TTF_Quit();
ClearImageCache();
delete ::nullbuffer;
}
int main(int argc, char** argv)
{
try {
app.init(argc,argv);
if (!app.isMakePreviews)
gui::ShowMainMenu();
app.shutdown();
return 0;
}
catch (XFrontend &e) {
cerr << "Error: " << e.what() << endl;
std::string message = _("Fatal Error that causes the application to quit:\n\n");
if (app.errorInit) {
gui::ErrorMenu m(message + e.what(), N_("Quit"));
m.manage();
}
}
catch (ecl::XGeneric &e) {
cerr << "Error: " << e.what() << endl;
}
catch (std::exception &e) {
cerr << "Error: " << e.what() << endl;
}
catch (...) {
cerr << "Uncaught exception...\n";
}
return 1;
}