summaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp1574
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();
+ }
+ }
+}