diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 1574 |
1 files changed, 1064 insertions, 510 deletions
diff --git a/src/main.cpp b/src/main.cpp index 39a0fb37..7d623f69 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,26 +1,24 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 2004 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * 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 * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * 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 The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "main.h" - #include <getopt.h> #include <iostream> #include <physfs.h> @@ -33,68 +31,123 @@ #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 "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 "units.h" +#include "gui/button.h" +#ifdef EATHENA_SUPPORT +#include "gui/char_server.h" +#endif #include "gui/char_select.h" -#include "gui/connection.h" +#include "gui/color.h" #include "gui/gui.h" #include "gui/login.h" #include "gui/ok_dialog.h" #include "gui/progressbar.h" -#include "gui/quitdialog.h" #include "gui/register.h" #include "gui/sdlinput.h" +#include "gui/setup.h" +#ifdef TMWSERV_SUPPORT +#include "gui/connection.h" +#include "gui/quitdialog.h" #include "gui/serverdialog.h" -#include "gui/textfield.h" +#endif #include "gui/updatewindow.h" +#ifdef TMWSERV_SUPPORT #include "net/charserverhandler.h" #include "net/connection.h" #include "net/loginhandler.h" -#include "net/logouthandler.h" #include "net/network.h" +#else +#include "net/ea/charserverhandler.h" +#include "net/ea/loginhandler.h" +#include "net/ea/network.h" +#include "net/ea/maploginhandler.h" +#include "net/messageout.h" +#endif +#include "net/logouthandler.h" +#ifdef TMWSERV_SUPPORT #include "net/accountserver/accountserver.h" #include "net/accountserver/account.h" #include "net/chatserver/chatserver.h" #include "net/gameserver/gameserver.h" +#endif +#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" +#ifdef TMWSERV_SUPPORT #include "utils/dtor.h" +#endif #include "utils/gettext.h" -#include "utils/tostring.h" +#include "utils/stringutils.h" +#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 + { + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event); + } listener; +} + +#ifdef TMWSERV_SUPPORT std::string token; //used to store magic_token +#else +// Account infos +char n_server, n_character; + +// TODO Anyone knows a good location for this? Or a way to make it non-global? +class SERVER_INFO; +SERVER_INFO **server_info; +#endif Graphics *graphics; @@ -109,24 +162,34 @@ Configuration branding; /**< XML branding information reader */ Logger *logger; /**< Log object */ KeyboardConfig keyboard; +#ifdef TMWSERV_SUPPORT Net::Connection *gameServerConnection = 0; Net::Connection *chatServerConnection = 0; +Net::Connection *accountServerConnection = 0; +#endif CharServerHandler charServerHandler; LoginData loginData; +#ifdef TMWSERV_SUPPORT LoginHandler loginHandler; LogoutHandler logoutHandler; +#endif LockedArray<LocalPlayer*> charInfo(maxSlot + 1); +Color *textColor; + // This anonymous namespace hides whatever is inside from other modules. namespace { -Net::Connection *accountServerConnection = 0; - std::string homeDir; std::string updateHost; std::string updatesDir; +#ifdef EATHENA_SUPPORT +LoginHandler loginHandler; +MapLoginHandler mapLoginHandler; +#endif + /** * A structure holding the values of various options that can be passed from * the command line. @@ -140,12 +203,14 @@ struct Options printHelp(false), printVersion(false), skipUpdate(false), + chooseDefault(false), serverPort(0) {}; bool printHelp; bool printVersion; bool skipUpdate; + bool chooseDefault; std::string username; std::string password; std::string character; @@ -157,18 +222,19 @@ struct Options short serverPort; }; -} // anonymous namespace - /** * Parse the update host and determine the updates directory * Then verify that the directory exists (creating if needed). */ 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 @@ -178,29 +244,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 = STATE_ERROR; } - } 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 = STATE_ERROR; + } +#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 = STATE_ERROR; +#endif } } } @@ -231,7 +327,7 @@ void initHomeDir() #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); } @@ -247,7 +343,11 @@ void initConfiguration(const Options &options) std::string defaultHost = branding.getValue("defaultServer", "server.themanaworld.org"); config.setValue("host", defaultHost); +#ifdef TWMSERV_SUPPORT int defaultPort = (int)branding.getValue("defaultPort", 9601); +#else + int defaultPort = (int)branding.getValue("defaultPort", 6901); +#endif config.setValue("port", defaultPort); config.setValue("hwaccel", 0); #if (defined __APPLE__ || defined WIN32) && defined USE_OPENGL @@ -270,24 +370,24 @@ void initConfiguration(const Options &options) // Checking if the configuration file exists... otherwise create 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); } } @@ -341,7 +441,7 @@ void initEngine(const Options &options) strncat(path, "/data", PATH_MAX - 1); resman->addToSearchPath(path, true); #else - resman->addToSearchPath(TMW_DATADIR "data", true); + resman->addToSearchPath(PKG_DATADIR "data", true); #endif #ifdef WIN32 @@ -368,23 +468,23 @@ void initEngine(const Options &options) Image::setLoadAsOpenGL(useOpenGL); // Create the graphics context - graphics = useOpenGL ? new OpenGLGraphics() : new Graphics(); + graphics = useOpenGL ? new OpenGLGraphics : new Graphics; #else // Create the graphics context - graphics = new Graphics(); + 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); } @@ -393,10 +493,17 @@ void initEngine(const Options &options) graphics->_beginDraw(); // Initialize the item shortcuts. - itemShortcut = new ItemShortcut(); + itemShortcut = new ItemShortcut; + + // Initialize the emote shortcuts. + emoteShortcut = new EmoteShortcut; gui = new Gui(graphics); +#ifdef TMWSERV_SUPPORT state = STATE_CHOOSE_SERVER; /**< Initial game state */ +#else + state = STATE_LOGIN; /**< Initial game state */ +#endif // Initialize sound engine try { @@ -416,6 +523,9 @@ void initEngine(const Options &options) // Initialize keyboard keyboard.init(); + + // Initialise player relations + player_relations.init(); } /** Clear the engine */ @@ -423,6 +533,7 @@ void exit_engine() { // Before config.write() since it writes the shortcuts to the config delete itemShortcut; + delete emoteShortcut; config.write(); @@ -436,6 +547,8 @@ void exit_engine() sound.close(); // Unload XML databases + ColorDB::unload(); + EmoteDB::unload(); ItemDB::unload(); MonsterDB::unload(); NPCDB::unload(); @@ -445,73 +558,82 @@ void exit_engine() void printHelp() { - std::cout << - "tmw\n\n" - "Options:\n" - " -h --help : Display this help\n" - " -v --version : Display the version\n" - " -u --skipupdate : Skip the update process\n" - " -d --data : Directory to load game data from\n" - " -U --username : Login with this username\n" - " -P --password : Login with this password\n" - " -s --server : Login Server name or IP\n" - " -o --port : Login Server Port\n" - " -c --character : Login with this character\n" - " -C --configfile : Configuration file to use\n" - " -H --updatehost : Use this update host\n"; + std::cout + << _("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 --password : Login with this password") << std::endl + << _(" -c --character : Login with this character") << std::endl + << _(" -o --port : Login Server Port") << std::endl + << _(" -s --server : Login Server name or IP") << 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 } void parseOptions(int argc, char *argv[], Options &options) { - const char *optstring = "hvud:U:P:Dc:s:o:C:H:"; + const char *optstring = "hvud:U:P:Dc:s:o: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' }, + { "default", no_argument, 0, 'D' }, { "password", required_argument, 0, 'P' }, - { "server", required_argument, 0, 's' }, - { "port", required_argument, 0, 'o' }, { "character", required_argument, 0, 'c' }, - { "configfile", required_argument, 0, 'C' }, + { "help", no_argument, 0, 'h' }, + { "homedir", required_argument, 0, 'S' }, { "updatehost", required_argument, 0, 'H' }, + { "port", required_argument, 0, 'o' }, + { "server", required_argument, 0, 's' }, + { "skipupdate", no_argument, 0, 'u' }, + { "username", required_argument, 0, 'U' }, + { "version", no_argument, 0, 'v' }, { 0 } }; while (optind < argc) { + int result = getopt_long(argc, argv, optstring, long_options, NULL); if (result == -1) break; switch (result) { + case 'C': + options.configPath = optarg; + break; + case 'd': + options.dataPath = optarg; + break; + case 'D': + options.chooseDefault = true; + break; default: // Unknown option case 'h': options.printHelp = true; break; - case 'v': - options.printVersion = true; - break; - case 'u': - options.skipUpdate = true; - break; - case 'd': - options.dataPath = optarg; + case 'H': + options.updateHost = optarg; break; - case 'U': - options.username = optarg; + case 'c': + options.character = optarg; break; case 'P': options.password = optarg; @@ -522,14 +644,17 @@ void parseOptions(int argc, char *argv[], Options &options) case 'o': options.serverPort = (short)atoi(optarg); break; - case 'c': - options.character = optarg; + case 'u': + options.skipUpdate = true; break; - case 'C': - options.configPath = optarg; + case 'U': + options.username = optarg; break; - case 'H': - options.updateHost = optarg; + case 'v': + options.printVersion = true; + break; + case 'S': + homeDir = optarg; break; } } @@ -555,17 +680,19 @@ void loadUpdates() } } - -namespace { - struct ErrorListener : public gcn::ActionListener { void action(const gcn::ActionEvent &event) { +#ifdef TMWSERV_SUPPORT state = STATE_CHOOSE_SERVER; +#else + state = loginData.registerLogin ? STATE_REGISTER : STATE_LOGIN; +#endif } } errorListener; +#ifdef TMWSERV_SUPPORT struct AccountListener : public gcn::ActionListener { void action(const gcn::ActionEvent &event) @@ -581,29 +708,65 @@ struct LoginListener : public gcn::ActionListener state = STATE_LOGIN; } } loginListener; - -} // anonymous namespace +#endif // TODO Find some nice place for these functions +#ifdef TMWSERV_SUPPORT void accountLogin(LoginData *loginData) +#else +void accountLogin(Network *network, LoginData *loginData) +#endif { +#ifdef EATHENA_SUPPORT + logger->log("Trying to connect to account server..."); +#endif logger->log("Username is %s", loginData->username.c_str()); - +#ifdef EATHENA_SUPPORT + network->connect(loginData->hostname, loginData->port); + network->registerHandler(&loginHandler); +#endif loginHandler.setLoginData(loginData); +#ifdef TMWSERV_SUPPORT Net::registerHandler(&loginHandler); charServerHandler.setCharInfo(&charInfo); Net::registerHandler(&charServerHandler); +#endif // Send login infos +#ifdef TMWSERV_SUPPORT Net::AccountServer::login(accountServerConnection, 0, // client version loginData->username, loginData->password); +#else + MessageOut outMsg(network); + outMsg.writeInt16(0x0064); + outMsg.writeInt32(0); // client version + outMsg.writeString(loginData->username, 24); + outMsg.writeString(loginData->password, 24); + + /* + * eAthena calls the last byte "client version 2", but it isn't used at + * at all. We're retasking it, with bit 0 to indicate whether the client + * can handle the 0x63 "update host" packet. Clients prior to 0.0.25 send + * 0 here. + */ + outMsg.writeInt8(0x01); +#endif // Clear the password, avoids auto login when returning to login loginData->password = ""; +#ifdef EATHENA_SUPPORT + // Remove _M or _F from username after a login for registration purpose + if (loginData->registerLogin) + { + loginData->username = + loginData->username.substr(0, loginData->username.length() - 2); + } +#endif + // TODO This is not the best place to save the config, but at least better // than the login gui window if (loginData->remember) @@ -614,6 +777,66 @@ void accountLogin(LoginData *loginData) config.setValue("remember", loginData->remember); } +#ifdef EATHENA_SUPPORT + +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..."); + network->connect(loginData->hostname, loginData->port); + network->registerHandler(&charServerHandler); + charServerHandler.setCharInfo(&charInfo); + charServerHandler.setLoginData(loginData); + + // Send login infos + MessageOut outMsg(network); + outMsg.writeInt16(0x0065); + outMsg.writeInt32(loginData->account_ID); + outMsg.writeInt32(loginData->session_ID1); + outMsg.writeInt32(loginData->session_ID2); + // [Fate] The next word is unused by the old char server, so we squeeze in + // tmw client version information + outMsg.writeInt16(CLIENT_PROTOCOL_VERSION); + outMsg.writeInt8(loginData->sex); + + // We get 4 useless bytes before the real answer comes in + network->skip(4); +} + +void mapLogin(Network *network, LoginData *loginData) +{ + logger->log("Memorizing selected character %s", + player_node->getName().c_str()); + config.setValue("lastCharacter", player_node->getName()); + + MessageOut outMsg(network); + + logger->log("Trying to connect to map server..."); + logger->log("Map: %s", map_path.c_str()); + + network->connect(loginData->hostname, loginData->port); + network->registerHandler(&mapLoginHandler); + + // Send login infos + outMsg.writeInt16(0x0072); + outMsg.writeInt32(loginData->account_ID); + outMsg.writeInt32(player_node->mCharId); + outMsg.writeInt32(loginData->session_ID1); + outMsg.writeInt32(loginData->session_ID2); + outMsg.writeInt8(loginData->sex); + + // We get 4 useless bytes before the real answer comes in + network->skip(4); +} + +#else + void accountRegister(LoginData *loginData) { logger->log("Username is %s", loginData->username.c_str()); @@ -748,6 +971,8 @@ void reconnectAccount(const std::string& passToken) Net::AccountServer::reconnectAccount(accountServerConnection, passToken); } +#endif + void xmlNullLogger(void *ctx, const char *msg, ...) { // Does nothing, that's the whole point of it @@ -764,479 +989,785 @@ void initXML() xmlSetGenericErrorFunc(NULL, xmlNullLogger); } +} // namespace + extern "C" char const *_nl_locale_name_default(void); /** Main */ int main(int argc, char *argv[]) { - try + // Parse command line options + Options options; + parseOptions(argc, argv, options); + if (options.printHelp) { - // Parse command line options - Options options; - parseOptions(argc, argv, options); - if (options.printHelp) - { - printHelp(); - return 0; - } - else if (options.printVersion) - { - printVersion(); - return 0; - } + printHelp(); + return 0; + } + else if (options.printVersion) + { + printVersion(); + return 0; + } #if ENABLE_NLS #ifdef WIN32 - putenv(("LANG=" + std::string(_nl_locale_name_default())).c_str()); + putenv(("LANG=" + std::string(_nl_locale_name_default())).c_str()); + // mingw doesn't like LOCALEDIR to be defined for some reason + bindtextdomain("tmw", "translations/"); +#else + bindtextdomain("tmw", LOCALEDIR); #endif - setlocale(LC_MESSAGES, ""); - bindtextdomain("tmw", LOCALEDIR); - bind_textdomain_codeset("tmw", "UTF-8"); - textdomain("tmw"); + setlocale(LC_MESSAGES, ""); + bind_textdomain_codeset("tmw", "UTF-8"); + textdomain("tmw"); #endif - // Initialize PhysicsFS - PHYSFS_init(argv[0]); + // Initialize PhysicsFS + PHYSFS_init(argv[0]); - initXML(); + initXML(); - // load branding information - branding.init("data/branding.xml"); + // load branding information + branding.init("data/branding.xml"); - initHomeDir(); - // Configure logger - logger = new Logger(); - logger->setLogFile(homeDir + std::string("/tmw.log")); - logger->setLogToStandardOut(config.getValue("logToStandardOut", 0)); + initHomeDir(); + // Configure logger + logger = new Logger(); + logger->setLogFile(homeDir + std::string("/tmw.log")); + logger->setLogToStandardOut(config.getValue("logToStandardOut", 0)); - // Log the tmw version + // Log the tmw version #ifdef PACKAGE_VERSION - logger->log("The Mana World v%s", PACKAGE_VERSION); + logger->log("The Mana World v%s", PACKAGE_VERSION); #else - logger->log("The Mana World - version not defined"); + logger->log("The Mana World - version not defined"); #endif - initConfiguration(options); + initConfiguration(options); - initEngine(options); + initEngine(options); - Game *game = NULL; - Window *currentDialog = NULL; - QuitDialog* quitDialog = NULL; - Image *login_wallpaper = NULL; + // Needs to be created in main, as the updater uses it + textColor = new Color; - gcn::Container *top = static_cast<gcn::Container*>(gui->getTop()); -#ifdef PACKAGE_VERSION - gcn::Label *versionLabel = new gcn::Label(PACKAGE_VERSION); - top->add(versionLabel, 25, 2); + Game *game = NULL; + Window *currentDialog = NULL; +#ifdef TMWSERV_SUPPORT + QuitDialog* quitDialog = NULL; #endif + Image *login_wallpaper = NULL; + setupWindow = new Setup; - sound.playMusic(branding.getValue("loginMusic", "")); - - // Server choice - if (options.serverName.empty()) { - loginData.hostname = config.getValue("MostUsedServerName0", + gcn::Container *top = static_cast<gcn::Container*>(gui->getTop()); +#ifdef PACKAGE_VERSION + gcn::Label *versionLabel = new gcn::Label(PACKAGE_VERSION); + top->add(versionLabel, 25, 2); +#endif + 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(), + progressBar->getY() + 4); + progressBar->setVisible(false); + gcn::Button *setup = new Button(_("Setup"), "Setup", &listener); + setup->setPosition(top->getWidth() - setup->getWidth() - 3, 3); + top->add(setup); + + sound.playMusic(branding.getValue("loginMusic", "")); + + // Server choice + if (options.serverName.empty()) { + loginData.hostname = config.getValue("MostUsedServerName0", branding.getValue("defaultServer", "server.themanaworld.org").c_str()); - } - else { - loginData.hostname = options.serverName; - } - if (options.serverPort == 0) { - loginData.port = (short)config.getValue("MostUsedServerPort0", - branding.getValue("defaultPort", 9601)); - } else { - loginData.port = options.serverPort; - } + } + else { + loginData.hostname = options.serverName; + } + if (options.serverPort == 0) { + loginData.port = (short)config.getValue("MostUsedServerPort0", + branding.getValue("defaultPort", 9601)); + } else { + loginData.port = options.serverPort; + } - loginData.username = options.username; - if (loginData.username.empty()) { - if (config.getValue("remember", 0)) { - loginData.username = config.getValue("username", ""); - } - } - if (!options.password.empty()) { - loginData.password = options.password; + loginData.username = options.username; + if (loginData.username.empty()) { + if (config.getValue("remember", 0)) { + loginData.username = config.getValue("username", ""); } + } + if (!options.password.empty()) { + loginData.password = options.password; + } - loginData.remember = config.getValue("remember", 0); - loginData.registerLogin = false; +#ifdef EATHENA_SUPPORT + loginData.hostname = config.getValue("host", "server.themanaworld.org"); + loginData.port = (short)config.getValue("port", 6901); +#endif + loginData.remember = config.getValue("remember", 0); + loginData.registerLogin = false; + +#ifdef TMWSERV_SUPPORT + Net::initialize(); + accountServerConnection = Net::getConnection(); + gameServerConnection = Net::getConnection(); + chatServerConnection = Net::getConnection(); +#else + SDLNet_Init(); + Network *network = new Network; +#endif + + // Set the most appropriate wallpaper, based on screen width + int screenWidth = (int) config.getValue("screenwidth", defaultScreenWidth); +#ifdef EATHENA_SUPPORT + int screenHeight = static_cast<int>(config.getValue("screenheight", + defaultScreenHeight)); +#endif + 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"; - Net::initialize(); - accountServerConnection = Net::getConnection(); - gameServerConnection = Net::getConnection(); - chatServerConnection = Net::getConnection(); + if (!ResourceManager::getInstance()->exists(wallpaperName)) + wallpaperName = "graphics/images/login_wallpaper.png"; - unsigned int oldstate = !state; // We start with a status change. + login_wallpaper = ResourceManager::getInstance()->getImage(wallpaperName); - SDL_Event event; - while (state != STATE_FORCE_QUIT) + if (!login_wallpaper) + logger->log("Couldn't load %s as wallpaper", wallpaperName.c_str()); + + unsigned int oldstate = !state; // We start with a status change. + + SDL_Event event; +#ifdef TMWSERV_SUPPORT + while (state != STATE_FORCE_QUIT) +#else + while (state != STATE_EXIT) +#endif + { + // Handle SDL events + while (SDL_PollEvent(&event)) { - // Handle SDL events - while (SDL_PollEvent(&event)) + switch (event.type) { - switch (event.type) - { - case SDL_QUIT: - state = STATE_FORCE_QUIT; - break; - - case SDL_KEYDOWN: - if (event.key.keysym.sym == SDLK_ESCAPE) + case SDL_QUIT: +#ifdef TMWSERV_SUPPORT + state = STATE_FORCE_QUIT; +#else + state = STATE_EXIT; +#endif + break; + + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_ESCAPE) + { +#ifdef TMWSERV_SUPPORT + if (!quitDialog) { - if (!quitDialog) - { - quitDialog = new QuitDialog(NULL, &quitDialog); - } - else - { - quitDialog->requestMoveToTop(); - } + quitDialog = new QuitDialog(NULL, &quitDialog); } - break; - } - - guiInput->pushInput(event); + else + { + quitDialog->requestMoveToTop(); + } +#else + state = STATE_EXIT; +#endif + } + break; } - Net::flush(); - gui->logic(); + guiInput->pushInput(event); + } - if (!login_wallpaper) - { - std::string wallpaperFile = branding.getValue( - "loginWallpaper", "graphics/images/login_wallpaper.png"); - login_wallpaper = ResourceManager::getInstance()-> - getImage(wallpaperFile); - if (!login_wallpaper) - { - logger->error(wallpaperFile); - } - } +#ifdef TMWSERV_SUPPORT + Net::flush(); +#else + network->flush(); + network->dispatchMessages(); +#endif + gui->logic(); - if (graphics->getWidth() > login_wallpaper->getWidth() || - graphics->getHeight() > login_wallpaper->getHeight()) - { - graphics->setColor(gcn::Color(64, 64, 64)); - graphics->fillRectangle(gcn::Rectangle( - 0, 0, graphics->getWidth(), graphics->getHeight())); - } - graphics->drawImage(login_wallpaper, - (graphics->getWidth() - login_wallpaper->getWidth()) / 2, - (graphics->getHeight() - login_wallpaper->getHeight()) / 2); - gui->draw(); - graphics->updateScreen(); - - // TODO: Add connect timeouts - if (state == STATE_CONNECT_ACCOUNT && - accountServerConnection->isConnected()) - { - if (options.skipUpdate) { - state = STATE_LOADDATA; - } else { - state = STATE_UPDATE; - } - } - else if (state == STATE_CONNECT_GAME && - gameServerConnection->isConnected() && - chatServerConnection->isConnected()) - { - accountServerConnection->disconnect(); - Net::clearHandlers(); +#ifdef EATHENA_SUPPORT + if (network->getState() == Network::NET_ERROR) + { + state = STATE_ERROR; - state = STATE_GAME; + if (!network->getError().empty()) { + errorMessage = network->getError(); + } else { + errorMessage = _("Got disconnected from server!"); } - else if (state == STATE_RECONNECT_ACCOUNT && - accountServerConnection->isConnected()) - { - reconnectAccount(token); - state = STATE_WAIT; + } +#endif + + if (progressBar->isVisible()) + { + progressBar->setProgress(progressBar->getProgress() + 0.005f); + if (progressBar->getProgress() == 1.0f) + progressBar->setProgress(0.0f); + } + + if (graphics->getWidth() > login_wallpaper->getWidth() || + graphics->getHeight() > login_wallpaper->getHeight()) + { + graphics->setColor(gcn::Color(64, 64, 64)); + graphics->fillRectangle(gcn::Rectangle( + 0, 0, graphics->getWidth(), graphics->getHeight())); + } + graphics->drawImage(login_wallpaper, + (graphics->getWidth() - login_wallpaper->getWidth()) / 2, + (graphics->getHeight() - login_wallpaper->getHeight()) / 2); + gui->draw(); + graphics->updateScreen(); + +#ifdef TMWSERV_SUPPORT + // TODO: Add connect timeouts + if (state == STATE_CONNECT_ACCOUNT && + accountServerConnection->isConnected()) + { + if (options.skipUpdate) { + state = STATE_LOADDATA; + } else { + state = STATE_UPDATE; } + } + else if (state == STATE_CONNECT_GAME && + gameServerConnection->isConnected() && + chatServerConnection->isConnected()) + { + accountServerConnection->disconnect(); + Net::clearHandlers(); - if (state != oldstate) { - // Load updates after exiting the update state - if (oldstate == STATE_UPDATE) - { - loadUpdates(); - // Reload the wallpaper in case that it was updated - login_wallpaper->decRef(); - login_wallpaper = ResourceManager::getInstance()->getImage( + state = STATE_GAME; + } + else if (state == STATE_RECONNECT_ACCOUNT && + accountServerConnection->isConnected()) + { + reconnectAccount(token); + state = STATE_WAIT; + } +#endif + +#ifdef TMWSERV_SUPPORT + if (state != oldstate) { + // Load updates after exiting the update state + if (oldstate == STATE_UPDATE) + { + loadUpdates(); + // Reload the wallpaper in case that it was updated + login_wallpaper->decRef(); + login_wallpaper = ResourceManager::getInstance()->getImage( branding.getValue("loginWallpaper", "graphics/images/login_wallpaper.png")); - } - - oldstate = state; - - // Get rid of the dialog of the previous state - if (currentDialog) { - delete currentDialog; - currentDialog = NULL; - } - // State has changed, while the quitDialog was active, it might - // not be correct anymore - if (quitDialog) { - quitDialog->scheduleDelete(); - } - - switch (state) { - case STATE_CHOOSE_SERVER: - logger->log("State: CHOOSE_SERVER"); - - // Allow changing this using a server choice dialog - // We show the dialog box only if the command-line - // options weren't set. - if (options.serverName.empty() && options.serverPort == 0) { - currentDialog = new ServerDialog(&loginData); - } else { - state = STATE_CONNECT_ACCOUNT; - - // Reset options so that cancelling or connect - // timeout will show the server dialog. - options.serverName.clear(); - options.serverPort = 0; - } - break; - - case STATE_CONNECT_ACCOUNT: - logger->log("State: CONNECT_ACCOUNT"); - logger->log("Trying to connect to account server..."); - accountServerConnection->connect(loginData.hostname, - loginData.port); - currentDialog = new ConnectionDialog( - STATE_SWITCH_ACCOUNTSERVER_ATTEMPT); - break; - - case STATE_UPDATE: - // Determine which source to use for the update host - if (!options.updateHost.empty()) - updateHost = options.updateHost; - else - updateHost = loginData.updateHost; + } - setUpdatesDir(); - logger->log("State: UPDATE"); - currentDialog = new UpdaterWindow(updateHost, - homeDir + "/" + updatesDir); - break; - - case STATE_LOGIN: - logger->log("State: LOGIN"); - if (options.username.empty() - || options.password.empty()) { - currentDialog = new LoginDialog(&loginData); - } else { - state = STATE_LOGIN_ATTEMPT; - // Clear the password so that when login fails, the - // dialog will show up next time. - options.password.clear(); - } - break; + oldstate = state; - case STATE_LOADDATA: - logger->log("State: LOADDATA"); + // Get rid of the dialog of the previous state + if (currentDialog) { + delete currentDialog; + currentDialog = NULL; + } + // State has changed, while the quitDialog was active, it might + // not be correct anymore + if (quitDialog) { + quitDialog->scheduleDelete(); + } - // Add customdata directory - ResourceManager::getInstance()->searchAndAddArchives( + switch (state) { + case STATE_CHOOSE_SERVER: + logger->log("State: CHOOSE_SERVER"); + + // Allow changing this using a server choice dialog + // We show the dialog box only if the command-line + // options weren't set. + if (options.serverName.empty() && options.serverPort == 0) { + currentDialog = new ServerDialog(&loginData); + } else { + state = STATE_CONNECT_ACCOUNT; + + // Reset options so that cancelling or connect + // timeout will show the server dialog. + options.serverName.clear(); + options.serverPort = 0; + } + break; + + case STATE_CONNECT_ACCOUNT: + logger->log("State: CONNECT_ACCOUNT"); + logger->log("Trying to connect to account server..."); + accountServerConnection->connect(loginData.hostname, + loginData.port); + currentDialog = new ConnectionDialog( + STATE_SWITCH_ACCOUNTSERVER_ATTEMPT); + break; + + case STATE_UPDATE: + // Determine which source to use for the update host + if (!options.updateHost.empty()) + updateHost = options.updateHost; + else + updateHost = loginData.updateHost; + + setUpdatesDir(); + logger->log("State: UPDATE"); + currentDialog = new UpdaterWindow(updateHost, + homeDir + "/" + updatesDir); + break; + + case STATE_LOGIN: + logger->log("State: LOGIN"); + if (options.username.empty() + || options.password.empty()) { + currentDialog = new LoginDialog(&loginData); + } else { + state = STATE_LOGIN_ATTEMPT; + // Clear the password so that when login fails, the + // dialog will show up next time. + options.password.clear(); + } + break; + + case STATE_LOADDATA: + logger->log("State: LOADDATA"); + + // Add customdata directory + ResourceManager::getInstance()->searchAndAddArchives( "customdata/", "zip", false); - // Load XML databases - ItemDB::load(); - MonsterDB::load(); - NPCDB::load(); - state = STATE_LOGIN; - break; - - case STATE_LOGIN_ATTEMPT: - accountLogin(&loginData); - break; - - case STATE_LOGIN_ERROR: - logger->log("State: LOGIN ERROR"); - currentDialog = new OkDialog("Error ", errorMessage); - currentDialog->addActionListener(&loginListener); - currentDialog = NULL; // OkDialog deletes itself - break; - - case STATE_SWITCH_ACCOUNTSERVER: - logger->log("State: SWITCH_ACCOUNTSERVER"); - - gameServerConnection->disconnect(); - chatServerConnection->disconnect(); - accountServerConnection->disconnect(); - - state = STATE_CHOOSE_SERVER; - break; - - case STATE_SWITCH_ACCOUNTSERVER_ATTEMPT: - logger->log("State: SWITCH_ACCOUNTSERVER_ATTEMPT"); - switchAccountServer(); - - state = STATE_SWITCH_ACCOUNTSERVER; - break; - - case STATE_REGISTER: - logger->log("State: REGISTER"); - currentDialog = new RegisterDialog(&loginData); - break; - - case STATE_REGISTER_ATTEMPT: - accountRegister(&loginData); - break; - - case STATE_CHAR_SELECT: - logger->log("State: CHAR_SELECT"); - currentDialog = - new CharSelectDialog(&charInfo, &loginData); - - if (((CharSelectDialog*) currentDialog)-> - selectByName(options.character)) { - ((CharSelectDialog*) currentDialog)->action( - gcn::ActionEvent(NULL, "ok")); - } else { - ((CharSelectDialog*) currentDialog)->selectByName( - config.getValue("lastCharacter", "")); - } - - break; - - case STATE_CHANGEEMAIL_ATTEMPT: - logger->log("State: CHANGE EMAIL ATTEMPT"); - accountChangeEmail(&loginData); - break; - - case STATE_CHANGEEMAIL: - logger->log("State: CHANGE EMAIL"); - currentDialog = new OkDialog("Email Address change", - "Email Address changed successfully!"); - currentDialog->addActionListener(&accountListener); - currentDialog = NULL; // OkDialog deletes itself - loginData.email = loginData.newEmail; - loginData.newEmail = ""; - break; - - case STATE_CHANGEPASSWORD_ATTEMPT: - logger->log("State: CHANGE PASSWORD ATTEMPT"); - accountChangePassword(&loginData); - break; - - case STATE_CHANGEPASSWORD: - logger->log("State: CHANGE PASSWORD"); - currentDialog = new OkDialog("Password change", - "Password changed successfully!"); - currentDialog->addActionListener(&accountListener); - currentDialog = NULL; // OkDialog deletes itself - loginData.password = loginData.newPassword; - loginData.newPassword = ""; - break; - - case STATE_UNREGISTER_ATTEMPT: - logger->log("State: UNREGISTER ATTEMPT"); - accountUnRegister(&loginData); - break; - - case STATE_UNREGISTER: - logger->log("State: UNREGISTER"); - accountServerConnection->disconnect(); - currentDialog = new OkDialog("Unregister successful", - "Farewell, come back any time ...."); - loginData.clear(); - //The errorlistener sets the state to STATE_CHOOSE_SERVER - currentDialog->addActionListener(&errorListener); - currentDialog = NULL; // OkDialog deletes itself - break; - - case STATE_ACCOUNTCHANGE_ERROR: - logger->log("State: ACCOUNT CHANGE ERROR"); - currentDialog = new OkDialog("Error ", errorMessage); - currentDialog->addActionListener(&accountListener); - currentDialog = NULL; // OkDialog deletes itself - break; - - - case STATE_ERROR: - logger->log("State: ERROR"); - currentDialog = new OkDialog("Error", errorMessage); - currentDialog->addActionListener(&errorListener); - currentDialog = NULL; // OkDialog deletes itself - gameServerConnection->disconnect(); - chatServerConnection->disconnect(); - Net::clearHandlers(); - break; - - case STATE_CONNECT_GAME: - logger->log("State: CONNECT_GAME"); - currentDialog = new ConnectionDialog(STATE_SWITCH_ACCOUNTSERVER_ATTEMPT); - break; - - case STATE_GAME: - logger->log("Memorizing selected character %s", - player_node->getName().c_str()); - config.setValue("lastCharacter", player_node->getName()); - - Net::GameServer::connect(gameServerConnection, token); - Net::ChatServer::connect(chatServerConnection, token); - sound.fadeOutMusic(1000); + // Load XML databases + ColorDB::load(); + ItemDB::load(); + MonsterDB::load(); + NPCDB::load(); + EmoteDB::load(); + Units::loadUnits(); + + state = STATE_LOGIN; + break; + + case STATE_LOGIN_ATTEMPT: + accountLogin(&loginData); + break; + + case STATE_LOGIN_ERROR: + logger->log("State: LOGIN ERROR"); + currentDialog = new OkDialog("Error ", errorMessage); + currentDialog->addActionListener(&loginListener); + currentDialog = NULL; // OkDialog deletes itself + break; + + case STATE_SWITCH_ACCOUNTSERVER: + logger->log("State: SWITCH_ACCOUNTSERVER"); + + gameServerConnection->disconnect(); + chatServerConnection->disconnect(); + accountServerConnection->disconnect(); + + state = STATE_CHOOSE_SERVER; + break; + + case STATE_SWITCH_ACCOUNTSERVER_ATTEMPT: + logger->log("State: SWITCH_ACCOUNTSERVER_ATTEMPT"); + switchAccountServer(); + + state = STATE_SWITCH_ACCOUNTSERVER; + break; + + case STATE_REGISTER: + logger->log("State: REGISTER"); + currentDialog = new RegisterDialog(&loginData); + break; + + case STATE_REGISTER_ATTEMPT: + accountRegister(&loginData); + break; + + case STATE_CHAR_SELECT: + logger->log("State: CHAR_SELECT"); + currentDialog = + new CharSelectDialog(&charInfo, &loginData); + + if (((CharSelectDialog*) currentDialog)-> + selectByName(options.character)) { + ((CharSelectDialog*) currentDialog)->action( + gcn::ActionEvent(NULL, "ok")); + } else { + ((CharSelectDialog*) currentDialog)->selectByName( + config.getValue("lastCharacter", "")); + } + + break; + + case STATE_CHANGEEMAIL_ATTEMPT: + logger->log("State: CHANGE EMAIL ATTEMPT"); + accountChangeEmail(&loginData); + break; + + case STATE_CHANGEEMAIL: + logger->log("State: CHANGE EMAIL"); + currentDialog = new OkDialog("Email Address change", + "Email Address changed successfully!"); + currentDialog->addActionListener(&accountListener); + currentDialog = NULL; // OkDialog deletes itself + loginData.email = loginData.newEmail; + loginData.newEmail = ""; + break; + + case STATE_CHANGEPASSWORD_ATTEMPT: + logger->log("State: CHANGE PASSWORD ATTEMPT"); + accountChangePassword(&loginData); + break; + + case STATE_CHANGEPASSWORD: + logger->log("State: CHANGE PASSWORD"); + currentDialog = new OkDialog("Password change", + "Password changed successfully!"); + currentDialog->addActionListener(&accountListener); + currentDialog = NULL; // OkDialog deletes itself + loginData.password = loginData.newPassword; + loginData.newPassword = ""; + break; + + case STATE_UNREGISTER_ATTEMPT: + logger->log("State: UNREGISTER ATTEMPT"); + accountUnRegister(&loginData); + break; + + case STATE_UNREGISTER: + logger->log("State: UNREGISTER"); + accountServerConnection->disconnect(); + currentDialog = new OkDialog("Unregister successful", + "Farewell, come back any time ...."); + loginData.clear(); + //The errorlistener sets the state to STATE_CHOOSE_SERVER + currentDialog->addActionListener(&errorListener); + currentDialog = NULL; // OkDialog deletes itself + break; + + case STATE_ACCOUNTCHANGE_ERROR: + logger->log("State: ACCOUNT CHANGE ERROR"); + currentDialog = new OkDialog("Error ", errorMessage); + currentDialog->addActionListener(&accountListener); + currentDialog = NULL; // OkDialog deletes itself + break; + + + case STATE_ERROR: + logger->log("State: ERROR"); + currentDialog = new OkDialog("Error", errorMessage); + currentDialog->addActionListener(&errorListener); + currentDialog = NULL; // OkDialog deletes itself + gameServerConnection->disconnect(); + chatServerConnection->disconnect(); + Net::clearHandlers(); + break; + + case STATE_CONNECT_GAME: + logger->log("State: CONNECT_GAME"); + currentDialog = new ConnectionDialog(STATE_SWITCH_ACCOUNTSERVER_ATTEMPT); + break; + + case STATE_GAME: + logger->log("Memorizing selected character %s", + player_node->getName().c_str()); + config.setValue("lastCharacter", player_node->getName()); + + Net::GameServer::connect(gameServerConnection, token); + Net::ChatServer::connect(chatServerConnection, token); + sound.fadeOutMusic(1000); #ifdef PACKAGE_VERSION - delete versionLabel; - versionLabel = NULL; + delete versionLabel; + versionLabel = NULL; #endif - currentDialog = NULL; - - logger->log("State: GAME"); - game = new Game; - game->logic(); - delete game; - - // If the quitdialog didn't set the next state - if (state == STATE_GAME) - { - state = STATE_EXIT; - } - break; + currentDialog = NULL; - case STATE_SWITCH_CHARACTER: - logger->log("State: SWITCH_CHARACTER"); - switchCharacter(&token); - break; + logger->log("State: GAME"); + game = new Game; + game->logic(); + delete game; + + // If the quitdialog didn't set the next state + if (state == STATE_GAME) + { + state = STATE_EXIT; + } + break; + + case STATE_SWITCH_CHARACTER: + logger->log("State: SWITCH_CHARACTER"); + switchCharacter(&token); + break; + + case STATE_RECONNECT_ACCOUNT: + logger->log("State: RECONNECT_ACCOUNT"); + + // Done with game & chat + gameServerConnection->disconnect(); + chatServerConnection->disconnect(); + + accountServerConnection->connect( + loginData.hostname, + loginData.port); + break; + + case STATE_WAIT: + break; + + case STATE_EXIT: + logger->log("State: EXIT"); + logoutThenExit(); + break; + + default: + state = STATE_FORCE_QUIT; + break; + } + } - case STATE_RECONNECT_ACCOUNT: - logger->log("State: RECONNECT_ACCOUNT"); +#else // no TMWSERV_SUPPORT - // Done with game & chat - gameServerConnection->disconnect(); - chatServerConnection->disconnect(); + if (state != oldstate) { + switch (oldstate) + { + case STATE_UPDATE: + loadUpdates(); + // Reload the wallpaper in case that it was updated + login_wallpaper->decRef(); + login_wallpaper = ResourceManager::getInstance()-> + getImage(wallpaperName); + // Load units + Units::loadUnits(); + break; + + // Those states don't cause a network disconnect + case STATE_LOADDATA: + break; + + case STATE_ACCOUNT: + case STATE_CHAR_CONNECT: + case STATE_CONNECTING: + progressBar->setVisible(false); + progressLabel->setCaption(""); + break; + + default: + network->disconnect(); + network->clearHandlers(); + break; + } - accountServerConnection->connect( - loginData.hostname, - loginData.port); - break; + oldstate = state; - case STATE_WAIT: - break; + if (currentDialog && state != STATE_ACCOUNT && + state != STATE_CHAR_CONNECT) { + delete currentDialog; + currentDialog = NULL; + } - case STATE_EXIT: - logger->log("State: EXIT"); - logoutThenExit(); - break; + switch (state) { + case STATE_LOADDATA: + logger->log("State: LOADDATA"); + + // Add customdata directory + ResourceManager::getInstance()->searchAndAddArchives( + "customdata/", + "zip", + false); + + // Load XML databases + ColorDB::load(); + ItemDB::load(); + MonsterDB::load(); + NPCDB::load(); + EmoteDB::load(); + + state = STATE_CHAR_CONNECT; + break; + + case STATE_LOGIN: + logger->log("State: LOGIN"); + + if (!loginData.password.empty()) { + loginData.registerLogin = false; + state = STATE_ACCOUNT; + } else { + currentDialog = new LoginDialog(&loginData); + positionDialog(currentDialog, screenWidth, + screenHeight); + } + break; + + case STATE_REGISTER: + logger->log("State: REGISTER"); + currentDialog = new RegisterDialog(&loginData); + positionDialog(currentDialog, screenWidth, screenHeight); + break; + + case STATE_CHAR_SERVER: + 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 = STATE_UPDATE; + } + else + { + int nextState = (options.skipUpdate) ? + STATE_LOADDATA : STATE_UPDATE; + currentDialog = new ServerSelectDialog(&loginData, + nextState); + positionDialog(currentDialog, screenWidth, + screenHeight); + if (options.chooseDefault + || !options.character.empty()) + { + ((ServerSelectDialog*) currentDialog)->action( + gcn::ActionEvent(NULL, "ok")); + } + } + break; + case STATE_CHAR_SELECT: + 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.character)) + options.chooseDefault = true; + else + ((CharSelectDialog*) currentDialog)->selectByName( + config.getValue("lastCharacter", "")); + + if (options.chooseDefault) + ((CharSelectDialog*) currentDialog)->action( + gcn::ActionEvent(NULL, "ok")); + + break; + + case STATE_GAME: + sound.fadeOutMusic(1000); - default: - state = STATE_FORCE_QUIT; - break; - } +#ifdef PACKAGE_VERSION + delete versionLabel; + versionLabel = NULL; +#endif + delete progressBar; + delete progressLabel; + delete setup; + delete setupWindow; + progressBar = NULL; + progressLabel = NULL; + currentDialog = NULL; + setup = NULL; + setupWindow = NULL; + login_wallpaper->decRef(); + login_wallpaper = NULL; + + logger->log("State: GAME"); + game = new Game(network); + game->logic(); + delete game; + state = STATE_EXIT; + break; + + case STATE_UPDATE: + // Determine which source to use for the update host + if (!options.updateHost.empty()) + updateHost = options.updateHost; + else + updateHost = loginData.updateHost; + + setUpdatesDir(); + logger->log("State: UPDATE"); + + if (options.skipUpdate) { + state = STATE_LOADDATA; + } else { + currentDialog = new UpdaterWindow(updateHost, + homeDir + "/" + updatesDir); + positionDialog(currentDialog, screenWidth, + screenHeight); + } + break; + + case STATE_ERROR: + logger->log("State: ERROR"); + currentDialog = new OkDialog(_("Error"), errorMessage); + positionDialog(currentDialog, screenWidth, screenHeight); + currentDialog->addActionListener(&errorListener); + currentDialog = NULL; // OkDialog deletes itself + network->disconnect(); + network->clearHandlers(); + break; + + case STATE_CONNECTING: + logger->log("State: CONNECTING"); + progressBar->setVisible(true); + progressLabel->setCaption( + _("Connecting to map server...")); + progressLabel->adjustSize(); + mapLogin(network, &loginData); + break; + + case STATE_CHAR_CONNECT: + progressBar->setVisible(true); + progressLabel->setCaption( + _("Connecting to character server...")); + progressLabel->adjustSize(); + charLogin(network, &loginData); + break; + + case STATE_ACCOUNT: + progressBar->setVisible(true); + progressLabel->setCaption( + _("Connecting to account server...")); + progressLabel->adjustSize(); + accountLogin(network, &loginData); + break; + + default: + state = STATE_EXIT; + break; } } +#endif + /* + * 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; + delete versionLabel; #endif - } - catch (...) - { - logger->log("Exception"); - } + delete progressBar; + delete progressLabel; + delete setup; + delete setupWindow; +#ifdef TMWSERV_SUPPORT if (accountServerConnection) accountServerConnection->disconnect(); if (gameServerConnection) @@ -1248,6 +1779,10 @@ int main(int argc, char *argv[]) delete gameServerConnection; delete chatServerConnection; Net::finalize(); +#else + delete network; + SDLNet_Quit(); +#endif logger->log("Quitting"); exit_engine(); @@ -1256,3 +1791,22 @@ int main(int argc, char *argv[]) return 0; } + +void SetupListener::action(const gcn::ActionEvent &event) +{ + Window *window = NULL; + + if (event.getId() == "Setup") + { + window = setupWindow; + } + + if (window) + { + window->setVisible(!window->isVisible()); + if (window->isVisible()) + { + window->requestMoveToTop(); + } + } +} |