diff options
Diffstat (limited to 'src/game.cpp')
-rw-r--r-- | src/game.cpp | 654 |
1 files changed, 454 insertions, 200 deletions
diff --git a/src/game.cpp b/src/game.cpp index 942c517c..cf1aa220 100644 --- a/src/game.cpp +++ b/src/game.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 "game.h" - #include <fstream> #include <physfs.h> #include <sstream> @@ -29,11 +27,16 @@ #include <guichan/exception.hpp> #include "beingmanager.h" +#ifdef TMWSERV_SUPPORT #include "channelmanager.h" #include "commandhandler.h" +#endif #include "configuration.h" +#include "effectmanager.h" +#include "emoteshortcut.h" #include "engine.h" #include "flooritemmanager.h" +#include "game.h" #include "graphics.h" #include "itemshortcut.h" #include "joystick.h" @@ -42,30 +45,29 @@ #include "log.h" #include "npc.h" #include "particle.h" -#include "effectmanager.h" +#include "player_relations.h" -#include "gui/buddywindow.h" #include "gui/buy.h" #include "gui/buysell.h" #include "gui/chat.h" #include "gui/confirm_dialog.h" #include "gui/debugwindow.h" +#include "gui/emoteshortcutcontainer.h" +#include "gui/emotewindow.h" #include "gui/equipmentwindow.h" #include "gui/gui.h" -#include "gui/guildwindow.h" #include "gui/help.h" #include "gui/inventorywindow.h" -#include "gui/itemshortcutwindow.h" -#include "gui/magic.h" +#include "gui/shortcutwindow.h" +#include "gui/itemshortcutcontainer.h" #include "gui/menuwindow.h" #include "gui/minimap.h" #include "gui/ministatus.h" +#include "gui/npcintegerdialog.h" #include "gui/npclistdialog.h" -#include "gui/npcpostdialog.h" +#include "gui/npcstringdialog.h" #include "gui/npc_text.h" #include "gui/ok_dialog.h" -#include "gui/partywindow.h" -#include "gui/quitdialog.h" #include "gui/sdlinput.h" #include "gui/sell.h" #include "gui/setup.h" @@ -73,23 +75,42 @@ #include "gui/status.h" #include "gui/trade.h" #include "gui/viewport.h" +#ifdef TMWSERV_SUPPORT +#include "gui/buddywindow.h" +#include "gui/guildwindow.h" +#include "gui/magic.h" +#include "gui/npcpostdialog.h" +#include "gui/partywindow.h" +#include "gui/quitdialog.h" +#endif -#include "net/beinghandler.h" -#include "net/buysellhandler.h" #include "net/chathandler.h" -#include "net/guildhandler.h" -#include "net/inventoryhandler.h" #include "net/itemhandler.h" -#include "net/network.h" #include "net/npchandler.h" -#include "net/partyhandler.h" #include "net/playerhandler.h" #include "net/tradehandler.h" +#ifdef TMWSERV_SUPPORT +#include "net/network.h" +#include "net/beinghandler.h" +#include "net/buysellhandler.h" #include "net/effecthandler.h" +#include "net/guildhandler.h" +#include "net/inventoryhandler.h" +#include "net/partyhandler.h" +#else +#include "net/ea/network.h" +#include "net/ea/beinghandler.h" +#include "net/ea/buysellhandler.h" +#include "net/ea/equipmenthandler.h" +#include "net/ea/inventoryhandler.h" +#include "net/ea/protocol.h" +#include "net/ea/skillhandler.h" +#include "net/messageout.h" +#endif #include "resources/imagewriter.h" -extern Graphics *graphics; +#include "utils/gettext.h" class Map; @@ -98,12 +119,17 @@ std::string map_path; bool done = false; volatile int tick_time; volatile int fps = 0, frame = 0; + Engine *engine = NULL; Joystick *joystick = NULL; extern Window *weightNotice; extern Window *deathNotice; +#ifdef TMWSERV_SUPPORT QuitDialog *quitDialog = NULL; +#else +ConfirmDialog *exitConfirm = NULL; +#endif OkDialog *disconnectedDialog = NULL; ChatWindow *chatWindow; @@ -114,34 +140,41 @@ BuyDialog *buyDialog; SellDialog *sellDialog; BuySellDialog *buySellDialog; InventoryWindow *inventoryWindow; +EmoteWindow *emoteWindow; +NpcIntegerDialog *npcIntegerDialog; NpcListDialog *npcListDialog; NpcTextDialog *npcTextDialog; -NpcPostDialog *npcPostDialog; +NpcStringDialog *npcStringDialog; SkillDialog *skillDialog; +#ifdef TMWSERV_SUPPORT +BuddyWindow *buddyWindow; +GuildWindow *guildWindow; MagicDialog *magicDialog; +NpcPostDialog *npcPostDialog; +PartyWindow *partyWindow; +#endif Setup* setupWindow; Minimap *minimap; EquipmentWindow *equipmentWindow; TradeWindow *tradeWindow; -BuddyWindow *buddyWindow; -GuildWindow *guildWindow; HelpWindow *helpWindow; DebugWindow *debugWindow; -ItemShortcutWindow *itemShortcutWindow; -PartyWindow *partyWindow; +ShortcutWindow *itemShortcutWindow; +ShortcutWindow *emoteShortcutWindow; BeingManager *beingManager = NULL; FloorItemManager *floorItemManager = NULL; +#ifdef TMWSERV_SUPPORT ChannelManager *channelManager = NULL; CommandHandler *commandHandler = NULL; +#endif +Particle* particleEngine = NULL; EffectManager *effectManager = NULL; -Particle *particleEngine = NULL; - const int MAX_TIME = 10000; /** - * Listener used for exitting handling. + * Listener used for exiting handling. */ namespace { struct ExitListener : public gcn::ActionListener @@ -151,6 +184,9 @@ namespace { if (event.getId() == "yes" || event.getId() == "ok") { done = true; } +#ifdef EATHENA_SUPPORT + exitConfirm = NULL; +#endif disconnectedDialog = NULL; } } exitListener; @@ -173,15 +209,18 @@ Uint32 nextSecond(Uint32 interval, void *param) { fps = frame; frame = 0; + return interval; } int get_elapsed_time(int start_time) { - if (start_time <= tick_time) { + if (start_time <= tick_time) + { return (tick_time - start_time) * 10; } - else { + else + { return (tick_time + (MAX_TIME - start_time)) * 10; } } @@ -189,49 +228,67 @@ int get_elapsed_time(int start_time) /** * Create all the various globally accessible gui windows */ +#ifdef TMWSERV_SUPPORT void createGuiWindows() +#else +void createGuiWindows(Network *network) +#endif { // Create dialogs +#ifdef TMWSERV_SUPPORT chatWindow = new ChatWindow; - menuWindow = new MenuWindow(); - statusWindow = new StatusWindow(player_node); - miniStatusWindow = new MiniStatusWindow(); buyDialog = new BuyDialog; sellDialog = new SellDialog; - buySellDialog = new BuySellDialog(); - inventoryWindow = new InventoryWindow(); - npcTextDialog = new NpcTextDialog(); - npcListDialog = new NpcListDialog(); + tradeWindow = new TradeWindow; npcPostDialog = new NpcPostDialog(); - skillDialog = new SkillDialog(); magicDialog = new MagicDialog(); - setupWindow = new Setup(); - minimap = new Minimap(); equipmentWindow = new EquipmentWindow(player_node->mEquipment.get()); - tradeWindow = new TradeWindow; buddyWindow = new BuddyWindow(); guildWindow = new GuildWindow(); - helpWindow = new HelpWindow(); - debugWindow = new DebugWindow(); - itemShortcutWindow = new ItemShortcutWindow(); partyWindow = new PartyWindow(); - - // Initialize window positions - //buddyWindow->setPosition(10, minimap->getHeight() + 30); +#else + chatWindow = new ChatWindow(network); + buyDialog = new BuyDialog(network); + sellDialog = new SellDialog(network); + tradeWindow = new TradeWindow(network); + equipmentWindow = new EquipmentWindow; +#endif + menuWindow = new MenuWindow; + statusWindow = new StatusWindow(player_node); + miniStatusWindow = new MiniStatusWindow; + buySellDialog = new BuySellDialog; + inventoryWindow = new InventoryWindow; + emoteWindow = new EmoteWindow; + npcTextDialog = new NpcTextDialog; + npcIntegerDialog = new NpcIntegerDialog; + npcListDialog = new NpcListDialog; + npcStringDialog = new NpcStringDialog; + skillDialog = new SkillDialog; + setupWindow = new Setup; + minimap = new Minimap; + helpWindow = new HelpWindow; + debugWindow = new DebugWindow; + itemShortcutWindow = new ShortcutWindow("ItemShortcut",new ItemShortcutContainer); + emoteShortcutWindow = new ShortcutWindow("emoteShortcut",new EmoteShortcutContainer); // Set initial window visibility chatWindow->setVisible((bool) config.getValue( chatWindow->getWindowName() + "Visible", true)); miniStatusWindow->setVisible((bool) config.getValue( - miniStatusWindow->getWindowName() + "Visible", - true)); + miniStatusWindow->getWindowName() + "Visible", true)); buyDialog->setVisible(false); sellDialog->setVisible(false); + minimap->setVisible((bool) config.getValue( + minimap->getWindowName() + "Visible", true)); tradeWindow->setVisible(false); menuWindow->setVisible((bool) config.getValue( menuWindow->getWindowName() + "Visible", true)); itemShortcutWindow->setVisible((bool) config.getValue( itemShortcutWindow->getWindowName() + "Visible", true)); + emoteShortcutWindow->setVisible((bool) config.getValue( + emoteShortcutWindow->getWindowName() + "Visible", true)); + minimap->setVisible((bool) config.getValue( + minimap->getWindowName() + "Visible", true)); if (config.getValue("logToChat", 0)) { @@ -244,6 +301,7 @@ void createGuiWindows() */ void destroyGuiWindows() { + logger->setChatWindow(NULL); delete chatWindow; delete statusWindow; delete miniStatusWindow; @@ -252,47 +310,71 @@ void destroyGuiWindows() delete sellDialog; delete buySellDialog; delete inventoryWindow; + delete emoteWindow; + delete npcIntegerDialog; delete npcListDialog; delete npcTextDialog; + delete npcStringDialog; +#ifdef TMWSERV_SUPPORT delete npcPostDialog; - delete skillDialog; delete magicDialog; + delete buddyWindow; + delete guildWindow; + delete partyWindow; +#endif + delete skillDialog; delete setupWindow; delete minimap; delete equipmentWindow; delete tradeWindow; - delete buddyWindow; - delete guildWindow; delete helpWindow; delete debugWindow; delete itemShortcutWindow; - delete partyWindow; + delete emoteShortcutWindow; } +#ifdef TMWSERV_SUPPORT Game::Game(): mBeingHandler(new BeingHandler()), - mBuySellHandler(new BuySellHandler()), - mChatHandler(new ChatHandler()), mGuildHandler(new GuildHandler()), - mInventoryHandler(new InventoryHandler()), - mItemHandler(new ItemHandler()), - mNpcHandler(new NPCHandler()), mPartyHandler(new PartyHandler()), - mPlayerHandler(new PlayerHandler()), - mTradeHandler(new TradeHandler()), mEffectHandler(new EffectHandler()), +#else +Game::Game(Network *network): + mNetwork(network), + mBeingHandler(new BeingHandler(config.getValue("EnableSync", 0) == 1)), + mEquipmentHandler(new EquipmentHandler), + mSkillHandler(new SkillHandler), +#endif + mBuySellHandler(new BuySellHandler), + mChatHandler(new ChatHandler), + mInventoryHandler(new InventoryHandler), + mItemHandler(new ItemHandler), + mNpcHandler(new NPCHandler), + mPlayerHandler(new PlayerHandler), + mTradeHandler(new TradeHandler), mLogicCounterId(0), mSecondsCounterId(0) { done = false; +#ifdef TMWSERV_SUPPORT createGuiWindows(); engine = new Engine; beingManager = new BeingManager; - floorItemManager = new FloorItemManager(); +#else + createGuiWindows(network); + engine = new Engine(network); + + beingManager = new BeingManager(network); +#endif + + floorItemManager = new FloorItemManager; +#ifdef TMWSERV_SUPPORT channelManager = new ChannelManager(); commandHandler = new CommandHandler(); - effectManager = new EffectManager(); +#endif + effectManager = new EffectManager; particleEngine = new Particle(NULL); particleEngine->setupEngine(); @@ -308,6 +390,9 @@ Game::Game(): // Initialize beings beingManager->setPlayer(player_node); +#ifdef EATHENA_SUPPORT + player_node->setNetwork(network); +#endif Joystick::init(); // TODO: The user should be able to choose which one to use @@ -315,6 +400,7 @@ Game::Game(): if (Joystick::getNumberOfJoysticks() > 0) joystick = new Joystick(0); +#ifdef TMWSERV_SUPPORT Net::registerHandler(mBeingHandler.get()); Net::registerHandler(mBuySellHandler.get()); Net::registerHandler(mChatHandler.get()); @@ -326,19 +412,50 @@ Game::Game(): Net::registerHandler(mPlayerHandler.get()); Net::registerHandler(mTradeHandler.get()); Net::registerHandler(mEffectHandler.get()); +#else + network->registerHandler(mBeingHandler.get()); + network->registerHandler(mBuySellHandler.get()); + network->registerHandler(mChatHandler.get()); + network->registerHandler(mEquipmentHandler.get()); + network->registerHandler(mInventoryHandler.get()); + network->registerHandler(mItemHandler.get()); + network->registerHandler(mNpcHandler.get()); + network->registerHandler(mPlayerHandler.get()); + network->registerHandler(mSkillHandler.get()); + network->registerHandler(mTradeHandler.get()); + + /* + * To prevent the server from sending data before the client + * has initialized, I've modified it to wait for a "ping" + * from the client to complete its initialization + * + * Note: This only affects the latest eAthena version. This + * packet is handled by the older version, but its response + * is ignored by the client + */ + MessageOut msg(mNetwork); + msg.writeInt16(CMSG_CLIENT_PING); + msg.writeInt32(tick_time); + + engine->changeMap(map_path); +#endif } Game::~Game() { +#ifdef TMWSERV_SUPPORT Net::clearHandlers(); +#endif delete player_node; destroyGuiWindows(); delete beingManager; delete floorItemManager; +#ifdef TMWSERV_SUPPORT delete channelManager; delete commandHandler; +#endif delete joystick; delete particleEngine; delete engine; @@ -387,12 +504,12 @@ static bool saveScreenshot() if (success) { std::stringstream chatlogentry; - chatlogentry << "Screenshot saved to ~/" << filenameSuffix.str(); + chatlogentry << _("Screenshot saved to ~/") << filenameSuffix.str(); chatWindow->chatLog(chatlogentry.str(), BY_SERVER); } else { - chatWindow->chatLog("Saving screenshot failed!", BY_SERVER); + chatWindow->chatLog(_("Saving screenshot failed!"), BY_SERVER); logger->log("Error: could not save screenshot."); } @@ -438,7 +555,7 @@ void Game::logic() // Draw a frame if either frames are not limited or enough time has // passed since the last frame. if (!mMinFrameTime || - get_elapsed_time(mDrawTime / 10) > mMinFrameTime) + get_elapsed_time(mDrawTime / 10) > mMinFrameTime) { frame++; gui->draw(); @@ -461,20 +578,25 @@ void Game::logic() } // Handle network stuff +#ifdef TMWSERV_SUPPORT Net::flush(); - // TODO: Fix notification when the connection is lost - if (false /*!mNetwork->isConnected() */) +#else + mNetwork->flush(); + mNetwork->dispatchMessages(); + + if (!mNetwork->isConnected()) { if (!disconnectedDialog) { - disconnectedDialog = new OkDialog("Network Error", - "The connection to the server was lost, " - "the program will now quit"); + disconnectedDialog = new OkDialog(_("Network Error"), + _("The connection to the server was lost, " + "the program will now quit")); disconnectedDialog->addActionListener(&exitListener); disconnectedDialog->requestMoveToTop(); } } +#endif } } @@ -495,7 +617,7 @@ void Game::handleInput() gcn::Window *requestedWindow = NULL; if (setupWindow->isVisible() && - keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE) + keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE) { keyboard.setNewKey((int) event.key.keysym.sym); keyboard.callbackNewKey(); @@ -503,6 +625,7 @@ void Game::handleInput() return; } +#ifdef TMWSERV_SUPPORT // send straight to gui for certain windows if (npcPostDialog->isVisible()) { @@ -517,61 +640,118 @@ void Game::handleInput() } return; } +#endif - switch (event.key.keysym.sym) + // Mode switch to emotes + if (keyboard.isKeyActive(keyboard.KEY_EMOTE)) { - case SDLK_F1: - // In-game Help - if (helpWindow->isVisible()) - { - helpWindow->setVisible(false); - } - else - { - helpWindow->loadHelp("index"); - helpWindow->requestMoveToTop(); - } + // Emotions + int emotion = keyboard.getKeyEmoteOffset(event.key.keysym.sym); + if (emotion) + { + emoteShortcut->useEmote(emotion); used = true; - break; - - case SDLK_RETURN: - // Input chat window - if (chatWindow->isInputFocused() || - deathNotice != NULL || - weightNotice != NULL) - { - break; - } + return; + } + } + if (keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT) || + keyboard.isKeyActive(keyboard.KEY_OK)) + { + // Input chat window + if (!(chatWindow->isInputFocused() || + deathNotice || + weightNotice)) + { +#ifdef TMWSERV_SUPPORT // Don not focus chat input when quit dialog is active - if(quitDialog != NULL && quitDialog->isVisible()) - break; - + if (quitDialog != NULL && quitDialog->isVisible()) + continue; +#else + // Quit by pressing Enter if the exit confirm is there + if (exitConfirm && + keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT)) + done = true; +#endif // Close the Browser if opened - if (helpWindow->isVisible()) - { + else if (helpWindow->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) helpWindow->setVisible(false); - } // Close the config window, cancelling changes if opened - else if (setupWindow->isVisible()) - { + else if (setupWindow->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) setupWindow->action(gcn::ActionEvent(NULL, "cancel")); - } + // Submits the text and proceeds to the next dialog + else if (npcStringDialog->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) + npcStringDialog->action(gcn::ActionEvent(NULL, "ok")); + // Proceed to the next dialog option, or close the window + else if (npcTextDialog->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) + npcTextDialog->action(gcn::ActionEvent(NULL, "ok")); + // Choose the currently highlighted dialogue option + else if (npcListDialog->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) + npcListDialog->action(gcn::ActionEvent(NULL, "ok")); + // Submits the text and proceeds to the next dialog + else if (npcIntegerDialog->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) + npcIntegerDialog->action(gcn::ActionEvent(NULL, "ok")); /* else if (guildWindow->isVisible()) { // TODO: Check if a dialog is open and close it if so } */ - // Else, open the chat edit box - else + else if (!(keyboard.getKeyValue( + KeyboardConfig::KEY_TOGGLE_CHAT) == + keyboard.getKeyValue( + KeyboardConfig::KEY_OK) && + (helpWindow->isVisible() || + setupWindow->isVisible() || + npcStringDialog->isVisible() || + npcTextDialog->isVisible() || + npcListDialog->isVisible() || + npcIntegerDialog->isVisible()))) { chatWindow->requestChatFocus(); used = true; } + } + } + + const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); + switch (tKey) + { + case KeyboardConfig::KEY_SCROLL_CHAT_UP: + if (chatWindow->isVisible()) + { + chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL); + used = true; + } + break; + case KeyboardConfig::KEY_SCROLL_CHAT_DOWN: + if (chatWindow->isVisible()) + { + chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL); + used = true; + return; + } break; - // Quitting confirmation dialog - case SDLK_ESCAPE: + case KeyboardConfig::KEY_WINDOW_HELP: + // In-game Help + if (helpWindow->isVisible()) + helpWindow->setVisible(false); + else + { + helpWindow->loadHelp("index"); + helpWindow->requestMoveToTop(); + } + used = true; + break; + // Quitting confirmation dialog + case KeyboardConfig::KEY_QUIT: +#ifdef TMWSERV_SUPPORT if (!quitDialog) { quitDialog = new QuitDialog(&done, &quitDialog); @@ -581,37 +761,58 @@ void Game::handleInput() { quitDialog->action(gcn::ActionEvent(NULL, "cancel")); } +#else + if (!exitConfirm) + { + exitConfirm = new ConfirmDialog(_("Quit"), + _("Are you sure you " + "want to quit?")); + exitConfirm->addActionListener(&exitListener); + exitConfirm->requestMoveToTop(); + } + else + { + exitConfirm->action(gcn::ActionEvent(NULL, _("no"))); + } +#endif break; - default: break; } - if (keyboard.isEnabled() && !chatWindow->isInputFocused() - && !guildWindow->isWindowFocused()) + && !npcStringDialog->isInputFocused()) { const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); + // Do not activate shortcuts if tradewindow is visible if (!tradeWindow->isVisible()) { // Checks if any item shortcut is pressed. - for (int i = KeyboardConfig::KEY_SHORTCUT_0; - i <= KeyboardConfig::KEY_SHORTCUT_9; - i++) + for (int i = KeyboardConfig::KEY_SHORTCUT_1; + i <= KeyboardConfig::KEY_SHORTCUT_12; + i++) { - if (tKey == i && !used) { + if (tKey == i && !used) + { itemShortcut->useItem( - i - KeyboardConfig::KEY_SHORTCUT_0); + i - KeyboardConfig::KEY_SHORTCUT_1); break; } } } - switch (tKey) { + + switch (tKey) + { case KeyboardConfig::KEY_PICKUP: { +#ifdef TMWSERV_SUPPORT const Vector &pos = player_node->getPosition(); Uint16 x = (int) pos.x / 32; Uint16 y = (int) pos.y / 32; +#else + Uint16 x = player_node->mX; + Uint16 y = player_node->mY; +#endif FloorItem *item = floorItemManager->findByCoordinates(x, y); @@ -630,8 +831,8 @@ void Game::handleInput() default: break; } - item = - floorItemManager->findByCoordinates(x, y); + item = floorItemManager->findByCoordinates( + x, y); } if (item) @@ -640,35 +841,29 @@ void Game::handleInput() used = true; } break; - - case KeyboardConfig::KEY_ATTACK: - player_node->attack(); - used = true; - break; - case KeyboardConfig::KEY_SIT: // Player sit action player_node->toggleSit(); used = true; break; - case KeyboardConfig::KEY_HIDE_WINDOWS: - // Hide certain windows + // Hide certain windows if (!chatWindow->isInputFocused()) { statusWindow->setVisible(false); inventoryWindow->setVisible(false); + emoteWindow->setVisible(false); skillDialog->setVisible(false); - magicDialog->setVisible(false); setupWindow->setVisible(false); equipmentWindow->setVisible(false); helpWindow->setVisible(false); debugWindow->setVisible(false); +#ifdef TMWSERV_SUPPORT guildWindow->setVisible(false); buddyWindow->setVisible(false); +#endif } break; - case KeyboardConfig::KEY_WINDOW_STATUS: requestedWindow = statusWindow; break; @@ -682,6 +877,7 @@ void Game::handleInput() requestedWindow = skillDialog; break; case KeyboardConfig::KEY_WINDOW_MINIMAP: + minimap->toggle(); requestedWindow = minimap; break; case KeyboardConfig::KEY_WINDOW_CHAT: @@ -696,83 +892,55 @@ void Game::handleInput() case KeyboardConfig::KEY_WINDOW_DEBUG: requestedWindow = debugWindow; break; - } - } - - if (requestedWindow) - { - requestedWindow->setVisible(!requestedWindow->isVisible()); - if (requestedWindow->isVisible()) - { - requestedWindow->requestMoveToTop(); - } - used = true; - } - - // Keys pressed together with Alt/Meta - // Emotions and some internal gui windows -#ifndef __APPLE__ - if (event.key.keysym.mod & KMOD_LALT) -#else - if (event.key.keysym.mod & KMOD_LMETA) -#endif - { - switch (event.key.keysym.sym) - { - case SDLK_p: + case KeyboardConfig::KEY_WINDOW_EMOTE: + requestedWindow = emoteWindow; + break; + case KeyboardConfig::KEY_WINDOW_EMOTE_SHORTCUT: + requestedWindow = emoteShortcutWindow; + break; + case KeyboardConfig::KEY_SCREENSHOT: // Screenshot (picture, hence the p) saveScreenshot(); used = true; break; - - default: - break; - - case SDLK_f: + case KeyboardConfig::KEY_PATHFIND: // Find path to mouse (debug purpose) viewport->toggleDebugPath(); used = true; break; - - case SDLK_t: + case KeyboardConfig::KEY_TRADE: // Toggle accepting of incoming trade requests + unsigned int deflt = player_relations.getDefault(); + if (deflt & PlayerRelation::TRADE) + { + chatWindow->chatLog( + _("Ignoring incoming trade requests"), + BY_SERVER); + deflt &= ~PlayerRelation::TRADE; + } + else { - TradeHandler *th = static_cast<TradeHandler*>( - mTradeHandler.get()); - th->setAcceptTradeRequests( - !th->acceptTradeRequests()); + chatWindow->chatLog( + _("Accepting incoming trade requests"), + BY_SERVER); + deflt |= PlayerRelation::TRADE; } + + player_relations.setDefault(deflt); + used = true; break; } + } - // Emotions - Uint8 emotion; - switch (event.key.keysym.sym) - { - case SDLK_1: emotion = 1; break; - case SDLK_2: emotion = 2; break; - case SDLK_3: emotion = 3; break; - case SDLK_4: emotion = 4; break; - case SDLK_5: emotion = 5; break; - case SDLK_6: emotion = 6; break; - case SDLK_7: emotion = 7; break; - case SDLK_8: emotion = 8; break; - case SDLK_9: emotion = 9; break; - case SDLK_0: emotion = 10; break; - case SDLK_MINUS: emotion = 11; break; - case SDLK_EQUALS: emotion = 12; break; - default: emotion = 0; break; - } - - if (emotion) - { - player_node->emote(emotion); - used = true; - } + if (requestedWindow) + { + requestedWindow->setVisible(!requestedWindow->isVisible()); + if (requestedWindow->isVisible()) + requestedWindow->requestMoveToTop(); + used = true; } } - // Quit event else if (event.type == SDL_QUIT) { @@ -801,15 +969,31 @@ void Game::handleInput() // Moving player around if (player_node->mAction != Being::DEAD && +#ifdef EATHENA_SUPPORT + current_npc == 0 && +#endif !chatWindow->isInputFocused()) { // Get the state of the keyboard keys keyboard.refreshActiveKeys(); - const Vector &pos = player_node->getPosition(); - Uint16 x = (int) pos.x / 32; - Uint16 y = (int) pos.y / 32; + // Ignore input if either "ignore" key is pressed + // Stops the character moving about if the user's window manager + // uses "ignore+arrow key" to switch virtual desktops. + if (keyboard.isKeyActive(keyboard.KEY_IGNORE_INPUT_1) || + keyboard.isKeyActive(keyboard.KEY_IGNORE_INPUT_2)) + { + return; + } +#ifdef TMWSERV_SUPPORT + const Vector &pos = player_node->getPosition(); + const Uint16 x = (int) pos.x / 32; + const Uint16 y = (int) pos.y / 32; +#else + const Uint16 x = player_node->mX; + const Uint16 y = player_node->mY; +#endif unsigned char direction = 0; // Translate pressed keys to movement and direction @@ -835,6 +1019,7 @@ void Game::handleInput() direction |= Being::RIGHT; } +#ifdef TMWSERV_SUPPORT // First if player is pressing key for the direction he is already // going if (direction == player_node->getWalkingDir()) @@ -854,31 +1039,100 @@ void Game::handleInput() { player_node->stopWalking(true); } +#else + player_node->setWalkingDir(direction); - // Target the nearest player if 'q' is pressed - if (keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER)) + // Attacking monsters + if (keyboard.isKeyActive(keyboard.KEY_ATTACK) || + (joystick && joystick->buttonPressed(0))) { - Being *target = beingManager->findNearestLivingBeing( - player_node, 20, Being::PLAYER); + Being *target = beingManager->findNearestLivingBeing(x, y, 20, + Being::MONSTER); - if (target) + bool newTarget = !keyboard.isKeyActive(keyboard.KEY_TARGET); + // A set target has highest priority + if (newTarget || !player_node->getTarget()) { - player_node->setTarget(target); + Uint16 targetX = x, targetY = y; + + switch (player_node->getSpriteDirection()) + { + case DIRECTION_UP : --targetY; break; + case DIRECTION_DOWN : ++targetY; break; + case DIRECTION_LEFT : --targetX; break; + case DIRECTION_RIGHT: ++targetX; break; + default: break; + } + + // Attack priorioty is: Monster, Player, auto target + target = beingManager->findBeing(targetX, targetY, Being::MONSTER); + if (!target) + target = beingManager->findBeing(targetX, targetY, Being::PLAYER); } + + player_node->attack(target, newTarget); + } +#endif + + // Target the nearest player if 'q' is pressed + if ( keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER) && + !keyboard.isKeyActive(keyboard.KEY_TARGET) ) + { + Being *target = beingManager->findNearestLivingBeing(player_node, 20, Being::PLAYER); + + player_node->setTarget(target); } // Target the nearest monster if 'a' pressed - if (keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST)) + if ((keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) || + (joystick && joystick->buttonPressed(3))) && + !keyboard.isKeyActive(keyboard.KEY_TARGET)) { Being *target = beingManager->findNearestLivingBeing( x, y, 20, Being::MONSTER); - if (target) + player_node->setTarget(target); + } + + // Target the nearest npc if 'n' pressed + if ( keyboard.isKeyActive(keyboard.KEY_TARGET_NPC) && + !keyboard.isKeyActive(keyboard.KEY_TARGET) ) + { + Being *target = beingManager->findNearestLivingBeing( + x, y, 20, Being::NPC); + + player_node->setTarget(target); + } + + // Talk to the nearest NPC if 't' pressed + if ( keyboard.isKeyActive(keyboard.KEY_TALK) ) + { + if (!npcTextDialog->isVisible() && !npcListDialog->isVisible()) { - player_node->setTarget(target); + Being *target = player_node->getTarget(); + + if (!target) + { + target = beingManager->findNearestLivingBeing( + x, y, 20, Being::NPC); + } + + if (target) + { + if (target->getType() == Being::NPC) + dynamic_cast<NPC*>(target)->talk(); + } } } +#ifdef EATHENA_SUPPORT + // Stop attacking if shift is pressed + if (keyboard.isKeyActive(keyboard.KEY_TARGET)) + { + player_node->stopAttack(); + } +#endif + if (joystick) { if (joystick->buttonPressed(1)) |