diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | src/game.cpp | 942 | ||||
-rw-r--r-- | src/net/beinghandler.cpp | 28 | ||||
-rw-r--r-- | src/net/protocol.h | 4 |
4 files changed, 520 insertions, 462 deletions
@@ -1,3 +1,11 @@ +2008-07-22 Lloyd Bryant ("Sanga") <lloyd_bryant@netzero.net> + + * Added handler for 0x0086 movement packet (new eAthena). + * Changed startup sequence for game.cpp to send a ping packet + to the server after all the handlers have been initialized. + This is required by the new eAthena version. + * Added #deines for some "ping" packets. + 2008-07-19 Lloyd Bryant ("Sanga") <lloyd_bryant@netzero.net> * Removed unnecessary check ("weight") from itemdb loader diff --git a/src/game.cpp b/src/game.cpp index d018852b..070cab52 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -68,6 +68,7 @@ #include "gui/status.h" #include "gui/trade.h" #include "gui/viewport.h" +#include "net/protocol.h" #include "net/beinghandler.h" #include "net/buysellhandler.h" #include "net/chathandler.h" @@ -79,6 +80,7 @@ #include "net/playerhandler.h" #include "net/skillhandler.h" #include "net/tradehandler.h" +#include "net/messageout.h" #include "resources/imagewriter.h" @@ -92,6 +94,7 @@ std::string map_path; bool done = false; volatile int tick_time; volatile int fps = 0, frame = 0; + Engine *engine = NULL; Joystick *joystick = NULL; @@ -134,14 +137,14 @@ const int MAX_TIME = 10000; namespace { struct ExitListener : public gcn::ActionListener { - void action(const gcn::ActionEvent &event) - { - if (event.getId() == "yes" || event.getId() == "ok") { - done = true; - } - exitConfirm = NULL; - disconnectedDialog = NULL; - } + void action(const gcn::ActionEvent &event) + { + if (event.getId() == "yes" || event.getId() == "ok") { + done = true; + } + exitConfirm = NULL; + disconnectedDialog = NULL; + } } exitListener; } @@ -162,16 +165,17 @@ Uint32 nextSecond(Uint32 interval, void *param) { fps = frame; frame = 0; + return interval; } int get_elapsed_time(int start_time) { if (start_time <= tick_time) { - return (tick_time - start_time) * 10; + return (tick_time - start_time) * 10; } else { - return (tick_time + (MAX_TIME - start_time)) * 10; + return (tick_time + (MAX_TIME - start_time)) * 10; } } @@ -218,7 +222,7 @@ void createGuiWindows(Network *network) if (config.getValue("logToChat", 0)) { - logger->setChatWindow(chatWindow); + logger->setChatWindow(chatWindow); } } @@ -283,14 +287,13 @@ Game::Game(Network *network): // Initialize beings beingManager->setPlayer(player_node); player_node->setNetwork(network); - engine->changeMap(map_path); Joystick::init(); // TODO: The user should be able to choose which one to use // Open the first device if (Joystick::getNumberOfJoysticks() > 0) { - joystick = new Joystick(0); + joystick = new Joystick(0); } network->registerHandler(mBeingHandler.get()); @@ -303,6 +306,21 @@ Game::Game(Network *network): 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); } Game::~Game() @@ -331,30 +349,30 @@ bool saveScreenshot(SDL_Surface *screenshot) bool found = false; do { - screenshotCount++; - filename.str(""); + screenshotCount++; + filename.str(""); #if (defined __USE_UNIX98 || defined __FreeBSD__) - filename << PHYSFS_getUserDir() << ".tme/"; + filename << PHYSFS_getUserDir() << ".tme/"; #elif defined __APPLE__ - filename << PHYSFS_getUserDir() << "Desktop/"; + filename << PHYSFS_getUserDir() << "Desktop/"; #endif - filename << "TMW_Screenshot_" << screenshotCount << ".png"; - testExists.open(filename.str().c_str(), std::ios::in); - found = !testExists.is_open(); - testExists.close(); + filename << "TMW_Screenshot_" << screenshotCount << ".png"; + testExists.open(filename.str().c_str(), std::ios::in); + found = !testExists.is_open(); + testExists.close(); } while (!found); if (ImageWriter::writePNG(screenshot, filename.str())) { - std::stringstream chatlogentry; - chatlogentry << "Screenshot saved to " << filename.str().c_str(); - chatWindow->chatLog(chatlogentry.str(), BY_SERVER); - return true; + std::stringstream chatlogentry; + chatlogentry << "Screenshot saved to " << filename.str().c_str(); + chatWindow->chatLog(chatlogentry.str(), BY_SERVER); + return true; } else { - chatWindow->chatLog("Saving screenshot failed!", BY_SERVER); - return false; + chatWindow->chatLog("Saving screenshot failed!", BY_SERVER); + return false; } } @@ -378,61 +396,61 @@ void Game::logic() while (!done) { - // Handle all necessary game logic - while (get_elapsed_time(gameTime) > 0) - { - handleInput(); - engine->logic(); - gameTime++; - } - - // This is done because at some point tick_time will wrap. - gameTime = tick_time; - - // Update the screen when application is active, delay otherwise. - if (SDL_GetAppState() & SDL_APPACTIVE) - { - // 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) - { - frame++; - gui->draw(); - graphics->updateScreen(); - mDrawTime += mMinFrameTime; - - // Make sure to wrap mDrawTime, since tick_time will wrap. - if (mDrawTime > MAX_TIME * 10) - mDrawTime -= MAX_TIME * 10; - } - else - { - SDL_Delay(10); - } - } - else - { - SDL_Delay(10); - mDrawTime = tick_time * 10; - } - - // Handle network stuff - mNetwork->flush(); - mNetwork->dispatchMessages(); - - if (!mNetwork->isConnected()) - { - if (!disconnectedDialog) - { - disconnectedDialog = new - OkDialog("Network Error", - "The connection to the server was lost, the " + // Handle all necessary game logic + while (get_elapsed_time(gameTime) > 0) + { + handleInput(); + engine->logic(); + gameTime++; + } + + // This is done because at some point tick_time will wrap. + gameTime = tick_time; + + // Update the screen when application is active, delay otherwise. + if (SDL_GetAppState() & SDL_APPACTIVE) + { + // 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) + { + frame++; + gui->draw(); + graphics->updateScreen(); + mDrawTime += mMinFrameTime; + + // Make sure to wrap mDrawTime, since tick_time will wrap. + if (mDrawTime > MAX_TIME * 10) + mDrawTime -= MAX_TIME * 10; + } + else + { + SDL_Delay(10); + } + } + else + { + SDL_Delay(10); + mDrawTime = tick_time * 10; + } + + // Handle network stuff + 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->addActionListener(&exitListener); - disconnectedDialog->requestMoveToTop(); - } - } + disconnectedDialog->addActionListener(&exitListener); + disconnectedDialog->requestMoveToTop(); + } + } } } @@ -440,296 +458,296 @@ void Game::handleInput() { if (joystick != NULL) { - joystick->update(); + joystick->update(); } // Events SDL_Event event; while (SDL_PollEvent(&event)) { - bool used = false; - - // Keyboard events (for discontinuous keys) - if (event.type == SDL_KEYDOWN) - { - gcn::Window *requestedWindow = NULL; - - if (setupWindow->isVisible() && - keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE) - { - keyboard.setNewKey((int) event.key.keysym.sym); - keyboard.callbackNewKey(); - keyboard.setNewKeyIndex(keyboard.KEY_NO_VALUE); - return; - } - // Keys pressed together with Alt/Meta - // Emotions and some internal gui windows - #ifndef __APPLE__ - if (event.key.keysym.mod & KMOD_ALT) - #else - if (event.key.keysym.mod & KMOD_LMETA) - #endif - { - switch (event.key.keysym.sym) - { - case SDLK_p: - // Screenshot (picture, hence the p) - { - SDL_Surface *screenshot = + bool used = false; + + // Keyboard events (for discontinuous keys) + if (event.type == SDL_KEYDOWN) + { + gcn::Window *requestedWindow = NULL; + + if (setupWindow->isVisible() && + keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE) + { + keyboard.setNewKey((int) event.key.keysym.sym); + keyboard.callbackNewKey(); + keyboard.setNewKeyIndex(keyboard.KEY_NO_VALUE); + return; + } + // Keys pressed together with Alt/Meta + // Emotions and some internal gui windows + #ifndef __APPLE__ + if (event.key.keysym.mod & KMOD_ALT) + #else + if (event.key.keysym.mod & KMOD_LMETA) + #endif + { + switch (event.key.keysym.sym) + { + case SDLK_p: + // Screenshot (picture, hence the p) + { + SDL_Surface *screenshot = graphics->getScreenshot(); - if (!saveScreenshot(screenshot)) - { - logger-> + if (!saveScreenshot(screenshot)) + { + logger-> log("Error: could not save Screenshot."); - } - SDL_FreeSurface(screenshot); - } - used = true; - break; - - default: - break; - - case SDLK_f: - // Find path to mouse (debug purpose) - viewport->toggleDebugPath(); - used = true; - break; - - case SDLK_t: - // Toggle accepting of incoming trade requests - { - unsigned int deflt = player_relations.getDefault(); - if (deflt & PlayerRelation::TRADE) { - chatWindow-> + } + SDL_FreeSurface(screenshot); + } + used = true; + break; + + default: + break; + + case SDLK_f: + // Find path to mouse (debug purpose) + viewport->toggleDebugPath(); + used = true; + break; + + case SDLK_t: + // 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 { - chatWindow->chatLog("Accepting incoming trade " + deflt &= ~PlayerRelation::TRADE; + } else { + 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; - } - } - switch (event.key.keysym.sym) - { - case SDLK_PAGEUP: - if (chatWindow->isVisible()) - { - chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL); - used = true; - } - break; - - case SDLK_PAGEDOWN: - if (chatWindow->isVisible()) - { - chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL); - used = true; - } - break; - - case SDLK_F1: - // In-game Help - if (helpWindow->isVisible()) - { - helpWindow->setVisible(false); - } - else - { - helpWindow->loadHelp("index"); - helpWindow->requestMoveToTop(); - } - used = true; - break; - - case SDLK_F2: requestedWindow = statusWindow; break; - case SDLK_F3: requestedWindow = inventoryWindow; break; - case SDLK_F4: requestedWindow = equipmentWindow; break; - case SDLK_F5: requestedWindow = skillDialog; break; - case SDLK_F6: requestedWindow = minimap; break; - case SDLK_F7: requestedWindow = chatWindow; break; - case SDLK_F8: requestedWindow = itemShortcutWindow; break; - case SDLK_F9: requestedWindow = setupWindow; break; - case SDLK_F10: requestedWindow = debugWindow; break; - //case SDLK_F11: requestedWindow = newSkillWindow; break; - - case SDLK_RETURN: - // Input chat window - if (chatWindow->isInputFocused() || - deathNotice != NULL || - weightNotice != NULL) - { - break; - } - - // Quit by pressing Enter if the exit confirm is there - if (exitConfirm) - { - done = true; - } - // Close the Browser if opened - else if (helpWindow->isVisible()) - { - helpWindow->setVisible(false); - } - // Close the config window, cancelling changes if opened - else if (setupWindow->isVisible()) - { - setupWindow->action(gcn::ActionEvent(NULL, "cancel")); - } - // Else, open the chat edit box - else - { - chatWindow->requestChatFocus(); - used = true; - } - break; - // Quitting confirmation dialog - case SDLK_ESCAPE: - 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")); - } - break; - - default: - break; - } - if (keyboard.isEnabled() && !chatWindow->isInputFocused()) - { - const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); - // Checks if any item shortcut is pressed. - for (int i = KeyboardConfig::KEY_SHORTCUT_0; - i <= KeyboardConfig::KEY_SHORTCUT_9; - i++) - { - if (tKey == i && !used) { - itemShortcut->useItem( - i - KeyboardConfig::KEY_SHORTCUT_0); - break; - } - } - switch (tKey) { - case KeyboardConfig::KEY_PICKUP: - { - FloorItem *item = + 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; + } + } + switch (event.key.keysym.sym) + { + case SDLK_PAGEUP: + if (chatWindow->isVisible()) + { + chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL); + used = true; + } + break; + + case SDLK_PAGEDOWN: + if (chatWindow->isVisible()) + { + chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL); + used = true; + } + break; + + case SDLK_F1: + // In-game Help + if (helpWindow->isVisible()) + { + helpWindow->setVisible(false); + } + else + { + helpWindow->loadHelp("index"); + helpWindow->requestMoveToTop(); + } + used = true; + break; + + case SDLK_F2: requestedWindow = statusWindow; break; + case SDLK_F3: requestedWindow = inventoryWindow; break; + case SDLK_F4: requestedWindow = equipmentWindow; break; + case SDLK_F5: requestedWindow = skillDialog; break; + case SDLK_F6: requestedWindow = minimap; break; + case SDLK_F7: requestedWindow = chatWindow; break; + case SDLK_F8: requestedWindow = itemShortcutWindow; break; + case SDLK_F9: requestedWindow = setupWindow; break; + case SDLK_F10: requestedWindow = debugWindow; break; + //case SDLK_F11: requestedWindow = newSkillWindow; break; + + case SDLK_RETURN: + // Input chat window + if (chatWindow->isInputFocused() || + deathNotice != NULL || + weightNotice != NULL) + { + break; + } + + // Quit by pressing Enter if the exit confirm is there + if (exitConfirm) + { + done = true; + } + // Close the Browser if opened + else if (helpWindow->isVisible()) + { + helpWindow->setVisible(false); + } + // Close the config window, cancelling changes if opened + else if (setupWindow->isVisible()) + { + setupWindow->action(gcn::ActionEvent(NULL, "cancel")); + } + // Else, open the chat edit box + else + { + chatWindow->requestChatFocus(); + used = true; + } + break; + // Quitting confirmation dialog + case SDLK_ESCAPE: + 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")); + } + break; + + default: + break; + } + if (keyboard.isEnabled() && !chatWindow->isInputFocused()) + { + const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); + // Checks if any item shortcut is pressed. + for (int i = KeyboardConfig::KEY_SHORTCUT_0; + i <= KeyboardConfig::KEY_SHORTCUT_9; + i++) + { + if (tKey == i && !used) { + itemShortcut->useItem( + i - KeyboardConfig::KEY_SHORTCUT_0); + break; + } + } + switch (tKey) { + case KeyboardConfig::KEY_PICKUP: + { + FloorItem *item = floorItemManager->findByCoordinates( - player_node->mX, player_node->mY); - - // If none below the player, try the tile in front - // of the player - if (!item) { - Uint16 x = player_node->mX; - Uint16 y = player_node->mY; - if (player_node->getDirection() & Being::UP) - y--; - if (player_node->getDirection() & Being::DOWN) - y++; - if (player_node->getDirection() & Being::LEFT) - x--; - if (player_node->getDirection() & Being::RIGHT) - x++; - - item = floorItemManager-> + player_node->mX, player_node->mY); + + // If none below the player, try the tile in front + // of the player + if (!item) { + Uint16 x = player_node->mX; + Uint16 y = player_node->mY; + if (player_node->getDirection() & Being::UP) + y--; + if (player_node->getDirection() & Being::DOWN) + y++; + if (player_node->getDirection() & Being::LEFT) + x--; + if (player_node->getDirection() & Being::RIGHT) + x++; + + item = floorItemManager-> findByCoordinates(x, y); - } - - if (item) - player_node->pickUp(item); - - used = true; - } - break; - case KeyboardConfig::KEY_SIT: - // Player sit action - player_node->toggleSit(); - used = true; - break; - case KeyboardConfig::KEY_HIDE_WINDOWS: - // Hide certain windows - if (!chatWindow->isInputFocused()) - { - statusWindow->setVisible(false); - inventoryWindow->setVisible(false); - skillDialog->setVisible(false); - setupWindow->setVisible(false); - equipmentWindow->setVisible(false); - helpWindow->setVisible(false); - debugWindow->setVisible(false); - } - break; - } - } - - if (requestedWindow) - { - requestedWindow->setVisible(!requestedWindow->isVisible()); - if (requestedWindow->isVisible()) - { - requestedWindow->requestMoveToTop(); - } - used = true; - } - - } - - // Quit event - else if (event.type == SDL_QUIT) - { - done = true; - } - - // Push input to GUI when not used - if (!used) - { - try - { - guiInput->pushInput(event); - } - catch (gcn::Exception e) - { - const char* err = e.getMessage().c_str(); - logger->log("Warning: guichan input exception: %s", err); - } - } + } + + if (item) + player_node->pickUp(item); + + used = true; + } + break; + case KeyboardConfig::KEY_SIT: + // Player sit action + player_node->toggleSit(); + used = true; + break; + case KeyboardConfig::KEY_HIDE_WINDOWS: + // Hide certain windows + if (!chatWindow->isInputFocused()) + { + statusWindow->setVisible(false); + inventoryWindow->setVisible(false); + skillDialog->setVisible(false); + setupWindow->setVisible(false); + equipmentWindow->setVisible(false); + helpWindow->setVisible(false); + debugWindow->setVisible(false); + } + break; + } + } + + if (requestedWindow) + { + requestedWindow->setVisible(!requestedWindow->isVisible()); + if (requestedWindow->isVisible()) + { + requestedWindow->requestMoveToTop(); + } + used = true; + } + + } + + // Quit event + else if (event.type == SDL_QUIT) + { + done = true; + } + + // Push input to GUI when not used + if (!used) + { + try + { + guiInput->pushInput(event); + } + catch (gcn::Exception e) + { + const char* err = e.getMessage().c_str(); + logger->log("Warning: guichan input exception: %s", err); + } + } } // End while // If the user is configuring the keys then don't respond. @@ -739,112 +757,112 @@ void Game::handleInput() } // Moving player around if (player_node->mAction != Being::DEAD && - current_npc == 0 && - !chatWindow->isInputFocused()) + current_npc == 0 && + !chatWindow->isInputFocused()) + { + // Get the state of the keyboard keys + keyboard.refreshActiveKeys(); + + const Uint16 x = player_node->mX; + const Uint16 y = player_node->mY; + unsigned char direction = 0; + + // Translate pressed keys to movement and direction + if (keyboard.isKeyActive(keyboard.KEY_MOVE_UP) || + (joystick && joystick->isUp())) + { + direction |= Being::UP; + } + else if (keyboard.isKeyActive(keyboard.KEY_MOVE_DOWN) || + (joystick && joystick->isDown())) + { + direction |= Being::DOWN; + } + + if (keyboard.isKeyActive(keyboard.KEY_MOVE_LEFT) || + (joystick && joystick->isLeft())) + { + direction |= Being::LEFT; + } + else if (keyboard.isKeyActive(keyboard.KEY_MOVE_RIGHT) || + (joystick && joystick->isRight())) + { + direction |= Being::RIGHT; + } + + player_node->setWalkingDir(direction); + + // Attacking monsters + if (keyboard.isKeyActive(keyboard.KEY_ATTACK) || + (joystick && joystick->buttonPressed(0))) { - // Get the state of the keyboard keys - keyboard.refreshActiveKeys(); - - const Uint16 x = player_node->mX; - const Uint16 y = player_node->mY; - unsigned char direction = 0; - - // Translate pressed keys to movement and direction - if (keyboard.isKeyActive(keyboard.KEY_MOVE_UP) || - (joystick && joystick->isUp())) - { - direction |= Being::UP; - } - else if (keyboard.isKeyActive(keyboard.KEY_MOVE_DOWN) || - (joystick && joystick->isDown())) - { - direction |= Being::DOWN; - } - - if (keyboard.isKeyActive(keyboard.KEY_MOVE_LEFT) || - (joystick && joystick->isLeft())) - { - direction |= Being::LEFT; - } - else if (keyboard.isKeyActive(keyboard.KEY_MOVE_RIGHT) || - (joystick && joystick->isRight())) - { - direction |= Being::RIGHT; - } - - player_node->setWalkingDir(direction); - - // Attacking monsters - if (keyboard.isKeyActive(keyboard.KEY_ATTACK) || - (joystick && joystick->buttonPressed(0))) - { - Being *target = NULL; - bool newTarget = keyboard.isKeyActive(keyboard.KEY_TARGET); - // A set target has highest priority - if (newTarget || !player_node->getTarget()) - { - Uint16 targetX = x, targetY = y; - - if (player_node->getDirection() & Being::UP) - targetY--; - if (player_node->getDirection() & Being::DOWN) - targetY++; - if (player_node->getDirection() & Being::LEFT) - targetX--; - if (player_node->getDirection() & Being::RIGHT) - targetX++; - - // 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); - } - - // Target the nearest player if 'q' is pressed - if ( keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER) ) - //if (keys[SDLK_q]) - { - Being *target = - beingManager-> + Being *target = NULL; + bool newTarget = keyboard.isKeyActive(keyboard.KEY_TARGET); + // A set target has highest priority + if (newTarget || !player_node->getTarget()) + { + Uint16 targetX = x, targetY = y; + + if (player_node->getDirection() & Being::UP) + targetY--; + if (player_node->getDirection() & Being::DOWN) + targetY++; + if (player_node->getDirection() & Being::LEFT) + targetX--; + if (player_node->getDirection() & Being::RIGHT) + targetX++; + + // 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); + } + + // Target the nearest player if 'q' is pressed + if ( keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER) ) + //if (keys[SDLK_q]) + { + Being *target = + beingManager-> findNearestLivingBeing(player_node, 20, Being::PLAYER); - if (target) - { - player_node->setTarget(target); - } - } - - // Target the nearest monster if 'a' pressed - if ( keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) ) - //if (keys[SDLK_a]) - { - Being *target = - beingManager->findNearestLivingBeing(x, y, 20, Being::MONSTER); - - if (target) - { - player_node->setTarget(target); - } - } - - if (joystick) - { - if (joystick->buttonPressed(1)) - { - FloorItem *item = floorItemManager->findByCoordinates(x, y); - - if (item) - player_node->pickUp(item); - } - else if (joystick->buttonPressed(2)) - { - player_node->toggleSit(); - } - } + if (target) + { + player_node->setTarget(target); + } + } + + // Target the nearest monster if 'a' pressed + if ( keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) ) + //if (keys[SDLK_a]) + { + Being *target = + beingManager->findNearestLivingBeing(x, y, 20, Being::MONSTER); + + if (target) + { + player_node->setTarget(target); + } + } + + if (joystick) + { + if (joystick->buttonPressed(1)) + { + FloorItem *item = floorItemManager->findByCoordinates(x, y); + + if (item) + player_node->pickUp(item); + } + else if (joystick->buttonPressed(2)) + { + player_node->toggleSit(); + } + } } } diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index f3c0cfb4..778c8cfe 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -45,6 +45,7 @@ BeingHandler::BeingHandler() static const Uint16 _messages[] = { SMSG_BEING_VISIBLE, SMSG_BEING_MOVE, + SMSG_BEING_MOVE2, SMSG_BEING_REMOVE, SMSG_BEING_ACTION, SMSG_BEING_LEVELUP, @@ -164,6 +165,33 @@ void BeingHandler::handleMessage(MessageIn *msg) msg->readInt8(); // unknown / sit break; + case SMSG_BEING_MOVE2: + /* + * A simplified movement packet, used by the + * later versions of eAthena for both mobs and + * players + */ + dstBeing = beingManager->findBeing(msg->readInt32()); + + Uint16 srcX, srcY, dstX, dstY; + msg->readCoordinatePair(srcX, srcY, dstX, dstY); + msg->readInt32(); // Server tick + + /* + * This packet doesn't have enough info to actually + * create a new being, so if the being isn't found, + * we'll just pretend the packet didn't happen + */ + + if (dstBeing) { + dstBeing->setAction(Being::STAND); + dstBeing->mX = srcX; + dstBeing->mY = srcY; + dstBeing->setDestination(dstX, dstY); + } + + break; + case SMSG_BEING_REMOVE: // A being should be removed or has died dstBeing = beingManager->findBeing(msg->readInt32()); diff --git a/src/net/protocol.h b/src/net/protocol.h index f90fcba3..53f245b5 100644 --- a/src/net/protocol.h +++ b/src/net/protocol.h @@ -26,6 +26,7 @@ // Packets from server to client #define SMSG_LOGIN_SUCCESS 0x0073 /**< Contains starting location */ +#define SMSG_SERVER_PING 0x007f /**< Contains server tick */ #define SMSG_PLAYER_UPDATE_1 0x01d8 #define SMSG_PLAYER_UPDATE_2 0x01d9 #define SMSG_PLAYER_MOVE 0x01da /**< A nearby player moves */ @@ -57,6 +58,8 @@ #define SMSG_ITEM_REMOVE 0x00a1 /**< An item disappers */ #define SMSG_BEING_VISIBLE 0x0078 #define SMSG_BEING_MOVE 0x007b /**< A nearby monster moves */ +#define SMSG_BEING_SPAWN 0x007c /**< A being spawns nearby */ +#define SMSG_BEING_MOVE2 0x0086 /**< New eAthena being moves */ #define SMSG_BEING_REMOVE 0x0080 #define SMSG_BEING_CHANGE_LOOKS 0x00c3 #define SMSG_BEING_CHANGE_LOOKS2 0x01d7 /**< Same as 0x00c3, but 16 bit ID */ @@ -102,6 +105,7 @@ #define SMSG_PARTY_MESSAGE 0x0109 // Packets from client to server +#define CMSG_CLIENT_PING 0x007e /**< Send to server with tick */ #define CMSG_TRADE_RESPONSE 0x00e6 #define CMSG_ITEM_PICKUP 0x009f #define CMSG_MAP_LOADED 0x007d |