diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 345 |
1 files changed, 229 insertions, 116 deletions
diff --git a/src/main.cpp b/src/main.cpp index 91ae87e9..54320433 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,48 +19,43 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "main.h" - #include <getopt.h> #include <iostream> #include <physfs.h> +#include <SDL_image.h> #include <unistd.h> #include <vector> -#include <SDL_image.h> #include <guichan/actionlistener.hpp> + #include <guichan/widgets/label.hpp> #include <libxml/parser.h> -#ifdef WIN32 -#include <SDL_syswm.h> -#endif -#ifndef WIN32 -#include <cerrno> -#include <sys/stat.h> -#endif -#if defined __APPLE__ -#include <CoreFoundation/CFBundle.h> -#endif +#include <SDL/SDL_ttf.h> #include "configuration.h" -#include "keyboardconfig.h" -#include "player_relations.h" +#include "emoteshortcut.h" #include "game.h" #include "graphics.h" #include "itemshortcut.h" -#include "lockedarray.h" +#include "keyboardconfig.h" #include "localplayer.h" +#include "lockedarray.h" #include "log.h" #include "logindata.h" +#include "main.h" #ifdef USE_OPENGL #include "openglgraphics.h" #endif +#include "player_relations.h" +#include "serverinfo.h" #include "sound.h" +#include "gui/button.h" #include "gui/char_server.h" #include "gui/char_select.h" +#include "gui/color.h" #include "gui/gui.h" #include "gui/login.h" #include "gui/ok_dialog.h" @@ -68,7 +63,6 @@ #include "gui/register.h" #include "gui/sdlinput.h" #include "gui/setup.h" -#include "gui/textfield.h" #include "gui/updatewindow.h" #include "net/charserverhandler.h" @@ -77,17 +71,35 @@ #include "net/messageout.h" #include "net/network.h" +#include "resources/colordb.h" +#include "resources/emotedb.h" #include "resources/image.h" #include "resources/itemdb.h" #include "resources/monsterdb.h" #include "resources/npcdb.h" #include "resources/resourcemanager.h" -#include "utils/dtor.h" #include "utils/gettext.h" #include "utils/tostring.h" -namespace { +#ifdef __APPLE__ +#include <CoreFoundation/CFBundle.h> +#endif + +#ifdef __MINGW32__ +#include <windows.h> +#define usleep(usec) (Sleep ((usec) / 1000), 0) +#endif + +#ifdef WIN32 +#include <SDL_syswm.h> +#else +#include <cerrno> +#include <sys/stat.h> +#endif + +namespace +{ Window *setupWindow = 0; struct SetupListener : public gcn::ActionListener @@ -123,6 +135,7 @@ CharServerHandler charServerHandler; LoginData loginData; LockedArray<LocalPlayer*> charInfo(MAX_SLOT + 1); +Color *textColor; // This anonymous namespace hides whatever is inside from other modules. namespace { @@ -168,10 +181,13 @@ struct Options */ void setUpdatesDir() { + std::stringstream updates; + // If updatesHost is currently empty, fill it from config file - if (updateHost.empty()) { + if (updateHost.empty()) + { updateHost = - config.getValue("updatehost", "http://updates.themanaworld.org"); + config.getValue("updatehost", "http://updates.themanaworld.org/"); } // Remove any trailing slash at the end of the update host @@ -181,29 +197,59 @@ void setUpdatesDir() // Parse out any "http://" or "ftp://", and set the updates directory size_t pos; pos = updateHost.find("://"); - if (pos != updateHost.npos) { - if (pos + 3 < updateHost.length()) { - updatesDir = - "updates/" + updateHost.substr(pos + 3); - } else { + if (pos != updateHost.npos) + { + if (pos + 3 < updateHost.length()) + { + updates << "updates/" << updateHost.substr(pos + 3) + << "/" << loginData.port; + updatesDir = updates.str(); + } + else + { logger->log("Error: Invalid update host: %s", updateHost.c_str()); - errorMessage = "Invalid update host: " + updateHost; + errorMessage = _("Invalid update host: ") + updateHost; state = ERROR_STATE; } - } else { + } + else + { logger->log("Warning: no protocol was specified for the update host"); - updatesDir = "updates/" + updateHost; + updates << "updates/" << updateHost << "/" << loginData.port; + updatesDir = updates.str(); } ResourceManager *resman = ResourceManager::getInstance(); // Verify that the updates directory exists. Create if necessary. - if (!resman->isDirectory("/" + updatesDir)) { - if (!resman->mkdir("/" + updatesDir)) { + if (!resman->isDirectory("/" + updatesDir)) + { + if (!resman->mkdir("/" + updatesDir)) + { +#if defined WIN32 + std::string newDir = homeDir + "\\" + updatesDir; + std::string::size_type loc = newDir.find("/", 0); + + while (loc != std::string::npos) + { + newDir.replace(loc, 1, "\\"); + loc = newDir.find("/", loc); + } + + if (!CreateDirectory(newDir.c_str(), 0) && + GetLastError() != ERROR_ALREADY_EXISTS) + { + logger->log("Error: %s can't be made, but doesn't exist!", + newDir.c_str()); + errorMessage = _("Error creating updates directory!"); + state = ERROR_STATE; + } +#else logger->log("Error: %s/%s can't be made, but doesn't exist!", - homeDir.c_str(), updatesDir.c_str()); - errorMessage = "Error creating updates directory!"; + homeDir.c_str(), updatesDir.c_str()); + errorMessage = _("Error creating updates directory!"); state = ERROR_STATE; +#endif } } } @@ -231,7 +277,7 @@ void init_engine(const Options &options) #endif { std::cout << homeDir - << " can't be created, but it doesn't exist! Exiting." + << _(" can't be created, but it doesn't exist! Exiting.") << std::endl; exit(1); } @@ -248,7 +294,7 @@ void init_engine(const Options &options) // Initialize SDL logger->log("Initializing SDL..."); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { - std::cerr << "Could not initialize SDL: " << + std::cerr << _("Could not initialize SDL: ") << SDL_GetError() << std::endl; exit(1); } @@ -261,7 +307,7 @@ void init_engine(const Options &options) if (!resman->setWriteDir(homeDir)) { std::cout << homeDir - << " couldn't be set as home directory! Exiting." + << _(" couldn't be set as home directory! Exiting.") << std::endl; exit(1); } @@ -281,18 +327,18 @@ void init_engine(const Options &options) if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX)) { - fprintf(stderr, "Can't find Resources directory\n"); + fprintf(stderr, _("Can't find Resources directory\n")); } CFRelease(resourcesURL); strncat(path, "/data", PATH_MAX - 1); resman->addToSearchPath(path, true); #else - resman->addToSearchPath(TMW_DATADIR "data", true); + resman->addToSearchPath(PKG_DATADIR "data", true); #endif // Fill configuration with defaults logger->log("Initializing configuration..."); - config.setValue("host", "server.themanaworld.org"); + config.setValue("host", "www.themanaworld.org"); config.setValue("port", 6901); config.setValue("hwaccel", 0); #if (defined __APPLE__ || defined WIN32) && defined USE_OPENGL @@ -313,24 +359,24 @@ void init_engine(const Options &options) // Checking if the configuration file exists... otherwise creates it with // default options ! - FILE *tmwFile = 0; + FILE *configFile = 0; std::string configPath = options.configPath; if (configPath.empty()) configPath = homeDir + "/config.xml"; - tmwFile = fopen(configPath.c_str(), "r"); + configFile = fopen(configPath.c_str(), "r"); // If we can't read it, it doesn't exist ! - if (tmwFile == NULL) { + if (configFile == NULL) { // We reopen the file in write mode and we create it - tmwFile = fopen(configPath.c_str(), "wt"); + configFile = fopen(configPath.c_str(), "wt"); } - if (tmwFile == NULL) { + if (configFile == NULL) { std::cout << "Can't create " << configPath << ". " "Using Defaults." << std::endl; } else { - fclose(tmwFile); + fclose(configFile); config.init(configPath); } @@ -344,7 +390,7 @@ void init_engine(const Options &options) SetClassLong(pInfo.window, GCL_HICON, (LONG) icon); } #else - SDL_Surface *icon = IMG_Load(TMW_DATADIR "data/icons/tmw.png"); + SDL_Surface *icon = IMG_Load(PKG_DATADIR "data/icons/tmw.png"); if (icon) { SDL_SetAlpha(icon, SDL_SRCALPHA, SDL_ALPHA_OPAQUE); @@ -365,17 +411,17 @@ void init_engine(const Options &options) graphics = new Graphics(); #endif - int width = (int) config.getValue("screenwidth", defaultScreenWidth); - int height = (int) config.getValue("screenheight", defaultScreenHeight); - int bpp = 0; - bool fullscreen = ((int) config.getValue("screen", 0) == 1); - bool hwaccel = ((int) config.getValue("hwaccel", 0) == 1); + const int width = (int) config.getValue("screenwidth", defaultScreenWidth); + const int height = (int) config.getValue("screenheight", defaultScreenHeight); + const int bpp = 0; + const bool fullscreen = ((int) config.getValue("screen", 0) == 1); + const bool hwaccel = ((int) config.getValue("hwaccel", 0) == 1); // Try to set the desired video mode if (!graphics->setVideoMode(width, height, bpp, fullscreen, hwaccel)) { - std::cerr << "Couldn't set " - << width << "x" << height << "x" << bpp << " video mode: " + std::cerr << _("Couldn't set ") + << width << "x" << height << "x" << bpp << _(" video mode: ") << SDL_GetError() << std::endl; exit(1); } @@ -386,6 +432,9 @@ void init_engine(const Options &options) // Initialize the item shortcuts. itemShortcut = new ItemShortcut(); + // Initialize the emote shortcuts. + emoteShortcut = new EmoteShortcut(); + gui = new Gui(graphics); state = LOGIN_STATE; /**< Initial game state */ @@ -417,6 +466,7 @@ void exit_engine() { // Before config.write() since it writes the shortcuts to the config delete itemShortcut; + delete emoteShortcut; config.write(); @@ -430,6 +480,8 @@ void exit_engine() sound.close(); // Unload XML databases + ColorDB::unload(); + EmoteDB::unload(); ItemDB::unload(); MonsterDB::unload(); NPCDB::unload(); @@ -441,28 +493,28 @@ void exit_engine() void printHelp() { std::cout - << "tmw" << std::endl << std::endl - << "Options: " << std::endl - << " -h --help : Display this help" << std::endl - << " -v --version : Display the version" << std::endl - << " -u --skipupdate : Skip the update process" << std::endl - << " -d --data : Directory to load game data from" << std::endl - << " -U --username : Login with this username" << std::endl - << " -P --password : Login with this password" << std::endl - << " -D --default : Bypass the login process with default settings" << std::endl - << " -p --playername : Login with this player" << std::endl - << " -C --configfile : Configuration file to use" << std::endl - << " -H --updatehost : Use this update host" << std::endl - << " -S --homedir : Directory to use as home directory" << std::endl; + << _("tmw") << std::endl << std::endl + << _("Options: ") << std::endl + << _(" -C --configfile : Configuration file to use") << std::endl + << _(" -d --data : Directory to load game data from") << std::endl + << _(" -D --default : Bypass the login process with default settings") << std::endl + << _(" -h --help : Display this help") << std::endl + << _(" -S --homedir : Directory to use as home directory") << std::endl + << _(" -H --updatehost : Use this update host") << std::endl + << _(" -p --playername : Login with this player") << std::endl + << _(" -P --password : Login with this password") << std::endl + << _(" -u --skipupdate : Skip the update downloads") << std::endl + << _(" -U --username : Login with this username") << std::endl + << _(" -v --version : Display the version") << std::endl; } void printVersion() { #ifdef PACKAGE_VERSION - std::cout << "The Mana World version " << PACKAGE_VERSION << std::endl; + std::cout << _("The Mana World version ") << PACKAGE_VERSION << std::endl; #else - std::cout << "The Mana World version " << - "(local build?, PACKAGE_VERSION is not defined)" << std::endl; + std::cout << _("The Mana World version ") << + _"(local build?, PACKAGE_VERSION is not defined)") << std::endl; #endif } @@ -471,17 +523,17 @@ void parseOptions(int argc, char *argv[], Options &options) const char *optstring = "hvud:U:P:Dp:C:H:S:"; const struct option long_options[] = { - { "help", no_argument, 0, 'h' }, - { "version", no_argument, 0, 'v' }, - { "skipupdate", no_argument, 0, 'u' }, + { "configfile", required_argument, 0, 'C' }, { "data", required_argument, 0, 'd' }, - { "username", required_argument, 0, 'U' }, - { "password", required_argument, 0, 'P' }, { "default", no_argument, 0, 'D' }, { "playername", required_argument, 0, 'p' }, - { "configfile", required_argument, 0, 'C' }, - { "updatehost", required_argument, 0, 'H' }, + { "password", required_argument, 0, 'P' }, + { "help", no_argument, 0, 'h' }, { "homedir", required_argument, 0, 'S' }, + { "updatehost", required_argument, 0, 'H' }, + { "skipupdate", no_argument, 0, 'u' }, + { "username", required_argument, 0, 'U' }, + { "version", no_argument, 0, 'v' }, { 0 } }; @@ -493,36 +545,36 @@ void parseOptions(int argc, char *argv[], Options &options) break; switch (result) { - default: // Unknown option - case 'h': - options.printHelp = true; - break; - case 'v': - options.printVersion = true; - break; - case 'u': - options.skipUpdate = true; + case 'C': + options.configPath = optarg; break; case 'd': options.dataPath = optarg; break; - case 'U': - options.username = optarg; - break; - case 'P': - options.password = optarg; - break; case 'D': options.chooseDefault = true; break; + default: // Unknown option + case 'h': + options.printHelp = true; + break; + case 'H': + options.updateHost = optarg; + break; case 'p': options.playername = optarg; break; - case 'C': - options.configPath = optarg; + case 'P': + options.password = optarg; break; - case 'H': - options.updateHost = optarg; + case 'u': + options.skipUpdate = true; + break; + case 'U': + options.username = optarg; + break; + case 'v': + options.printVersion = true; break; case 'S': homeDir = optarg; @@ -603,6 +655,13 @@ void accountLogin(Network *network, LoginData *loginData) config.setValue("remember", loginData->remember); } +static void positionDialog(Window *dialog, int screenWidth, int screenHeight) +{ + dialog->setPosition( + (screenWidth - dialog->getWidth()) / 2, + (screenHeight - dialog->getHeight()) / 2); +} + void charLogin(Network *network, LoginData *loginData) { logger->log("Trying to connect to char server..."); @@ -706,6 +765,9 @@ int main(int argc, char *argv[]) unsigned int oldstate = !state; // We start with a status change. + // Needs to be created in main, as the updater uses it + textColor = new Color(); + Game *game = NULL; Window *currentDialog = NULL; Image *login_wallpaper = NULL; @@ -716,7 +778,7 @@ int main(int argc, char *argv[]) gcn::Label *versionLabel = new gcn::Label(PACKAGE_VERSION); top->add(versionLabel, 2, 2); #endif - ProgressBar *progressBar = new ProgressBar(0.0f, 100, 20); + ProgressBar *progressBar = new ProgressBar(0.0f, 100, 20, 168, 116, 31); gcn::Label *progressLabel = new gcn::Label(); top->add(progressBar, 5, top->getHeight() - 5 - progressBar->getHeight()); top->add(progressLabel, 15 + progressBar->getWidth(), @@ -738,12 +800,37 @@ int main(int argc, char *argv[]) loginData.password = options.password; } loginData.hostname = config.getValue("host", "server.themanaworld.org"); - loginData.port = (short)config.getValue("port", 0); + loginData.port = (short)config.getValue("port", 6901); loginData.remember = config.getValue("remember", 0); loginData.registerLogin = false; SDLNet_Init(); Network *network = new Network(); + + // Set the most appropriate wallpaper, based on screen width + int screenWidth = (int) config.getValue("screenwidth", defaultScreenWidth); + int screenHeight = static_cast<int>(config.getValue("screenheight", + defaultScreenHeight)); + std::string wallpaperName; + + wallpaperName = "graphics/images/login_wallpaper.png"; + if (screenWidth >= 1024 && screenWidth < 1280) + wallpaperName = "graphics/images/login_wallpaper_1024x768.png"; + else if (screenWidth >= 1280 && screenWidth < 1440) + wallpaperName = "graphics/images/login_wallpaper_1280x960.png"; + else if (screenWidth >= 1440 && screenWidth < 1600) + wallpaperName = "graphics/images/login_wallpaper_1440x1080.png"; + else if (screenWidth >= 1600) + wallpaperName = "graphics/images/login_wallpaper_1600x1200.png"; + + if (!ResourceManager::getInstance()->exists(wallpaperName)) + wallpaperName = "graphics/images/login_wallpaper.png"; + + login_wallpaper = ResourceManager::getInstance()->getImage(wallpaperName); + + if (!login_wallpaper) + logger->log("Couldn't load %s as wallpaper", wallpaperName.c_str()); + while (state != EXIT_STATE) { // Handle SDL events @@ -779,16 +866,6 @@ int main(int argc, char *argv[]) } } - if (!login_wallpaper) - { - login_wallpaper = ResourceManager::getInstance()-> - getImage("graphics/images/login_wallpaper.png"); - if (!login_wallpaper) - { - logger->error("Couldn't load login_wallpaper.png"); - } - } - if (progressBar->isVisible()) { progressBar->setProgress(progressBar->getProgress() + 0.005f); @@ -817,7 +894,7 @@ int main(int argc, char *argv[]) // Reload the wallpaper in case that it was updated login_wallpaper->decRef(); login_wallpaper = ResourceManager::getInstance()-> - getImage("graphics/images/login_wallpaper.png"); + getImage(wallpaperName); break; // Those states don't cause a network disconnect @@ -856,9 +933,12 @@ int main(int argc, char *argv[]) false); // Load XML databases + ColorDB::load(); ItemDB::load(); MonsterDB::load(); NPCDB::load(); + EmoteDB::load(); + state = CHAR_CONNECT_STATE; break; @@ -870,33 +950,50 @@ int main(int argc, char *argv[]) state = ACCOUNT_STATE; } else { currentDialog = new LoginDialog(&loginData); + positionDialog(currentDialog, screenWidth, + screenHeight); } break; case REGISTER_STATE: logger->log("State: REGISTER"); currentDialog = new RegisterDialog(&loginData); + positionDialog(currentDialog, screenWidth, screenHeight); break; case CHAR_SERVER_STATE: logger->log("State: CHAR_SERVER"); + + if (n_server == 1) + { + SERVER_INFO *si = *server_info; + loginData.hostname = iptostring(si->address); + loginData.port = si->port; + loginData.updateHost = si->updateHost; + state = UPDATE_STATE; + } + else { int nextState = (options.skipUpdate) ? LOADDATA_STATE : UPDATE_STATE; currentDialog = new ServerSelectDialog(&loginData, - nextState); - } - if (options.chooseDefault || options.playername != "") { - ((ServerSelectDialog*) currentDialog)->action( - gcn::ActionEvent(NULL, "ok")); + nextState); + positionDialog(currentDialog, screenWidth, + screenHeight); + if (options.chooseDefault + || !options.playername.empty()) + { + ((ServerSelectDialog*) currentDialog)->action( + gcn::ActionEvent(NULL, "ok")); + } } break; - case CHAR_SELECT_STATE: logger->log("State: CHAR_SELECT"); currentDialog = new CharSelectDialog(network, &charInfo, (loginData.sex == 0) ? GENDER_FEMALE : GENDER_MALE); + positionDialog(currentDialog, screenWidth, screenHeight); if (((CharSelectDialog*) currentDialog)-> selectByName(options.playername)) @@ -908,6 +1005,7 @@ int main(int argc, char *argv[]) if (options.chooseDefault) ((CharSelectDialog*) currentDialog)->action( gcn::ActionEvent(NULL, "ok")); + break; case GAME_STATE: @@ -945,13 +1043,21 @@ int main(int argc, char *argv[]) setUpdatesDir(); logger->log("State: UPDATE"); - currentDialog = new UpdaterWindow(updateHost, - homeDir + "/" + updatesDir); + + if (options.skipUpdate) { + state = LOADDATA_STATE; + } else { + currentDialog = new UpdaterWindow(updateHost, + homeDir + "/" + updatesDir); + positionDialog(currentDialog, screenWidth, + screenHeight); + } break; case ERROR_STATE: logger->log("State: ERROR"); currentDialog = new OkDialog(_("Error"), errorMessage); + positionDialog(currentDialog, screenWidth, screenHeight); currentDialog->addActionListener(&errorListener); currentDialog = NULL; // OkDialog deletes itself network->disconnect(); @@ -988,8 +1094,15 @@ int main(int argc, char *argv[]) break; } } + /* + * This loop can really stress the CPU, for no reason since it's + * just constantly redrawing the wallpaper. Added the following + * usleep to limit it to 20 FPS during the login sequence + */ + usleep(50000); } + delete textColor; #ifdef PACKAGE_VERSION delete versionLabel; #endif |