diff options
Diffstat (limited to 'src')
55 files changed, 829 insertions, 482 deletions
diff --git a/src/being.cpp b/src/being.cpp index 20225f47..0492727c 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -321,7 +321,15 @@ void Being::takeDamage(Being *attacker, int amount, AttackType type) // Selecting the right color if (type == CRITICAL || type == FLEE) { - color = &userPalette->getColor(UserPalette::HIT_CRITICAL); + if (attacker == player_node) + { + color = &userPalette->getColor( + UserPalette::HIT_LOCAL_PLAYER_CRITICAL); + } + else + { + color = &userPalette->getColor(UserPalette::HIT_CRITICAL); + } } else if (!amount) { @@ -329,7 +337,7 @@ void Being::takeDamage(Being *attacker, int amount, AttackType type) { // This is intended to be the wrong direction to visually // differentiate between hits and misses - color = &userPalette->getColor(UserPalette::HIT_MONSTER_PLAYER); + color = &userPalette->getColor(UserPalette::HIT_LOCAL_PLAYER_MISS); } else { @@ -338,7 +346,16 @@ void Being::takeDamage(Being *attacker, int amount, AttackType type) } else if (getType() == MONSTER) { - color = &userPalette->getColor(UserPalette::HIT_PLAYER_MONSTER); + if (attacker == player_node) + { + color = &userPalette->getColor( + UserPalette::HIT_LOCAL_PLAYER_MONSTER); + } + else + { + color = &userPalette->getColor( + UserPalette::HIT_PLAYER_MONSTER); + } } else { @@ -421,13 +438,15 @@ void Being::setShowName(bool doShowName) void Being::setGuildName(const std::string &name) { - logger->log("Got guild name \"%s\" for being %s(%i)", name.c_str(), mName.c_str(), mId); + logger->log("Got guild name \"%s\" for being %s(%i)", name.c_str(), + mName.c_str(), mId); } void Being::setGuildPos(const std::string &pos) { - logger->log("Got guild position \"%s\" for being %s(%i)", pos.c_str(), mName.c_str(), mId); + logger->log("Got guild position \"%s\" for being %s(%i)", pos.c_str(), + mName.c_str(), mId); } void Being::addGuild(Guild *guild) @@ -530,7 +549,8 @@ void Being::fireMissile(Being *victim, const std::string &particle) if (!victim || particle.empty()) return; - Particle *missile = particleEngine->addEffect(particle, getPixelX(), getPixelY()); + Particle *missile = particleEngine->addEffect(particle, + getPixelX(), getPixelY()); if (missile) { @@ -625,22 +645,20 @@ void Being::setAction(Action action, int attackType) void Being::setDirection(Uint8 direction) { - if (mDirection == direction) - return; + if (Net::getNetworkType() == ServerInfo::MANASERV) + { + if (mDirection == direction) + return; + } mDirection = direction; - // if the direction does not change much, keep the common component - int mFaceDirection = mDirection & direction; - if (!mFaceDirection) - mFaceDirection = direction; - SpriteDirection dir; - if (mFaceDirection & UP) + if (mDirection & UP) dir = DIRECTION_UP; - else if (mFaceDirection & DOWN) + else if (mDirection & DOWN) dir = DIRECTION_DOWN; - else if (mFaceDirection & RIGHT) + else if (mDirection & RIGHT) dir = DIRECTION_RIGHT; else dir = DIRECTION_LEFT; @@ -649,7 +667,7 @@ void Being::setDirection(Uint8 direction) CompoundSprite::setDirection(dir); } -/** TODO: Used by eAthena only */ +/** Note: Used by Tmw-Athena only */ void Being::nextTile() { if (mPath.empty()) @@ -939,7 +957,7 @@ void Being::drawSpeech(int offsetX, int offsetY) } } -/** TODO: eAthena only */ +/** Note: Used by Tmw-Athena only */ int Being::getOffset(char pos, char neg) const { // Check whether we're walking in the requested direction @@ -1012,12 +1030,23 @@ void Being::showName() mDispName = 0; std::string mDisplayName(mName); - if (config.getBoolValue("showgender")) + Being* player = static_cast<Being*>(this); + if (player) { - if (getGender() == GENDER_FEMALE) - mDisplayName += " \u2640"; - else if (getGender() == GENDER_MALE) - mDisplayName += " \u2642"; + if (config.getBoolValue("showgender")) + { + if (getGender() == GENDER_FEMALE) + mDisplayName += " \u2640"; + else if (getGender() == GENDER_MALE) + mDisplayName += " \u2642"; + } + + // Display the IP when under tmw-Athena (GM only). + if (Net::getNetworkType() == ServerInfo::TMWATHENA && player_node + && player_node->getShowIp() && player->getIp()) + { + mDisplayName += strprintf(" %s", ipToString(player->getIp())); + } } if (getType() == MONSTER) diff --git a/src/being.h b/src/being.h index a55e2d3a..0d1816f9 100644 --- a/src/being.h +++ b/src/being.h @@ -490,6 +490,18 @@ class Being : public ActorSprite, public ConfigListener, public Mana::Listener */ void setGM(bool gm); + /** + * Sets the IP or an IP hash. + * The TMW-Athena server sends this information only to GMs. + */ + void setIp(int ip) { mIp = ip; } + + /** + * Returns the player's IP or an IP hash. + * Value is 0 if not set by the server. + */ + int getIp() const { return mIp; } + bool canTalk(); void talkTo(); @@ -585,6 +597,8 @@ class Being : public ActorSprite, public ConfigListener, public Mana::Listener int mX, mY; /**< Position in tile */ int mDamageTaken; + + int mIp; }; #endif diff --git a/src/client.cpp b/src/client.cpp index ae9af8de..66a1f28c 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -201,6 +201,7 @@ Client *Client::mInstance = 0; Client::Client(const Options &options): mOptions(options), + mRootDir(""), mCurrentDialog(0), mQuitDialog(0), mDesktop(0), @@ -224,6 +225,7 @@ Client::Client(const Options &options): branding.setDefaultValues(getBrandingDefaults()); } + initRootDir(); initHomeDir(); initConfiguration(); @@ -264,6 +266,8 @@ Client::Client(const Options &options): "Exiting.", mLocalDataDir.c_str())); } + Image::SDLsetEnableAlphaCache(config.getValue("alphaCache", true)); + #if defined __APPLE__ CFBundleRef mainBundle = CFBundleGetMainBundle(); CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle); @@ -326,9 +330,14 @@ Client::Client(const Options &options): } #endif -#ifdef USE_OPENGL bool useOpenGL = !mOptions.noOpenGL && (config.getValue("opengl", 0) == 1); + // Set up the transparency option for low CPU when not using OpenGL. + if (!useOpenGL && (config.getValue("disableTransparency", 0) == 1)) + Image::SDLdisableTransparency(); + +#ifdef USE_OPENGL + // Setup image loading for the right image format Image::setLoadAsOpenGL(useOpenGL); @@ -546,12 +555,7 @@ int Client::exec() Net::getLoginHandler()->disconnect(); } else if (mState == STATE_CONNECT_SERVER && - mOldState == STATE_CHOOSE_SERVER) - { - Net::connectToServer(mCurrentServer); - } - else if (mState == STATE_CONNECT_SERVER && - mOldState != STATE_CHOOSE_SERVER && + mOldState == STATE_CONNECT_SERVER && Net::getLoginHandler()->isConnected()) { mState = STATE_LOGIN; @@ -647,6 +651,9 @@ int Client::exec() case STATE_CONNECT_SERVER: logger->log("State: CONNECT SERVER"); + + Net::connectToServer(mCurrentServer); + mCurrentDialog = new ConnectionDialog( _("Connecting to server"), STATE_SWITCH_SERVER); break; @@ -945,9 +952,9 @@ int Client::exec() case STATE_SWITCH_LOGIN: logger->log("State: SWITCH LOGIN"); - Net::getLoginHandler()->logout(); + Net::getLoginHandler()->disconnect(); - mState = STATE_LOGIN; + mState = STATE_CONNECT_SERVER; break; case STATE_SWITCH_CHARACTER: @@ -1022,6 +1029,57 @@ void Client::action(const gcn::ActionEvent &event) } } +void Client::initRootDir() +{ + mRootDir = PHYSFS_getBaseDir(); +#ifdef WIN32 + std::string portableName = mRootDir + "portable.xml"; + struct stat statbuf; + + if (!stat(portableName.c_str(), &statbuf) && S_ISREG(statbuf.st_mode)) + { + std::string dir; + Configuration portable; + portable.init(portableName); + + logger->log("Portable file: %s", portableName.c_str()); + + if (mOptions.localDataDir.empty()) + { + dir = portable.getValue("dataDir", ""); + if (!dir.empty()) + { + mOptions.localDataDir = mRootDir + dir; + logger->log("Portable data dir: %s", + mOptions.localDataDir.c_str()); + } + } + + if (mOptions.configDir.empty()) + { + dir = portable.getValue("configDir", ""); + if (!dir.empty()) + { + mOptions.configDir = mRootDir + dir; + logger->log("Portable config dir: %s", + mOptions.configDir.c_str()); + } + } + + if (mOptions.screenshotDir.empty()) + { + dir = portable.getValue("screenshotDir", ""); + if (!dir.empty()) + { + mOptions.screenshotDir = mRootDir + dir; + logger->log("Portable screenshot dir: %s", + mOptions.screenshotDir.c_str()); + } + } + } +#endif +} + /** * Initializes the home directory. On UNIX and FreeBSD, ~/.mana is used. On * Windows and other systems we use the current working directory. @@ -1083,7 +1141,8 @@ void Client::initHomeDir() { std::string oldConfigFile = std::string(PHYSFS_getUserDir()) + "/.tmw/config.xml"; - if (!stat(oldConfigFile.c_str(), &statbuf) && S_ISREG(statbuf.st_mode)) + if (mRootDir.empty() && !stat(oldConfigFile.c_str(), &statbuf) + && S_ISREG(statbuf.st_mode)) { std::ifstream oldConfig; std::ofstream newConfig; @@ -1128,6 +1187,7 @@ void Client::initConfiguration() config.setValue("customcursor", true); config.setValue("useScreenshotDirectorySuffix", true); config.setValue("ChatLogLength", 128); + config.setValue("disableTransparency", false); // Checking if the configuration file exists... otherwise create it with // default options. @@ -1241,24 +1301,18 @@ void Client::initUpdatesDir() void Client::initScreenshotDir() { if (!mOptions.screenshotDir.empty()) + { mScreenshotDir = mOptions.screenshotDir; - else + } + else if (mScreenshotDir.empty()) { - std::string configScreenshotDir = - config.getStringValue("screenshotDirectory"); - if (!configScreenshotDir.empty()) - mScreenshotDir = configScreenshotDir; - else - { #ifdef WIN32 - mScreenshotDir = getSpecialFolderLocation(CSIDL_MYPICTURES); - if (mScreenshotDir.empty()) - mScreenshotDir = getSpecialFolderLocation(CSIDL_DESKTOP); + mScreenshotDir = getSpecialFolderLocation(CSIDL_MYPICTURES); + if (mScreenshotDir.empty()) + mScreenshotDir = getSpecialFolderLocation(CSIDL_DESKTOP); #else - mScreenshotDir = std::string(PHYSFS_getUserDir()) + "Desktop"; + mScreenshotDir = std::string(PHYSFS_getUserDir()) + "Desktop"; #endif - } - config.setValue("screenshotDirectory", mScreenshotDir); if (config.getBoolValue("useScreenshotDirectorySuffix")) { diff --git a/src/client.h b/src/client.h index 836ac3f8..aa650abe 100644 --- a/src/client.h +++ b/src/client.h @@ -183,6 +183,7 @@ public: void action(const gcn::ActionEvent &event); private: + void initRootDir(); void initHomeDir(); void initConfiguration(); void initUpdatesDir(); @@ -200,6 +201,7 @@ private: std::string mUpdateHost; std::string mUpdatesDir; std::string mScreenshotDir; + std::string mRootDir; ServerInfo mCurrentServer; diff --git a/src/commandhandler.cpp b/src/commandhandler.cpp index 878180e6..f3947bd9 100644 --- a/src/commandhandler.cpp +++ b/src/commandhandler.cpp @@ -21,6 +21,7 @@ #include "commandhandler.h" +#include "actorspritemanager.h" #include "channelmanager.h" #include "channel.h" #include "game.h" @@ -46,7 +47,8 @@ void CommandHandler::handleCommand(const std::string &command, ChatTab *tab) { std::string::size_type pos = command.find(' '); std::string type(command, 0, pos); - std::string args(command, pos == std::string::npos ? command.size() : pos + 1); + std::string args(command, pos == std::string::npos ? + command.size() : pos + 1); if (type == "help") // Do help before tabs so they can't override it { @@ -120,6 +122,10 @@ void CommandHandler::handleCommand(const std::string &command, ChatTab *tab) { handlePresent(args, tab); } + else if (type == "showip" && Net::getNetworkType() == ServerInfo::TMWATHENA) + { + handleShowIp(args, tab); + } else { tab->chatLog(_("Unknown command.")); @@ -462,6 +468,35 @@ void CommandHandler::handleToggle(const std::string &args, ChatTab *tab) } } +void CommandHandler::handleShowIp(const std::string &args, ChatTab *tab) +{ + if (args.empty()) + { + tab->chatLog(player_node->getShowIp() ? + _("Show IP: On") : _("Show IP: Off")); + return; + } + + char opt = parseBoolean(args); + + switch (opt) + { + case 0: + tab->chatLog(_("Show IP: Off")); + player_node->setShowIp(false); + break; + case 1: + tab->chatLog(_("Show IP: On")); + player_node->setShowIp(true); + break; + case -1: + tab->chatLog(strprintf(BOOLEAN_OPTIONS, "showip")); + return; + } + + actorSpriteManager->updatePlayerNames(); +} + void CommandHandler::handlePresent(const std::string &args, ChatTab *tab) { chatWindow->doPresent(); diff --git a/src/commandhandler.h b/src/commandhandler.h index c65c3670..c14305e1 100644 --- a/src/commandhandler.h +++ b/src/commandhandler.h @@ -147,6 +147,11 @@ class CommandHandler * Handle away command. */ void handleAway(const std::string &args, ChatTab *tab); + + /* + * Handle showip command. + */ + void handleShowIp(const std::string &args, ChatTab *tab); }; extern CommandHandler *commandHandler; diff --git a/src/defaults.cpp b/src/defaults.cpp index c08fb357..366d804a 100644 --- a/src/defaults.cpp +++ b/src/defaults.cpp @@ -122,6 +122,7 @@ DefaultsData* getConfigDefaults() AddDEF(configData, "ScrollCenterOffsetY", 0); AddDEF(configData, "onlineServerList", ""); AddDEF(configData, "theme", ""); + AddDEF(configData, "disableTransparency", false); return configData; } diff --git a/src/game.cpp b/src/game.cpp index 5557f650..2322d61e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -287,8 +287,23 @@ static bool saveScreenshot() { static unsigned int screenshotCount = 0; + // We don't want to show IP addresses in screenshots + const bool showip = player_node->getShowIp(); + if (showip) + { + player_node->setShowIp(false); + actorSpriteManager->updatePlayerNames(); + gui->draw(); + } + SDL_Surface *screenshot = graphics->getScreenshot(); + if (showip) + { + player_node->setShowIp(true); + actorSpriteManager->updatePlayerNames(); + } + // Search for an unused screenshot name std::stringstream filenameSuffix; std::stringstream filename; @@ -304,7 +319,8 @@ static bool saveScreenshot() screenshotDirectory = std::string(PHYSFS_getUserDir()); } - do { + do + { screenshotCount++; filenameSuffix.str(""); filename.str(""); @@ -315,7 +331,8 @@ static bool saveScreenshot() testExists.open(filename.str().c_str(), std::ios::in); found = !testExists.is_open(); testExists.close(); - } while (!found); + } + while (!found); const bool success = ImageWriter::writePNG(screenshot, filename.str()); @@ -602,13 +619,8 @@ void Game::handleInput() { case KeyboardConfig::KEY_PICKUP: { - const Vector &pos = player_node->getPosition(); - Map *map = viewport->getCurrentMap(); - Uint16 x = (int) pos.x / map->getTileWidth(); - Uint16 y = (int) (pos.y - 1) - / map->getTileHeight(); - // y - 1 needed to fix position, otherwise, it's - // off under eAthena. + int x = player_node->getTileX(); + int y = player_node->getTileY(); FloorItem *item = actorSpriteManager->findItem(x, y); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index f8dc3e82..c8568b0f 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -160,6 +160,9 @@ Gui::~Gui() void Gui::logic() { + ResourceManager *resman = ResourceManager::getInstance(); + resman->clearScheduled(); + // Fade out mouse cursor after extended inactivity if (mMouseInactivityTimer < 100 * 15) { diff --git a/src/gui/login.cpp b/src/gui/login.cpp index b243fd04..b12e6a5d 100644 --- a/src/gui/login.cpp +++ b/src/gui/login.cpp @@ -91,8 +91,6 @@ LoginDialog::LoginDialog(LoginData *loginData): mPassField->requestFocus(); mLoginButton->setEnabled(canSubmit()); - mRegisterButton->setEnabled(Net::getLoginHandler() - ->isRegistrationEnabled()); } LoginDialog::~LoginDialog() @@ -120,10 +118,17 @@ void LoginDialog::action(const gcn::ActionEvent &event) } else if (event.getId() == "register") { - mLoginData->username = mUserField->getText(); - mLoginData->password = mPassField->getText(); - - Client::setState(STATE_REGISTER_PREP); + if (Net::getLoginHandler()->isRegistrationEnabled()) + { + mLoginData->username = mUserField->getText(); + mLoginData->password = mPassField->getText(); + Client::setState(STATE_REGISTER_PREP); + } + else + { + new OkDialog(_("Registration disabled"), _("You need to use the " + "website to register an account for this server.")); + } } } diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp index 1657c8d3..e377042a 100644 --- a/src/gui/serverdialog.cpp +++ b/src/gui/serverdialog.cpp @@ -199,13 +199,18 @@ ServerDialog::ServerDialog(ServerInfo *serverInfo, const std::string &dir): mDownloadStatus(DOWNLOADING_PREPARING), mDownloadProgress(-1.0f), mServers(ServerInfos()), +#ifndef MANASERV_SUPPORT + mManaservServers(ServerInfos()), +#endif mServerInfo(serverInfo) { setWindowName("ServerDialog"); Label *serverLabel = new Label(_("Server:")); Label *portLabel = new Label(_("Port:")); +#ifdef MANASERV_SUPPORT Label *typeLabel = new Label(_("Server type:")); +#endif mServerNameField = new TextField(mServerInfo->hostname); mPortField = new TextField(toString(mServerInfo->port)); @@ -214,7 +219,6 @@ ServerDialog::ServerDialog(ServerInfo *serverInfo, const std::string &dir): mServersListModel = new ServersListModel(&mServers, this); mServersList = new ServersListBox(mServersListModel); - mServersList->addMouseListener(this); ScrollArea *usedScroll = new ScrollArea(mServersList); usedScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); @@ -244,6 +248,7 @@ ServerDialog::ServerDialog(ServerInfo *serverInfo, const std::string &dir): place(1, 0, mServerNameField, 4).setPadding(3); place(0, 1, portLabel); place(1, 1, mPortField, 4).setPadding(3); +#ifdef MANASERV_SUPPORT place(0, 2, typeLabel); place(1, 2, mTypeField, 4).setPadding(3); place(0, 3, usedScroll, 5, 5).setPadding(3); @@ -252,6 +257,14 @@ ServerDialog::ServerDialog(ServerInfo *serverInfo, const std::string &dir): place(1, 9, mDeleteButton); place(3, 9, mQuitButton); place(4, 9, mConnectButton); +#else + place(0, 2, usedScroll, 5, 5).setPadding(3); + place(0, 7, mDescription, 5); + place(0, 8, mManualEntryButton); + place(1, 8, mDeleteButton); + place(3, 8, mQuitButton); + place(4, 8, mConnectButton); +#endif // Make sure the list has enough height getLayout().setRowHeight(3, 80); @@ -417,16 +430,6 @@ void ServerDialog::valueChanged(const gcn::SelectionEvent &) mDeleteButton->setEnabled(myServer.save); } -void ServerDialog::mouseClicked(gcn::MouseEvent &mouseEvent) -{ - if (mouseEvent.getClickCount() == 2 && - mouseEvent.getSource() == mServersList) - { - action(gcn::ActionEvent(mConnectButton, - mConnectButton->getActionEventId())); - } -} - void ServerDialog::logic() { { @@ -468,7 +471,11 @@ void ServerDialog::setFieldsReadOnly(bool readOnly) mServersList->setSelected(-1); mServerNameField->setText(std::string()); +#ifdef MANASERV_SUPPORT mPortField->setText(std::string()); +#else + mPortField->setText(std::string("6901")); +#endif mServerNameField->requestFocus(); } @@ -590,7 +597,11 @@ void ServerDialog::loadServers() } } +#ifdef MANASERV_SUPPORT if (!found) +#else + if (!found && server.type != ServerInfo::MANASERV) +#endif mServers.push_back(server); } } @@ -616,7 +627,15 @@ void ServerDialog::loadCustomServers() break; server.save = true; + +#ifdef MANASERV_SUPPORT mServers.push_back(server); +#else + if (server.type == ServerInfo::MANASERV) + mManaservServers.push_back(server); + else + mServers.push_back(server); +#endif } } @@ -659,6 +678,27 @@ void ServerDialog::saveCustomServers(const ServerInfo ¤tServer) ++savedServerCount; } +#ifndef MANASERV_SUPPORT + for (unsigned i = 0; + i < mManaservServers.size() && savedServerCount < MAX_SERVERLIST; ++i) + { + const ServerInfo &server = mManaservServers.at(i); + + // Only save servers that were loaded from settings + if (!(server.save && server.isValid())) + continue; + + const std::string index = toString(savedServerCount); + const std::string nameKey = "MostUsedServerName" + index; + const std::string typeKey = "MostUsedServerType" + index; + const std::string portKey = "MostUsedServerPort" + index; + + config.setValue(nameKey, toString(server.hostname)); + config.setValue(typeKey, serverTypeToString(server.type)); + config.setValue(portKey, toString(server.port)); + ++savedServerCount; + } +#endif // Insert an invalid entry at the end to make the loading stop there if (savedServerCount < MAX_SERVERLIST) config.setValue("MostUsedServerName" + toString(savedServerCount), ""); diff --git a/src/gui/serverdialog.h b/src/gui/serverdialog.h index 03ed0f7a..aae8b2e0 100644 --- a/src/gui/serverdialog.h +++ b/src/gui/serverdialog.h @@ -32,7 +32,6 @@ #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> #include <guichan/listmodel.hpp> -#include <guichan/mouselistener.hpp> #include <guichan/selectionlistener.hpp> #include <string> @@ -136,8 +135,6 @@ class ServerDialog : public Window, */ void valueChanged(const gcn::SelectionEvent &event); - void mouseClicked(gcn::MouseEvent &mouseEvent); - void logic(); protected: @@ -194,6 +191,9 @@ class ServerDialog : public Window, float mDownloadProgress; ServerInfos mServers; +#ifndef MANASERV_SUPPORT + ServerInfos mManaservServers; +#endif ServerInfo *mServerInfo; }; diff --git a/src/gui/setup_players.cpp b/src/gui/setup_players.cpp index cbe0e264..e1948bb0 100644 --- a/src/gui/setup_players.cpp +++ b/src/gui/setup_players.cpp @@ -298,9 +298,9 @@ Setup_Players::Setup_Players(): place(0, 7, mEnableChatLogCheckBox, 2).setPadding(2); place(2, 5, ignore_action_label); place(2, 6, mIgnoreActionChoicesBox, 2).setPadding(2); - place(2, 7, mDefaultTrading); - place(2, 8, mDefaultWhisper); - place(0, 9, mWhisperTabCheckBox, 4).setPadding(4); + place(0, 8, mDefaultTrading); + place(0, 9, mDefaultWhisper); + place(0, 10, mWhisperTabCheckBox, 4).setPadding(4); player_relations.addListener(this); diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index ae921d2f..c8af218f 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -210,6 +210,7 @@ Setup_Video::Setup_Video(): mPickupParticleEnabled(config.getBoolValue("showpickupparticle")), mOpacity(config.getFloatValue("guialpha")), mFps(config.getIntValue("fpslimit")), + mSDLTransparencyDisabled(config.getBoolValue("disableTransparency")), mSpeechMode(static_cast<Being::Speech>(config.getIntValue("speech"))), mModeListModel(new ModeListModel), mModeList(new ListBox(mModeListModel)), @@ -222,7 +223,7 @@ Setup_Video::Setup_Video(): mParticleEffectsCheckBox(new CheckBox(_("Particle effects"), mParticleEffectsEnabled)), mNameCheckBox(new CheckBox(_("Show own name"), mNameEnabled)), - mNPCLogCheckBox(new CheckBox(_("Log NPC interactions"), mNPCLogEnabled)), + mNPCLogCheckBox(new CheckBox(_("Log NPC dialogue"), mNPCLogEnabled)), mPickupNotifyLabel(new Label(_("Show pickup notification"))), // TRANSLATORS: Refers to "Show pickup notification" mPickupChatCheckBox(new CheckBox(_("in chat"), mPickupChatEnabled)), @@ -241,11 +242,14 @@ Setup_Video::Setup_Video(): mParticleDetail(3 - config.getIntValue("particleEmitterSkip")), mParticleDetailSlider(new Slider(0, 3)), mParticleDetailField(new Label), - mFontSize(config.getIntValue("fontSize")) + mFontSize(config.getIntValue("fontSize")), + mDisableSDLTransparencyCheckBox( + new CheckBox(_("Disable transparency (Low CPU mode)"), + mSDLTransparencyDisabled)) { setName(_("Video")); - mShowMonsterDamageCheckBox = new CheckBox(_("Show monster damage"), + mShowMonsterDamageCheckBox = new CheckBox(_("Show damage"), mShowMonsterDamageEnabled); ScrollArea *scrollArea = new ScrollArea(mModeList); @@ -268,6 +272,7 @@ Setup_Video::Setup_Video(): mAlphaSlider->setValue(mOpacity); mAlphaSlider->setWidth(90); + mAlphaSlider->setEnabled(!mSDLTransparencyDisabled); mFpsLabel->setCaption(mFps > 0 ? toString(mFps) : _("None")); mFpsLabel->setWidth(60); @@ -275,6 +280,10 @@ Setup_Video::Setup_Video(): mFpsSlider->setEnabled(mFps > 0); mFpsCheckBox->setSelected(mFps > 0); + // If the openGL Mode is enabled, disabling the transaprency + // is irrelevant. + mDisableSDLTransparencyCheckBox->setEnabled(!mOpenGLEnabled); + // Pre-select the current video mode. std::string videoMode = toString(graphics->getWidth()) + "x" + toString(graphics->getHeight()); @@ -295,13 +304,16 @@ Setup_Video::Setup_Video(): mFpsSlider->setActionEventId("fpslimitslider"); mOverlayDetailSlider->setActionEventId("overlaydetailslider"); mOverlayDetailField->setActionEventId("overlaydetailfield"); + mOpenGLCheckBox->setActionEventId("opengl"); mParticleDetailSlider->setActionEventId("particledetailslider"); mParticleDetailField->setActionEventId("particledetailfield"); + mDisableSDLTransparencyCheckBox->setActionEventId("disableTransparency"); mModeList->addActionListener(this); mCustomCursorCheckBox->addActionListener(this); mShowMonsterDamageCheckBox->addActionListener(this); mVisibleNamesCheckBox->addActionListener(this); + mOpenGLCheckBox->addActionListener(this); mParticleEffectsCheckBox->addActionListener(this); mPickupChatCheckBox->addActionListener(this); mPickupParticleCheckBox->addActionListener(this); @@ -315,6 +327,7 @@ Setup_Video::Setup_Video(): mOverlayDetailField->addKeyListener(this); mParticleDetailSlider->addActionListener(this); mParticleDetailField->addKeyListener(this); + mDisableSDLTransparencyCheckBox->addActionListener(this); mSpeechLabel->setCaption(speechModeToString(mSpeechMode)); mSpeechSlider->setValue(mSpeechMode); @@ -372,6 +385,8 @@ Setup_Video::Setup_Video(): place(1, 11, particleDetailLabel); place(2, 11, mParticleDetailField, 3).setPadding(2); + place(0, 12, mDisableSDLTransparencyCheckBox, 4); + setDimension(gcn::Rectangle(0, 0, 365, 300)); } @@ -442,8 +457,9 @@ void Setup_Video::apply() { new OkDialog(_("Changing to OpenGL"), _("Applying change to OpenGL requires restart. " - "In case OpenGL messes up your game graphics, restart " - "the game with the command line option \"--no-opengl\".")); + "In case OpenGL messes up your game graphics, " + "restart the game with the command line option " + "\"--no-opengl\".")); } else { @@ -451,6 +467,25 @@ void Setup_Video::apply() _("Applying change to OpenGL requires restart.")); } } + // If LowCPU is enabled from a disabled state we warn the user + else if (mDisableSDLTransparencyCheckBox->isSelected()) + { + if (config.getValue("disableTransparency", true) == false) + { + new OkDialog(_("Transparency disabled"), + _("You must restart to apply changes.")); + } + } + else + { + if (config.getValue("disableTransparency", true) == true) + { + new OkDialog(_("Transparency enabled"), + _("You must restart to apply changes.")); + } + } + config.setValue("disableTransparency", + mDisableSDLTransparencyCheckBox->isSelected()); mFps = mFpsCheckBox->isSelected() ? (int) mFpsSlider->getValue() : 0; mFpsSlider->setEnabled(mFps > 0); @@ -467,13 +502,13 @@ void Setup_Video::apply() mParticleEffectsEnabled = config.getBoolValue("particleeffects"); mNameEnabled = config.getBoolValue("showownname"); mNPCLogEnabled = config.getBoolValue("logNpcInGui"); - mSpeechMode = static_cast<Being::Speech>( - config.getIntValue("speech")); + mSpeechMode = static_cast<Being::Speech>(config.getIntValue("speech")); mOpacity = config.getFloatValue("guialpha"); mOverlayDetail = config.getIntValue("OverlayDetail"); mOpenGLEnabled = config.getBoolValue("opengl"); mPickupChatEnabled = config.getBoolValue("showpickupchat"); mPickupParticleEnabled = config.getBoolValue("showpickupparticle"); + mSDLTransparencyDisabled = config.getBoolValue("disableTransparency"); } void Setup_Video::cancel() @@ -491,10 +526,13 @@ void Setup_Video::cancel() mNameCheckBox->setSelected(mNameEnabled); mNPCLogCheckBox->setSelected(mNPCLogEnabled); mAlphaSlider->setValue(mOpacity); + mAlphaSlider->setEnabled(!mSDLTransparencyDisabled); mOverlayDetailSlider->setValue(mOverlayDetail); mParticleDetailSlider->setValue(mParticleDetail); std::string text = mFpsCheckBox->isSelected() ? toString(mFps) : _("None"); mFpsLabel->setCaption(text); + mDisableSDLTransparencyCheckBox->setSelected(mSDLTransparencyDisabled); + mDisableSDLTransparencyCheckBox->setEnabled(!mOpenGLEnabled); config.setValue("screen", mFullScreenEnabled); @@ -518,6 +556,7 @@ void Setup_Video::cancel() config.setValue("opengl", mOpenGLEnabled); config.setValue("showpickupchat", mPickupChatEnabled); config.setValue("showpickupparticle", mPickupParticleEnabled); + config.setValue("disableTransparency", mSDLTransparencyDisabled); } void Setup_Video::action(const gcn::ActionEvent &event) @@ -626,4 +665,24 @@ void Setup_Video::action(const gcn::ActionEvent &event) mFpsSlider->setValue(mFps); mFpsSlider->setEnabled(mFps > 0); } + else if (id == "opengl" || id == "disableTransparency") + { + // Disable transparency disabling when in OpenGL. + if (mOpenGLCheckBox->isSelected()) + { + mDisableSDLTransparencyCheckBox->setSelected(false); + mDisableSDLTransparencyCheckBox->setEnabled(false); + } + else + { + mDisableSDLTransparencyCheckBox->setEnabled(true); + } + + // Disable gui opacity slider when disabling transparency. + if (mDisableSDLTransparencyCheckBox->isEnabled()) + mAlphaSlider->setEnabled( + !mDisableSDLTransparencyCheckBox->isSelected()); + else + mAlphaSlider->setEnabled(true); + } } diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h index ae0786b1..d0e2c492 100644 --- a/src/gui/setup_video.h +++ b/src/gui/setup_video.h @@ -62,6 +62,7 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, bool mPickupParticleEnabled; double mOpacity; int mFps; + bool mSDLTransparencyDisabled; Being::Speech mSpeechMode; ModeListModel *mModeListModel; @@ -106,6 +107,8 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, int mFontSize; gcn::DropDown *mFontSizeDropDown; + + gcn::CheckBox *mDisableSDLTransparencyCheckBox; }; #endif diff --git a/src/gui/socialwindow.cpp b/src/gui/socialwindow.cpp index 588ce5e7..b4321b25 100644 --- a/src/gui/socialwindow.cpp +++ b/src/gui/socialwindow.cpp @@ -140,7 +140,7 @@ public: mGuild->getName().c_str())) mConfirmDialog = NULL; } - else if (event.getId() == "~yes") + else if (event.getId() == "no") { mConfirmDialog = NULL; } @@ -180,7 +180,7 @@ public: { setCaption(party->getName()); - setTabColor(&Theme::getThemeColor(Theme::PARTY)); + setTabColor(&Theme::getThemeColor(Theme::PARTY_SOCIAL_TAB)); mList = new AvatarListBox(party); mScroll = new ScrollArea(mList); @@ -219,7 +219,7 @@ public: mParty->getName().c_str())) mConfirmDialog = NULL; } - else if (event.getId() == "~yes") + else if (event.getId() == "no") { mConfirmDialog = NULL; } @@ -498,10 +498,12 @@ void SocialWindow::action(const gcn::ActionEvent &event) "shorter name.")); return; } - - Net::getGuildHandler()->create(name); - SERVER_NOTICE(strprintf(_("Creating guild called %s."), - name.c_str())) + else if (!name.empty()) + { + Net::getGuildHandler()->create(name); + SERVER_NOTICE(strprintf(_("Creating guild called %s."), + name.c_str())); + } mGuildCreateDialog = NULL; } @@ -519,10 +521,12 @@ void SocialWindow::action(const gcn::ActionEvent &event) "shorter name.")); return; } - - Net::getPartyHandler()->create(name); - SERVER_NOTICE(strprintf(_("Creating party called %s."), - name.c_str())); + else if (!name.empty()) + { + Net::getPartyHandler()->create(name); + SERVER_NOTICE(strprintf(_("Creating party called %s."), + name.c_str())); + } mPartyCreateDialog = NULL; } diff --git a/src/gui/truetypefont.cpp b/src/gui/truetypefont.cpp index e2ae5b93..ebc01ec7 100644 --- a/src/gui/truetypefont.cpp +++ b/src/gui/truetypefont.cpp @@ -64,8 +64,8 @@ class TextChunk if (!surface) { - throw "Rendering font to surface failed: " + - std::string(TTF_GetError()); + img = 0; + return; } img = Image::load(surface); @@ -108,9 +108,7 @@ TrueTypeFont::~TrueTypeFont() --fontCounter; if (fontCounter == 0) - { TTF_Quit(); - } } void TrueTypeFont::drawString(gcn::Graphics *graphics, @@ -123,9 +121,7 @@ void TrueTypeFont::drawString(gcn::Graphics *graphics, Graphics *g = dynamic_cast<Graphics *>(graphics); if (!g) - { throw "Not a valid graphics object!"; - } gcn::Color col = g->getColor(); const float alpha = col.a / 255.0f; @@ -154,15 +150,16 @@ void TrueTypeFont::drawString(gcn::Graphics *graphics, if (!found) { if (mCache.size() >= CACHE_SIZE) - { mCache.pop_back(); - } mCache.push_front(chunk); mCache.front().generate(mFont); } - mCache.front().img->setAlpha(alpha); - g->drawImage(mCache.front().img, x, y); + if (mCache.front().img) + { + mCache.front().img->setAlpha(alpha); + g->drawImage(mCache.front().img, x, y); + } } int TrueTypeFont::getWidth(const std::string &text) const @@ -174,7 +171,10 @@ int TrueTypeFont::getWidth(const std::string &text) const // Raise priority: move it to front // Assumption is that TTF::draw will be called next mCache.splice(mCache.begin(), mCache, i); - return i->img->getWidth(); + if (i->img) + return i->img->getWidth(); + else + return 0; } } diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 0209b13f..368eef17 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -352,10 +352,17 @@ void Viewport::mousePressed(gcn::MouseEvent &event) return; mPlayerFollowMouse = false; + mBeingPopup->setVisible(false); const int pixelX = event.getX() + (int) mPixelViewX; const int pixelY = event.getY() + (int) mPixelViewY; + mHoverBeing = actorSpriteManager->findBeingByPixel(pixelX, pixelY); + mHoverItem = actorSpriteManager->findItem(pixelX / mMap->getTileWidth(), + pixelY / mMap->getTileHeight()); + + updateCursorType(); + // Right click might open a popup if (event.getButton() == gcn::MouseEvent::RIGHT) { @@ -452,10 +459,8 @@ void Viewport::mouseDragged(gcn::MouseEvent &event) if (mLocalWalkTime != player_node->getActionTime()) { mLocalWalkTime = player_node->getActionTime(); - int destX = (event.getX() + mPixelViewX + 16) / - mMap->getTileWidth(); - int destY = (event.getY() + mPixelViewY + 16) / - mMap->getTileHeight(); + int destX = (event.getX() + mPixelViewX) / mMap->getTileWidth(); + int destY = (event.getY() + mPixelViewY) / mMap->getTileHeight(); player_node->setDestination(destX, destY); } } @@ -502,6 +507,11 @@ void Viewport::mouseMoved(gcn::MouseEvent &event) mHoverItem = actorSpriteManager->findItem(x / mMap->getTileWidth(), y / mMap->getTileHeight()); + updateCursorType(); +} + +void Viewport::updateCursorType() +{ if (mHoverBeing) { switch (mHoverBeing->getType()) diff --git a/src/gui/viewport.h b/src/gui/viewport.h index c54b9860..55db3676 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -180,6 +180,11 @@ class Viewport : public WindowContainer, public gcn::MouseListener, */ void _followMouse(); + /** + * Updates the cursor type + */ + void updateCursorType(); + Map *mMap; /**< The current map. */ int mScrollRadius; diff --git a/src/gui/widgets/avatarlistbox.cpp b/src/gui/widgets/avatarlistbox.cpp index 6551aa04..60837ea1 100644 --- a/src/gui/widgets/avatarlistbox.cpp +++ b/src/gui/widgets/avatarlistbox.cpp @@ -22,7 +22,6 @@ #include "graphics.h" -#include "gui/chat.h" #include "gui/gui.h" #include "gui/palette.h" @@ -139,14 +138,6 @@ void AvatarListBox::mousePressed(gcn::MouseEvent &event) int y = event.getY(); setSelected(y / getFont()->getHeight()); distributeActionEvent(); - - if (event.getClickCount() == 2 && mListModel) - { - int selected = getSelected(); - AvatarListModel *model = static_cast<AvatarListModel*>(mListModel); - chatWindow->addWhisperTab(model->getAvatarAt(selected)->getName(), - true); - } } // TODO: Add support for context menu else if (event.getButton() == gcn::MouseEvent::RIGHT) diff --git a/src/gui/widgets/browserbox.cpp b/src/gui/widgets/browserbox.cpp index d890f138..314429fa 100644 --- a/src/gui/widgets/browserbox.cpp +++ b/src/gui/widgets/browserbox.cpp @@ -2,6 +2,7 @@ * The Mana Client * Copyright (C) 2004-2009 The Mana World Development Team * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2009 Aethyra Development Team * * This file is part of The Mana Client. * @@ -21,6 +22,8 @@ #include "gui/widgets/browserbox.h" +#include "client.h" + #include "gui/widgets/linkhandler.h" #include "resources/theme.h" @@ -40,7 +43,9 @@ BrowserBox::BrowserBox(unsigned int mode, bool opaque): mMaxRows(0), mHeight(0), mWidth(0), - mYStart(0) + mYStart(0), + mUpdateTime(-1), + mAlwaysUpdate(true) { setFocusable(true); addMouseListener(this); @@ -74,13 +79,14 @@ void BrowserBox::addRow(const std::string &row) { std::string tmp = row; std::string newRow; - BROWSER_LINK bLink; std::string::size_type idx1, idx2, idx3; gcn::Font *font = getFont(); // Use links and user defined colors if (mUseLinksAndUserColors) { + BROWSER_LINK bLink; + // Check for links in format "@@link|Caption@@" idx1 = tmp.find("@@"); while (idx1 != std::string::npos) @@ -92,7 +98,7 @@ void BrowserBox::addRow(const std::string &row) break; bLink.link = tmp.substr(idx1 + 2, idx2 - (idx1 + 2)); bLink.caption = tmp.substr(idx2 + 1, idx3 - (idx2 + 1)); - bLink.y1 = mTextRows.size() * font->getHeight(); + bLink.y1 = static_cast<int>(mTextRows.size()) * font->getHeight(); bLink.y2 = bLink.y1 + font->getHeight(); newRow += tmp.substr(0, idx1); @@ -150,7 +156,7 @@ void BrowserBox::addRow(const std::string &row) if (mMode == AUTO_SIZE) { std::string plain = newRow; - for (idx1 = plain.find("##"); idx1 != std::string::npos; idx1 = plain.find("##")) + while ((idx1 = plain.find("##")) != std::string::npos) plain.erase(idx1, 3); // Adjust the BrowserBox size @@ -179,11 +185,11 @@ void BrowserBox::addRow(const std::string &row) // Wraping between words (at blank spaces) if ((nextChar < row.size()) && (row.at(nextChar) == ' ')) { - int nextSpacePos = row.find(" ", (nextChar + 1)); + int nextSpacePos = static_cast<int>( + row.find(" ", (nextChar + 1))); if (nextSpacePos <= 0) - { - nextSpacePos = row.size() - 1; - } + nextSpacePos = static_cast<int>(row.size()) - 1; + int nextWordWidth = font->getWidth( row.substr(nextChar, (nextSpacePos - nextChar))); @@ -204,12 +210,14 @@ void BrowserBox::addRow(const std::string &row) } } - setHeight(font->getHeight() * (mTextRows.size() + y)); + setHeight(font->getHeight() * (static_cast<int>( + mTextRows.size()) + y)); } else { - setHeight(font->getHeight() * mTextRows.size()); + setHeight(font->getHeight() * static_cast<int>(mTextRows.size())); } + mUpdateTime = 0; updateHeight(); } @@ -225,7 +233,9 @@ void BrowserBox::clearRows() struct MouseOverLink { - MouseOverLink(int x, int y) : mX(x),mY(y) { } + MouseOverLink(int x, int y) : mX(x), mY(y) + { } + bool operator() (BROWSER_LINK &link) { return (mX >= link.x1 && mX < link.x2 && @@ -249,7 +259,8 @@ void BrowserBox::mouseMoved(gcn::MouseEvent &event) LinkIterator i = find_if(mLinks.begin(), mLinks.end(), MouseOverLink(event.getX(), event.getY())); - mSelectedLink = (i != mLinks.end()) ? (i - mLinks.begin()) : -1; + mSelectedLink = (i != mLinks.end()) + ? static_cast<int>(i - mLinks.begin()) : -1; } void BrowserBox::draw(gcn::Graphics *graphics) @@ -261,10 +272,7 @@ void BrowserBox::draw(gcn::Graphics *graphics) mYStart = 0; if (getWidth() != mWidth) - { - mWidth = getWidth(); updateHeight(); - } if (mOpaque) { @@ -296,7 +304,28 @@ void BrowserBox::draw(gcn::Graphics *graphics) } } + gcn::Font *font = getFont(); + + for (LinePartIterator i = mLineParts.begin(); + i != mLineParts.end(); + i ++) + { + const LinePart &part = *i; + if (part.getY() + 50 < mYStart) + continue; + if (part.getY() > yEnd) + break; + graphics->setColor(part.getColor()); + font->drawString(graphics, part.getText(), part.getX(), part.getY()); + } + + return; +} + +int BrowserBox::calcHeight() +{ int x = 0, y = 0; + int wrappedLines = 0; int link = 0; gcn::Font *font = getFont(); @@ -305,27 +334,13 @@ void BrowserBox::draw(gcn::Graphics *graphics) char const *hyphen = "~"; int hyphenWidth = font->getWidth(hyphen); - graphics->setColor(Theme::getThemeColor(Theme::TEXT)); + gcn::Color selColor = Theme::getThemeColor(Theme::TEXT); const gcn::Color textColor = Theme::getThemeColor(Theme::TEXT); - TextRowsHeightIterator h = mTextRowsHeights.begin(); - for (TextRowIterator i = mTextRows.begin(); - i != mTextRows.end(); - i++, h++) - { - bool hidden = false; - if (y + 50 < mYStart) - { - y += *(h); - continue; - } - else if (y > yEnd) - { - break; - } + mLineParts.clear(); - gcn::Color selColor = textColor; - gcn::Color prevColor = selColor; + for (TextRowIterator i = mTextRows.begin(); i != mTextRows.end(); i++) + { const std::string row = *(i); bool wrapped = false; x = 0; @@ -333,19 +348,19 @@ void BrowserBox::draw(gcn::Graphics *graphics) // Check for separator lines if (row.find("---", 0) == 0) { - if (!hidden) + const int dashWidth = fontWidthMinus; + for (x = 0; x < getWidth(); x++) { - const int dashWidth = fontWidthMinus; - for (x = 0; x < getWidth(); x++) - { - font->drawString(graphics, "-", x, y); - x += dashWidth - 2; - } + mLineParts.push_back(LinePart(x, y, selColor, "-")); + x += dashWidth - 2; } + y += fontHeight; continue; } + gcn::Color prevColor = selColor; + // TODO: Check if we must take texture size limits into account here // TODO: Check if some of the O(n) calls can be removed for (std::string::size_type start = 0, end = std::string::npos; @@ -364,14 +379,14 @@ void BrowserBox::draw(gcn::Graphics *graphics) if (mUseLinksAndUserColors) end = row.find("##", start + 1); - if (!hidden - && (mUseLinksAndUserColors || - (!mUseLinksAndUserColors && (start == 0)))) + if (mUseLinksAndUserColors || + (!mUseLinksAndUserColors && (start == 0))) { // Check for color change in format "##x", x = [L,P,0..9] if (row.find("##", start) == start && row.size() > start + 2) { const char c = row.at(start + 2); + bool valid; const gcn::Color col = Theme::getThemeColor(c, valid); @@ -381,7 +396,6 @@ void BrowserBox::draw(gcn::Graphics *graphics) } else if (c == '<') { - link++; prevColor = selColor; selColor = col; } @@ -408,144 +422,12 @@ void BrowserBox::draw(gcn::Graphics *graphics) selColor = textColor; } } - start += 3; - - if (start == row.size()) - break; - } - graphics->setColor(selColor); - } - - std::string::size_type len = - end == std::string::npos ? end : end - start; - std::string part = row.substr(start, len); - - // Auto wrap mode - if (mMode == AUTO_WRAP && getWidth() > 0 - && font->getWidth(part) > 0 - && (x + font->getWidth(part) + 10) > getWidth()) - { - bool forced = false; - - /* FIXME: This code layout makes it easy to crash remote - clients by talking garbage. Forged long utf-8 characters - will cause either a buffer underflow in substr or an - infinite loop in the main loop. */ - do - { - if (!forced) - end = row.rfind(' ', end); - - // Check if we have to (stupidly) force-wrap - if (end == std::string::npos || end <= start) - { - forced = true; - end = row.size(); - x += hyphenWidth; // Account for the wrap-notifier - continue; - } - - // Skip to the start of the current character - while ((row[end] & 192) == 128) - end--; - end--; // And then to the last byte of the previous one - - part = row.substr(start, end - start + 1); - } - while (end > start && font->getWidth(part) > 0 - && (x + font->getWidth(part) + 10) > getWidth()); - - if (forced) - { - x -= hyphenWidth; // Remove the wrap-notifier accounting - if (y >= mYStart) - { - font->drawString(graphics, hyphen, - getWidth() - hyphenWidth, y); - } - end++; // Skip to the next character - } - else - { - end += 2; // Skip to after the space - } - - wrapped = true; - } - - font->drawString(graphics, part, x, y); - - if (mMode == AUTO_WRAP && font->getWidth(part) == 0) - break; - - x += font->getWidth(part); - } - y += fontHeight; - } - setHeight(mHeight); -} - -int BrowserBox::calcHeight() -{ - int x = 0, y = 0; - int wrappedLines = 0; - int link = 0; - gcn::Font *font = getFont(); - - int fontHeight = font->getHeight(); - int fontWidthMinus = font->getWidth("-"); - char const *hyphen = "~"; - int hyphenWidth = font->getWidth(hyphen); - - mTextRowsHeights.clear(); - - for (TextRowIterator i = mTextRows.begin(); i != mTextRows.end(); i++) - { - const std::string row = *(i); - bool wrapped = false; - int yStart = y; - x = 0; - - // Check for separator lines - if (row.find("---", 0) == 0) - { - const int dashWidth = fontWidthMinus; - for (x = 0; x < getWidth(); x++) - x += dashWidth - 2; - - y += fontHeight; - continue; - } - - // TODO: Check if we must take texture size limits into account here - // TODO: Check if some of the O(n) calls can be removed - for (std::string::size_type start = 0, end = std::string::npos; - start != std::string::npos; - start = end, end = std::string::npos) - { - // Wrapped line continuation shall be indented - if (wrapped) - { - y += fontHeight; - x = 15; - wrapped = false; - } - - // "Tokenize" the string at control sequences - if (mUseLinksAndUserColors) - end = row.find("##", start + 1); - - if (mUseLinksAndUserColors || - (!mUseLinksAndUserColors && (start == 0))) - { - // Check for color change in format "##x", x = [L,P,0..9] - if (row.find("##", start) == start && row.size() > start + 2) - { - const char c = row.at(start + 2); if (c == '<') { - const int size = font->getWidth(mLinks[link].caption) + 1; + const int size = + font->getWidth(mLinks[link].caption) + 1; + mLinks[link].x1 = x; mLinks[link].y1 = y; mLinks[link].x2 = mLinks[link].x1 + size; @@ -605,6 +487,8 @@ int BrowserBox::calcHeight() if (forced) { x -= hyphenWidth; // Remove the wrap-notifier accounting + mLineParts.push_back(LinePart(getWidth() - hyphenWidth, + y, selColor, hyphen)); end++; // Skip to the next character } else @@ -616,19 +500,26 @@ int BrowserBox::calcHeight() wrappedLines++; } + mLineParts.push_back(LinePart(x, y, selColor, part.c_str())); + if (mMode == AUTO_WRAP && font->getWidth(part) == 0) break; x += font->getWidth(part); } y += fontHeight; - mTextRowsHeights.push_back(y - yStart); } - return (mTextRows.size() + wrappedLines) * fontHeight; + return (static_cast<int>(mTextRows.size()) + wrappedLines) * fontHeight; } void BrowserBox::updateHeight() { - mHeight = calcHeight(); - setHeight(mHeight); + if (mAlwaysUpdate || !mUpdateTime || std::abs(mUpdateTime - tick_time) > 10 + || mTextRows.size() < 3) + { + mWidth = getWidth(); + mHeight = calcHeight(); + setHeight(mHeight); + mUpdateTime = tick_time; + } } diff --git a/src/gui/widgets/browserbox.h b/src/gui/widgets/browserbox.h index b71f30d7..54a2a8cc 100644 --- a/src/gui/widgets/browserbox.h +++ b/src/gui/widgets/browserbox.h @@ -2,6 +2,7 @@ * The Mana Client * Copyright (C) 2004-2009 The Mana World Development Team * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2009 Aethyra Development Team * * This file is part of The Mana Client. * @@ -30,12 +31,39 @@ class LinkHandler; -struct BROWSER_LINK { +struct BROWSER_LINK +{ int x1, x2, y1, y2; /**< Where link is placed */ std::string link; std::string caption; }; +class LinePart +{ + public: + LinePart(int x, int y, gcn::Color color, std::string text) : + mX(x), mY(y), mColor(color), mText(text) + { + } + + int getX() const + { return mX; } + + int getY() const + { return mY; } + + const std::string &getText() const + { return mText; } + + const gcn::Color &getColor() const + { return mColor; } + + private: + int mX, mY; + gcn::Color mColor; + std::string mText; +}; + /** * A simple browser box able to handle links and forward events to the * parent conteiner. @@ -72,7 +100,7 @@ class BrowserBox : public gcn::Widget, /** * Sets the maximum numbers of rows in the browser box. 0 = no limit. */ - void setMaxRow(int max) {mMaxRows = max; }; + void setMaxRow(unsigned max) {mMaxRows = max; }; /** * Disable links & user defined colors to be used in chat input. @@ -111,8 +139,9 @@ class BrowserBox : public gcn::Widget, /** * BrowserBox modes. */ - enum { - AUTO_SIZE, + enum + { + AUTO_SIZE = 0, AUTO_WRAP /**< Maybe it needs a fix or to be redone. */ }; @@ -126,7 +155,8 @@ class BrowserBox : public gcn::Widget, * windows and widgets. So, I think it's better keep BrowserBox * opaque (white background) by default. */ - enum { + enum + { RED = 0xff0000, /**< Color 1 */ GREEN = 0x009000, /**< Color 2 */ BLUE = 0x0000ff, /**< Color 3 */ @@ -142,21 +172,29 @@ class BrowserBox : public gcn::Widget, * Highlight modes for links. * This can be used for a bitmask. */ - enum { + enum + { UNDERLINE = 1, BACKGROUND = 2 }; + typedef std::list<std::string> TextRows; + + TextRows &getRows() + { return mTextRows; } + + void setAlwaysUpdate(bool n) + { mAlwaysUpdate = n; } + private: int calcHeight(); - typedef std::list<std::string> TextRows; typedef TextRows::iterator TextRowIterator; TextRows mTextRows; - typedef std::list<int> TextRowsHeights; - typedef TextRowsHeights::iterator TextRowsHeightIterator; - TextRowsHeights mTextRowsHeights; + typedef std::list<LinePart> LinePartList; + typedef LinePartList::iterator LinePartIterator; + LinePartList mLineParts; typedef std::vector<BROWSER_LINK> Links; typedef Links::iterator LinkIterator; @@ -172,6 +210,8 @@ class BrowserBox : public gcn::Widget, int mHeight; int mWidth; int mYStart; + int mUpdateTime; + bool mAlwaysUpdate; }; #endif diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp index e9162ab6..c86eb2ea 100644 --- a/src/gui/widgets/chattab.cpp +++ b/src/gui/widgets/chattab.cpp @@ -54,6 +54,7 @@ ChatTab::ChatTab(const std::string &name) : Tab() mTextOutput->setOpaque(false); mTextOutput->setMaxRow((int) config.getIntValue("ChatLogLength")); mTextOutput->setLinkHandler(chatWindow->mItemLinkHandler); + mTextOutput->setAlwaysUpdate(false); mScrollArea = new ScrollArea(mTextOutput); mScrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, diff --git a/src/gui/widgets/desktop.cpp b/src/gui/widgets/desktop.cpp index 2a80cc11..23dd3eb5 100644 --- a/src/gui/widgets/desktop.cpp +++ b/src/gui/widgets/desktop.cpp @@ -85,7 +85,7 @@ void Desktop::draw(gcn::Graphics *graphics) if (mWallpaper) { - if (!mWallpaper->isAnOpenGLOne()) + if (!mWallpaper->useOpenGL()) g->drawImage(mWallpaper, (getWidth() - mWallpaper->getWidth()) / 2, (getHeight() - mWallpaper->getHeight()) / 2); @@ -114,7 +114,7 @@ void Desktop::setBestFittingWallpaper() if (mWallpaper) mWallpaper->decRef(); - if (!nWallPaper->isAnOpenGLOne() && (nWallPaper->getWidth() != getWidth() + if (!nWallPaper->useOpenGL() && (nWallPaper->getWidth() != getWidth() || nWallPaper->getHeight() != getHeight())) { // We rescale to obtain a fullscreen wallpaper... diff --git a/src/gui/widgets/itemcontainer.cpp b/src/gui/widgets/itemcontainer.cpp index c8c98d0a..d448c3c2 100644 --- a/src/gui/widgets/itemcontainer.cpp +++ b/src/gui/widgets/itemcontainer.cpp @@ -255,47 +255,13 @@ void ItemContainer::mousePressed(gcn::MouseEvent &event) if (mSelectedIndex == index) { - if(event.getClickCount() == 2) - { - if (item->getInfo().getEquippable()) - { - if (item->isEquipped()) - item->doEvent("doUnequip"); - else - item->doEvent("doEquip"); - } - else - item->doEvent("doUse"); - - } - else - { - mSelectionStatus = SEL_DESELECTING; - } + mSelectionStatus = SEL_DESELECTING; } else if (item && item->getId()) { - if(event.getClickCount() == 2) - { - if (item->getInfo().getEquippable()) - { - if (item->isEquipped()) - item->doEvent("doUnequip"); - else - item->doEvent("doEquip"); - } - else - { - item->doEvent("doUse"); - } - } - else - { - setSelectedIndex(index); - mSelectionStatus = SEL_SELECTING; - - itemShortcut->setItemSelected(item->getId()); - } + setSelectedIndex(index); + mSelectionStatus = SEL_SELECTING; + itemShortcut->setItemSelected(item->getId()); if (item->getInfo().getEquippable()) outfitWindow->setItemSelected(item->getId()); diff --git a/src/gui/widgets/itemshortcutcontainer.cpp b/src/gui/widgets/itemshortcutcontainer.cpp index f2982de9..fb4f558f 100644 --- a/src/gui/widgets/itemshortcutcontainer.cpp +++ b/src/gui/widgets/itemshortcutcontainer.cpp @@ -109,6 +109,7 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics) else if (item->isEquipped()) caption = "Eq."; + image->setAlpha(1.0f); g->drawImage(image, itemX, itemY); if (item->isEquipped()) g->setColor(Theme::getThemeColor(Theme::ITEM_EQUIPPED)); diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp index 2900239f..b7d92277 100644 --- a/src/imageparticle.cpp +++ b/src/imageparticle.cpp @@ -48,20 +48,12 @@ bool ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const int screenY = (int) mPos.y - (int)mPos.z + offsetY - mImage->getHeight()/2; // Check if on screen - if (screenX + mImage->getWidth() < 0 || - screenX > graphics->getWidth() || - screenY + mImage->getHeight() < 0 || - screenY > graphics->getHeight()) + if (screenX + mImage->getWidth() < 0 + || screenX > graphics->getWidth() + || screenY + mImage->getHeight() < 0 + || screenY > graphics->getHeight()) return false; - float alphafactor = mAlpha; - - if (mLifetimeLeft > -1 && mLifetimeLeft < mFadeOut) - alphafactor *= (float) mLifetimeLeft / (float) mFadeOut; - - if (mLifetimePast < mFadeIn) - alphafactor *= (float) mLifetimePast / (float) mFadeIn; - - mImage->setAlpha(alphafactor); + mImage->setAlpha(getCurrentAlpha()); return graphics->drawImage(mImage, screenX, screenY); } diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 15f7e11d..b60ee6f7 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -84,7 +84,8 @@ LocalPlayer::LocalPlayer(int id, int subtype): mWalkingDir(0), mPathSetByMouse(false), mLocalWalkTime(-1), - mMessageTime(0) + mMessageTime(0), + mShowIp(false) { listen("Attributes"); @@ -635,8 +636,9 @@ void LocalPlayer::pickUp(FloorItem *item) if (!item) return; - int dx = item->getTileX() - (int) getPosition().x / 32; - int dy = item->getTileY() - (int) getPosition().y / 32; + int dx = item->getTileX() - (int) getPosition().x / mMap->getTileWidth(); + int dy = item->getTileY() - ((int) getPosition().y - 1) + / mMap->getTileHeight(); if (dx * dx + dy * dy < 4) { @@ -931,20 +933,23 @@ void LocalPlayer::attack(Being *target, bool keep) if (mAction != STAND) return; + Uint8 direction = 0; if (abs(dist_y) >= abs(dist_x)) { if (dist_y > 0) - setDirection(DOWN); + direction = DOWN; else - setDirection(UP); + direction = UP; } else { if (dist_x > 0) - setDirection(RIGHT); + direction = RIGHT; else - setDirection(LEFT); + direction = LEFT; } + Net::getPlayerHandler()->setDirection(direction); + setDirection(direction); mActionTime = tick_time; mTargetTime = tick_time; diff --git a/src/localplayer.h b/src/localplayer.h index 41fc84a8..0580ef89 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -164,6 +164,12 @@ class LocalPlayer : public Being */ void pickedUp(const ItemInfo &itemInfo, int amount); + void setShowIp(bool show) + { mShowIp = show; } + + bool getShowIp() const + { return mShowIp; } + /** Tells that the path has been set by mouse. */ void pathSetByMouse() { mPathSetByMouse = true; } @@ -183,7 +189,7 @@ class LocalPlayer : public Being void event(const std::string &channel, const Mana::Event &event); /** - * Tells the engine whether to check + * Tells the engine wether to check * if the Player Name is to be displayed. */ void setCheckNameSetting(bool checked) { mUpdateName = checked; } @@ -224,6 +230,8 @@ class LocalPlayer : public Being /** Queued messages*/ std::list<MessagePair> mMessages; int mMessageTime; + + bool mShowIp; }; extern LocalPlayer *player_node; @@ -55,7 +55,7 @@ #elif defined WIN32 #include "winver.h" #elif defined __APPLE__ -#define PACKAGE_VERSION "1.0.0" +#define PACKAGE_VERSION "0.5.0" #endif #ifdef PACKAGE_VERSION diff --git a/src/mana-ea.rc b/src/mana-ea.rc deleted file mode 100644 index 12068ea2..00000000 --- a/src/mana-ea.rc +++ /dev/null @@ -1,23 +0,0 @@ -#include <windows.h> // include for version info constants - -#include "winver.h" - -A ICON MOVEABLE PURE LOADONCALL DISCARDABLE "../data/icons/mana.ico" - -1 VERSIONINFO -FILEVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD -PRODUCTVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD -//FILETYPE VFT_APP -{ - BLOCK "StringFileInfo" { - BLOCK "040904E4" { - VALUE "CompanyName", "The Mana Development Team" - VALUE "FileVersion", PACKAGE_VERSION - VALUE "FileDescription", "Mana (Eathena)" - VALUE "LegalCopyright", "2004-2010 (C)" - VALUE "OriginalFilename", "mana-ea.exe" - VALUE "ProductName", "Mana MMORPG Client" - VALUE "ProductVersion", PACKAGE_VERSION - } - } -} diff --git a/src/map.cpp b/src/map.cpp index 367083b6..ea5cc976 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -390,22 +390,26 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY) } } - // Draws beings with a lower opacity to make them visible - // even when covered by a wall or some other elements... - Actors::const_iterator ai = mActors.begin(); - while (ai != mActors.end()) + // If the transparency hasn't been disabled, + if (Image::useOpenGL() || !Image::SDLisTransparencyDisabled()) { - if (Actor *actor = *ai) + // We draw beings with a lower opacity to make them visible + // even when covered by a wall or some other elements... + Actors::const_iterator ai = mActors.begin(); + while (ai != mActors.end()) { - // For now, just draw actors with only one layer. - if (actor->getNumberOfLayers() == 1) + if (Actor *actor = *ai) { - actor->setAlpha(0.3f); - actor->draw(graphics, -scrollX, -scrollY); - actor->setAlpha(1.0f); + // For now, just draw actors with only one layer. + if (actor->getNumberOfLayers() == 1) + { + actor->setAlpha(0.3f); + actor->draw(graphics, -scrollX, -scrollY); + actor->setAlpha(1.0f); + } } + ai++; } - ai++; } drawAmbientLayers(graphics, FOREGROUND_LAYERS, scrollX, scrollY, diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp index 6a5adbe1..3c3e9edf 100644 --- a/src/net/messagein.cpp +++ b/src/net/messagein.cpp @@ -97,6 +97,9 @@ void MessageIn::readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction) case 7: direction = 9; break; + case 8: + direction = 8; + break; default: // OOPSIE! Impossible or unknown direction = 0; diff --git a/src/net/net.cpp b/src/net/net.cpp index 7e7395a6..25dcd981 100644 --- a/src/net/net.cpp +++ b/src/net/net.cpp @@ -134,12 +134,16 @@ void connectToServer(ServerInfo &server) // TODO: Query the server about itself and choose the netcode based on // that +#ifndef MANASERV_SUPPORT + server.type = ServerInfo::TMWATHENA; +#else if (server.port == 6901) server.type = ServerInfo::TMWATHENA; else if (server.port == 9601) server.type = ServerInfo::MANASERV; else logger->error(_("Unknown Server Type! Exiting.")); +#endif } if (networkType == server.type && getGeneralHandler() != NULL) diff --git a/src/net/tmwa/adminhandler.cpp b/src/net/tmwa/adminhandler.cpp index b72c2a13..2795df8a 100644 --- a/src/net/tmwa/adminhandler.cpp +++ b/src/net/tmwa/adminhandler.cpp @@ -43,8 +43,10 @@ namespace TmwAthena { AdminHandler::AdminHandler() { - static const Uint16 _messages[] = { + static const Uint16 _messages[] = + { SMSG_ADMIN_KICK_ACK, + SMSG_ADMIN_IP, 0 }; handledMessages = _messages; @@ -63,6 +65,13 @@ void AdminHandler::handleMessage(Net::MessageIn &msg) else SERVER_NOTICE(_("Kick succeeded!")) break; + case SMSG_ADMIN_IP: + id = msg.readInt32(); + int ip = msg.readInt32(); + Being *player = actorSpriteManager->findBeing(id); + player->setIp(ip); + player->updateName(); + break; } } diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp index 332ac548..d6ba816b 100644 --- a/src/net/tmwa/beinghandler.cpp +++ b/src/net/tmwa/beinghandler.cpp @@ -44,7 +44,8 @@ const int EMOTION_TIME = 150; /**< Duration of emotion icon */ BeingHandler::BeingHandler(bool enableSync): mSync(enableSync) { - static const Uint16 _messages[] = { + static const Uint16 _messages[] = + { SMSG_BEING_VISIBLE, SMSG_BEING_MOVE, SMSG_BEING_SPAWN, @@ -354,7 +355,8 @@ void BeingHandler::handleMessage(Net::MessageIn &msg) } break; - case SMSG_BEING_SELFEFFECT: { + case SMSG_BEING_SELFEFFECT: + { id = (Uint32)msg.readInt32(); Being* being = actorSpriteManager->findBeing(id); if (!being) @@ -562,7 +564,6 @@ void BeingHandler::handleMessage(Net::MessageIn &msg) msg.readCoordinatePair(srcX, srcY, dstX, dstY); dstBeing->setTileCoords(srcX, srcY); dstBeing->setDestination(dstX, dstY); - } else { diff --git a/src/net/tmwa/gui/partytab.cpp b/src/net/tmwa/gui/partytab.cpp index d5781971..6833831c 100644 --- a/src/net/tmwa/gui/partytab.cpp +++ b/src/net/tmwa/gui/partytab.cpp @@ -42,7 +42,7 @@ namespace TmwAthena { PartyTab::PartyTab() : ChatTab(_("Party")) { - setTabColor(&Theme::getThemeColor(Theme::PARTY)); + setTabColor(&Theme::getThemeColor(Theme::PARTY_CHAT_TAB)); } PartyTab::~PartyTab() diff --git a/src/net/tmwa/guildhandler.cpp b/src/net/tmwa/guildhandler.cpp index 39d49bc7..1ff2f22a 100644 --- a/src/net/tmwa/guildhandler.cpp +++ b/src/net/tmwa/guildhandler.cpp @@ -44,6 +44,7 @@ Guild *taGuild; GuildHandler::GuildHandler() { static const Uint16 _messages[] = { +/* SMSG_GUILD_CREATE_RESPONSE, SMSG_GUILD_POSITION_INFO, SMSG_GUILD_MEMBER_LOGIN, @@ -70,6 +71,7 @@ GuildHandler::GuildHandler() SMSG_GUILD_DEL_ALLIANCE, SMSG_GUILD_OPPOSITION_ACK, SMSG_GUILD_BROKEN, +*/ 0 }; handledMessages = _messages; diff --git a/src/net/tmwa/network.cpp b/src/net/tmwa/network.cpp index aff19b11..4d2073a0 100644 --- a/src/net/tmwa/network.cpp +++ b/src/net/tmwa/network.cpp @@ -77,8 +77,8 @@ short packet_lengths[] = { 8, 14, 10, 35, 6, 8, 4, 11, 54, 53, 60, 2, -1, 47, 33, 6, 30, 8, 34, 14, 2, 6, 26, 2, 28, 81, 6, 10, 26, 2, -1, -1, -1, -1, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56, -1, 4, 5, 10, -// #0x2000 - 26, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, +// #0x0200 + 26, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 19, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp index ca42a5c9..970d1ecd 100644 --- a/src/net/tmwa/playerhandler.cpp +++ b/src/net/tmwa/playerhandler.cpp @@ -159,6 +159,9 @@ PlayerHandler::PlayerHandler() void PlayerHandler::handleMessage(Net::MessageIn &msg) { + if (!player_node) + return; + switch (msg.getId()) { case SMSG_WALK_RESPONSE: diff --git a/src/net/tmwa/protocol.h b/src/net/tmwa/protocol.h index 21d562bc..0a768d5d 100644 --- a/src/net/tmwa/protocol.h +++ b/src/net/tmwa/protocol.h @@ -181,6 +181,7 @@ static const int STORAGE_OFFSET = 1; #define SMSG_PLAYER_STORAGE_CLOSE 0x00f8 /**< Storage access closed */ #define SMSG_ADMIN_KICK_ACK 0x00cd +#define SMSG_ADMIN_IP 0x020c #define SMSG_GUILD_CREATE_RESPONSE 0x0167 #define SMSG_GUILD_POSITION_INFO 0x016c diff --git a/src/particle.cpp b/src/particle.cpp index cb2faa77..f147a9f2 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -185,7 +185,8 @@ bool Particle::update() { mAlive = DEAD_FLOOR; } - } else if (mPos.z > PARTICLE_SKY) + } + else if (mPos.z > PARTICLE_SKY) { mAlive = DEAD_SKY; } @@ -431,6 +432,19 @@ void Particle::adjustEmitterSize(int w, int h) } } +float Particle::getCurrentAlpha() const +{ + float alpha = mAlpha; + + if (mLifetimeLeft > -1 && mLifetimeLeft < mFadeOut) + alpha *= (float)mLifetimeLeft / (float)mFadeOut; + + if (mLifetimePast < mFadeIn) + alpha *= (float)mLifetimePast / (float)mFadeIn; + + return alpha; +} + void Particle::clear() { delete_all(mChildEmitters); diff --git a/src/particle.h b/src/particle.h index 8aa9e5f2..0e39883b 100644 --- a/src/particle.h +++ b/src/particle.h @@ -266,7 +266,12 @@ class Particle : public Actor { mDeathEffect = effectFile; mDeathEffectConditions = conditions; } protected: - float mAlpha; /**< Opacity of the graphical representation of the particle */ + /** Opacity of the graphical representation of the particle */ + float mAlpha; + + /** Calculates the current alpha transparency taking current fade status into account*/ + float getCurrentAlpha() const; + int mLifetimeLeft; /**< Lifetime left in game ticks*/ int mLifetimePast; /**< Age of the particle in game ticks*/ int mFadeOut; /**< Lifetime in game ticks left where fading out begins*/ diff --git a/src/resources/ambientlayer.cpp b/src/resources/ambientlayer.cpp index 50fe8bd9..b662ddeb 100644 --- a/src/resources/ambientlayer.cpp +++ b/src/resources/ambientlayer.cpp @@ -33,7 +33,7 @@ AmbientLayer::AmbientLayer(Image *img, float parallax, mKeepRatio(keepRatio) { - if (keepRatio && !mImage->isAnOpenGLOne() + if (keepRatio && !mImage->useOpenGL() && defaultScreenWidth != 0 && defaultScreenHeight != 0 && graphics->getWidth() != defaultScreenWidth @@ -92,7 +92,7 @@ void AmbientLayer::update(int timePassed, float dx, float dy) void AmbientLayer::draw(Graphics *graphics, int x, int y) { - if (!mImage->isAnOpenGLOne() || !mKeepRatio) + if (!mImage->useOpenGL() || !mKeepRatio) graphics->drawImagePattern(mImage, (int) -mPosX, (int) -mPosY, x + (int) mPosX, y + (int) mPosY); else diff --git a/src/resources/ambientoverlay.cpp b/src/resources/ambientoverlay.cpp index 64a46676..aba12f84 100644 --- a/src/resources/ambientoverlay.cpp +++ b/src/resources/ambientoverlay.cpp @@ -34,7 +34,7 @@ AmbientOverlay::AmbientOverlay(Image *img, float parallax, mKeepRatio(keepRatio) { - if (keepRatio && !mImage->isAnOpenGLOne() + if (keepRatio && !mImage->useOpenGL() && defaultScreenWidth != 0 && defaultScreenHeight != 0 && graphics->getWidth() != defaultScreenWidth @@ -92,7 +92,7 @@ void AmbientOverlay::update(int timePassed, float dx, float dy) void AmbientOverlay::draw(Graphics *graphics, int x, int y) { - if (!mImage->isAnOpenGLOne() || !mKeepRatio) + if (!mImage->useOpenGL() || !mKeepRatio) graphics->drawImagePattern(mImage, (int) -mPosX, (int) -mPosY, x + (int) mPosX, y + (int) mPosY); else diff --git a/src/resources/image.cpp b/src/resources/image.cpp index 82799bce..63f1bd2c 100644 --- a/src/resources/image.cpp +++ b/src/resources/image.cpp @@ -22,12 +22,14 @@ #include "resources/image.h" #include "resources/dye.h" +#include "resources/resourcemanager.h" #ifdef USE_OPENGL #include "openglgraphics.h" #endif #include "log.h" +#include "configuration.h" #include <SDL_image.h> #include <SDL_rotozoom.h> @@ -37,17 +39,23 @@ bool Image::mUseOpenGL = false; int Image::mTextureType = 0; int Image::mTextureSize = 0; #endif +bool Image::mEnableAlphaCache = false; + +// The low CPU mode is disabled per default +bool Image::mDisableTransparency = false; Image::Image(SDL_Surface *image, bool hasAlphaChannel, Uint8 *alphaChannel): mAlpha(1.0f), - mHasAlphaChannel(hasAlphaChannel), mSDLSurface(image), - mAlphaChannel(alphaChannel) + mAlphaChannel(alphaChannel), + mHasAlphaChannel(hasAlphaChannel) { #ifdef USE_OPENGL mGLImage = 0; #endif + mUseAlphaCache = Image::mEnableAlphaCache; + mBounds.x = 0; mBounds.y = 0; @@ -68,9 +76,10 @@ Image::Image(SDL_Surface *image, bool hasAlphaChannel, Uint8 *alphaChannel): #ifdef USE_OPENGL Image::Image(GLuint glimage, int width, int height, int texWidth, int texHeight): mAlpha(1.0f), - mHasAlphaChannel(true), mSDLSurface(0), mAlphaChannel(0), + mHasAlphaChannel(true), + mUseAlphaCache(false), mGLImage(glimage), mTexWidth(texWidth), mTexHeight(texHeight) @@ -166,12 +175,28 @@ Image *Image::load(SDL_Surface *tmpImage) return _SDLload(tmpImage); } +void Image::SDLcleanCache() +{ + ResourceManager *resman = ResourceManager::getInstance(); + + for (std::map<float, SDL_Surface*>::iterator + i = mAlphaCache.begin(), i_end = mAlphaCache.end(); + i != i_end; ++i) + { + if (mSDLSurface != i->second) + resman->scheduleDelete(i->second); + i->second = 0; + } + mAlphaCache.clear(); +} + void Image::unload() { mLoaded = false; if (mSDLSurface) { + SDLcleanCache(); // Free the image surface. SDL_FreeSurface(mSDLSurface); mSDLSurface = NULL; @@ -189,7 +214,7 @@ void Image::unload() #endif } -bool Image::isAnOpenGLOne() const +bool Image::useOpenGL() { #ifdef USE_OPENGL return mUseOpenGL; @@ -200,29 +225,64 @@ bool Image::isAnOpenGLOne() const bool Image::hasAlphaChannel() { - if (mLoaded) - return mHasAlphaChannel; + if (!mLoaded) + return false; #ifdef USE_OPENGL if (mUseOpenGL) return true; #endif - return false; + return mHasAlphaChannel; +} + +SDL_Surface *Image::getByAlpha(float alpha) +{ + std::map<float, SDL_Surface*>::iterator it = mAlphaCache.find(alpha); + if (it != mAlphaCache.end()) + return (*it).second; + return 0; } void Image::setAlpha(float alpha) { + if (!useOpenGL() && mDisableTransparency) + return; + if (mAlpha == alpha) return; if (alpha < 0.0f || alpha > 1.0f) return; - mAlpha = alpha; - if (mSDLSurface) { + if (mUseAlphaCache) + { + SDL_Surface *surface = getByAlpha(mAlpha); + if (!surface) + { + if (mAlphaCache.size() > 100) + SDLcleanCache(); + + mAlphaCache[mAlpha] = mSDLSurface; + } + surface = getByAlpha(alpha); + if (surface) + { + mAlphaCache.erase(alpha); + mSDLSurface = surface; + mAlpha = alpha; + return; + } + else + { + mSDLSurface = Image::SDLduplicateSurface(mSDLSurface); + } + } + + mAlpha = alpha; + if (!hasAlphaChannel()) { // Set the alpha value this image is drawn at @@ -263,6 +323,10 @@ void Image::setAlpha(float alpha) SDL_UnlockSurface(mSDLSurface); } } + else + { + mAlpha = alpha; + } } Image* Image::SDLmerge(Image *image, int x, int y) @@ -371,6 +435,14 @@ Image* Image::SDLgetScaledImage(int width, int height) return scaledImage; } +SDL_Surface* Image::SDLduplicateSurface(SDL_Surface* tmpImage) +{ + if (!tmpImage || !tmpImage->format) + return NULL; + + return SDL_ConvertSurface(tmpImage, tmpImage->format, SDL_SWSURFACE); +} + Image *Image::_SDLload(SDL_Surface *tmpImage) { if (!tmpImage) @@ -560,25 +632,40 @@ Image *Image::getSubImage(int x, int y, int width, int height) return new SubImage(this, mSDLSurface, x, y, width, height); } +void Image::SDLterminateAlphaCache() +{ + SDLcleanCache(); + mUseAlphaCache = false; +} + //============================================================================ // SubImage Class //============================================================================ SubImage::SubImage(Image *parent, SDL_Surface *image, - int x, int y, int width, int height): + int x, int y, int width, int height): Image(image), mParent(parent) { - mParent->incRef(); - - mHasAlphaChannel = mParent->hasAlphaChannel(); - mAlphaChannel = mParent->SDLgetAlphaChannel(); + if (mParent) + { + mParent->incRef(); + mParent->SDLterminateAlphaCache(); + mHasAlphaChannel = mParent->hasAlphaChannel(); + mAlphaChannel = mParent->SDLgetAlphaChannel(); + } + else + { + mHasAlphaChannel = false; + mAlphaChannel = 0; + } // Set up the rectangle. mBounds.x = x; mBounds.y = y; mBounds.w = width; mBounds.h = height; + mUseAlphaCache = false; } #ifdef USE_OPENGL diff --git a/src/resources/image.h b/src/resources/image.h index 3e8ad551..1db52ca0 100644 --- a/src/resources/image.h +++ b/src/resources/image.h @@ -39,6 +39,8 @@ #include <SDL_opengl.h> #endif +#include <map> + class Dye; class Position; @@ -111,16 +113,10 @@ class Image : public Resource { return mBounds.h; } /** - * Tells if the image was loaded using OpenGL or SDL + * Tells if the system is using OpenGL or SDL * @return true if OpenGL, false if SDL. */ - bool isAnOpenGLOne() const; - - /** - * Tells if the image has got an alpha channel - * @return true if it's true, false otherwise. - */ - bool hasAlphaChannel(); + static bool useOpenGL(); /** * Sets the alpha value of this image. @@ -141,10 +137,24 @@ class Image : public Resource */ virtual Image *getSubImage(int x, int y, int width, int height); + /** + * Tells if the image has got an alpha channel + * @return true if it's true, false otherwise. + */ + bool hasAlphaChannel(); // SDL only public functions /** + * Disable the transparency handling (for low CPUs in SDL Mode) + */ + static void SDLdisableTransparency() + { mDisableTransparency = true; } + + static bool SDLisTransparencyDisabled() + { return mDisableTransparency; } + + /** * Gets an scaled instance of an image. * * @param width The desired width of the scaled image. @@ -169,6 +179,15 @@ class Image : public Resource Uint8 *SDLgetAlphaChannel() const { return mAlphaChannel; } + SDL_Surface* SDLduplicateSurface(SDL_Surface* tmpImage); + + void SDLcleanCache(); + + void SDLterminateAlphaCache(); + + static void SDLsetEnableAlphaCache(bool n) + { mEnableAlphaCache = n; } + #ifdef USE_OPENGL // OpenGL only public functions @@ -188,18 +207,17 @@ class Image : public Resource protected: - // ----------------------- - // Generic protected members - // ----------------------- + // ----------------------- + // Generic protected members + // ----------------------- SDL_Rect mBounds; bool mLoaded; float mAlpha; - bool mHasAlphaChannel; - // ----------------------- - // SDL protected members - // ----------------------- + // ----------------------- + // SDL protected members + // ----------------------- /** SDL Constructor */ Image(SDL_Surface *image, bool hasAlphaChannel = false, @@ -208,14 +226,27 @@ class Image : public Resource /** SDL_Surface to SDL_Surface Image loader */ static Image *_SDLload(SDL_Surface *tmpImage); + SDL_Surface *getByAlpha(float alpha); + SDL_Surface *mSDLSurface; /** Alpha Channel pointer used for 32bit based SDL surfaces */ Uint8 *mAlphaChannel; + bool mHasAlphaChannel; + + /** Alpha cache: The cache stores a copy of the image + for specific requested opacities, hence, increasing + the image disply speed */ + std::map<float, SDL_Surface*> mAlphaCache; + bool mUseAlphaCache; + static bool mEnableAlphaCache; + + /** Stores whether the transparency is disabled */ + static bool mDisableTransparency; - // ----------------------- - // OpenGL protected members - // ----------------------- + // ----------------------- + // OpenGL protected members + // ----------------------- #ifdef USE_OPENGL /** * OpenGL Constructor. diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index c63b626e..00e4726e 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -533,3 +533,18 @@ SDL_Surface *ResourceManager::loadSDLSurface(const std::string &filename) return tmp; } + +void ResourceManager::scheduleDelete(SDL_Surface* surface) +{ + mDeletedSurfaces.insert(surface); +} + +void ResourceManager::clearScheduled() +{ + for (std::set<SDL_Surface*>::iterator i = mDeletedSurfaces.begin(), + i_end = mDeletedSurfaces.end(); i != i_end; ++i) + { + SDL_FreeSurface(*i); + } + mDeletedSurfaces.clear(); +} diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h index 28ab4725..870182e4 100644 --- a/src/resources/resourcemanager.h +++ b/src/resources/resourcemanager.h @@ -26,6 +26,7 @@ #include <map> #include <string> #include <vector> +#include <set> class Image; class ImageSet; @@ -205,6 +206,10 @@ class ResourceManager */ SDL_Surface *loadSDLSurface(const std::string &filename); + void scheduleDelete(SDL_Surface* surface); + + void clearScheduled(); + /** * Returns an instance of the class, creating one if it does not * already exist. @@ -227,6 +232,7 @@ class ResourceManager static ResourceManager *instance; typedef std::map<std::string, Resource*> Resources; typedef Resources::iterator ResourceIterator; + std::set<SDL_Surface*> mDeletedSurfaces; Resources mResources; Resources mOrphanedResources; time_t mOldestOrphan; diff --git a/src/resources/theme.cpp b/src/resources/theme.cpp index 0316b0bf..aa28af36 100644 --- a/src/resources/theme.cpp +++ b/src/resources/theme.cpp @@ -398,6 +398,8 @@ static int readColorType(const std::string &type) "BUTTON", "BUTTON_DISABLED", "TAB", + "PARTY_CHAT_TAB", + "PARTY_SOCIAL_TAB", "BACKGROUND", "HIGHLIGHT", "TAB_FLASH", diff --git a/src/resources/theme.h b/src/resources/theme.h index 6798bed5..3a5aa41a 100644 --- a/src/resources/theme.h +++ b/src/resources/theme.h @@ -127,6 +127,8 @@ class Theme : public Palette, public ConfigListener BUTTON, BUTTON_DISABLED, TAB, + PARTY_CHAT_TAB, + PARTY_SOCIAL_TAB, BACKGROUND, HIGHLIGHT, TAB_FLASH, diff --git a/src/resources/userpalette.cpp b/src/resources/userpalette.cpp index 5067c794..a6b5bc03 100644 --- a/src/resources/userpalette.cpp +++ b/src/resources/userpalette.cpp @@ -33,21 +33,24 @@ #include <math.h> const std::string ColorTypeNames[] = { - "Being", - "Player", - "Self", - "GM", - "NPC", - "Monster", - "Party", - "Guild", - "Particle", - "Experience", - "Pickup", - "Hit Player Monster", - "Hit Monster Player", - "Hit Critical", - "Miss" + "ColorBeing", + "ColorPlayer", + "ColorSelf", + "ColorGM", + "ColorNPC", + "ColorMonster", + "ColorParty", + "ColorGuild", + "ColorParticle", + "ColorExperience", + "ColorPickup", + "ColorHitPlayerMonster", + "ColorHitMonsterPlayer", + "ColorHitCritical", + "ColorHitLocalPlayerMonster", + "ColorHitLocalPlayerCritical", + "ColorHitLocalPlayerMiss", + "ColorMiss" }; std::string UserPalette::getConfigName(const std::string &typeName) @@ -96,9 +99,16 @@ UserPalette::UserPalette(): addColor(PARTICLE, 0xffffff, STATIC, _("Particle Effects")); addColor(PICKUP_INFO, 0x28dc28, STATIC, _("Pickup Notification")); addColor(EXP_INFO, 0xffff00, STATIC, _("Exp Notification")); - addColor(HIT_PLAYER_MONSTER, 0x0064ff, STATIC, _("Player Hits Monster")); + addColor(HIT_PLAYER_MONSTER, 0x0064ff, STATIC, + _("Other Player Hits Monster")); addColor(HIT_MONSTER_PLAYER, 0xff3232, STATIC, _("Monster Hits Player")); addColor(HIT_CRITICAL, 0xff0000, RAINBOW, _("Critical Hit")); + addColor(HIT_LOCAL_PLAYER_MONSTER, 0x00ff00, STATIC, + _("Local Player Hits Monster")); + addColor(HIT_LOCAL_PLAYER_CRITICAL, 0xff0000, RAINBOW, + _("Local Player Critical Hit")); + addColor(HIT_LOCAL_PLAYER_MISS, 0x00ffa6, STATIC, + _("Local Player Miss")); addColor(MISS, 0xffff00, STATIC, _("Misses")); commit(true); } diff --git a/src/resources/userpalette.h b/src/resources/userpalette.h index 82bcea1c..be02db10 100644 --- a/src/resources/userpalette.h +++ b/src/resources/userpalette.h @@ -49,6 +49,9 @@ class UserPalette : public Palette, public gcn::ListModel HIT_PLAYER_MONSTER, HIT_MONSTER_PLAYER, HIT_CRITICAL, + HIT_LOCAL_PLAYER_MONSTER, + HIT_LOCAL_PLAYER_CRITICAL, + HIT_LOCAL_PLAYER_MISS, MISS, USER_COLOR_LAST }; diff --git a/src/textparticle.cpp b/src/textparticle.cpp index e8d99dca..0753cc38 100644 --- a/src/textparticle.cpp +++ b/src/textparticle.cpp @@ -44,16 +44,8 @@ bool TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const int screenX = (int) mPos.x + offsetX; int screenY = (int) mPos.y - (int) mPos.z + offsetY; - float alpha = mAlpha * 255.0f; - - if (mLifetimeLeft > -1 && mLifetimeLeft < mFadeOut) - alpha = alpha * mLifetimeLeft / mFadeOut; - - if (mLifetimePast < mFadeIn) - alpha = alpha * mLifetimePast / mFadeIn; - gcn::Color color = *mColor; - color.a = (int)alpha; + color.a = getCurrentAlpha() * 255; TextRenderer::renderText(graphics, mText, screenX, screenY, gcn::Graphics::CENTER, diff --git a/src/winver.h b/src/winver.h index 03a0c215..ea8d8e9c 100644 --- a/src/winver.h +++ b/src/winver.h @@ -1,6 +1,6 @@ /* VERSION DEFINITIONS */ #define VER_MAJOR 0 -#define VER_MINOR 1 +#define VER_MINOR 5 #define VER_RELEASE 0 #define VER_BUILD 0 -#define PACKAGE_VERSION "0.1.0.0" +#define PACKAGE_VERSION "0.5.0.0" |