diff options
Diffstat (limited to 'src/game.cpp')
-rw-r--r-- | src/game.cpp | 571 |
1 files changed, 304 insertions, 267 deletions
diff --git a/src/game.cpp b/src/game.cpp index 9fa0129e..93bec013 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -26,11 +26,12 @@ #include <sstream> #include <string> -#include <guichan/sdl/sdlinput.hpp> #include <guichan/exception.hpp> +#include <guichan/sdl/sdlinput.hpp> #include "beingmanager.h" #include "configuration.h" +#include "effectmanager.h" #include "engine.h" #include "flooritemmanager.h" #include "graphics.h" @@ -74,9 +75,11 @@ #include "net/equipmenthandler.h" #include "net/inventoryhandler.h" #include "net/itemhandler.h" +#include "net/messageout.h" #include "net/network.h" #include "net/npchandler.h" #include "net/playerhandler.h" +#include "net/protocol.h" #include "net/skillhandler.h" #include "net/tradehandler.h" #include "net/messageout.h" @@ -93,6 +96,7 @@ std::string map_path; bool done = false; volatile int tick_time; volatile int fps = 0, frame = 0; + Engine *engine = NULL; Joystick *joystick = NULL; @@ -112,7 +116,6 @@ InventoryWindow *inventoryWindow; NpcListDialog *npcListDialog; NpcTextDialog *npcTextDialog; SkillDialog *skillDialog; -//NewSkillDialog *newSkillWindow; Setup* setupWindow; Minimap *minimap; EquipmentWindow *equipmentWindow; @@ -126,11 +129,12 @@ ItemShortcutWindow *itemShortcutWindow; BeingManager *beingManager = NULL; FloorItemManager *floorItemManager = NULL; Particle* particleEngine = NULL; +EffectManager *effectManager = NULL; const int MAX_TIME = 10000; /** - * Listener used for exitting handling. + * Listener used for exiting handling. */ namespace { struct ExitListener : public gcn::ActionListener @@ -163,15 +167,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; } } @@ -193,7 +200,6 @@ void createGuiWindows(Network *network) npcTextDialog = new NpcTextDialog(); npcListDialog = new NpcListDialog(); skillDialog = new SkillDialog(); - //newSkillWindow = new NewSkillDialog(); setupWindow = new Setup(); minimap = new Minimap(); equipmentWindow = new EquipmentWindow(player_node->mEquipment.get()); @@ -215,8 +221,7 @@ void createGuiWindows(Network *network) 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); tradeWindow->setVisible(false); @@ -251,7 +256,6 @@ void destroyGuiWindows() delete minimap; delete equipmentWindow; //delete chargeDialog; - //delete newSkillWindow; delete tradeWindow; //delete buddyWindow; delete helpWindow; @@ -277,6 +281,8 @@ Game::Game(Network *network): beingManager = new BeingManager(network); floorItemManager = new FloorItemManager(); + effectManager = new EffectManager(); + particleEngine = new Particle(NULL); particleEngine->setupEngine(); @@ -311,17 +317,13 @@ Game::Game(Network *network): network->registerHandler(mTradeHandler.get()); /* - * THIS IS A TEMPORARY WORKAROUND! - * - * To prevent the server from sending data before the client has - * initialized, it's been modified to wait for a "ping" from the client to - * complete its initialization. + * 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 * - * The real fix is to make sure we are not throwing away messages in the - * network buffer due to not having registered the handlers above straight - * after receiving a login success from the map server. - * - * The response from eAthena on this packet is ignored by the client. + * 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); @@ -356,17 +358,17 @@ bool saveScreenshot(SDL_Surface *screenshot) bool found = false; do { - screenshotCount++; - filename.str(""); + screenshotCount++; + filename.str(""); #if (defined __USE_UNIX98 || defined __FreeBSD__) - filename << PHYSFS_getUserDir() << ".tmw/"; + filename << PHYSFS_getUserDir() << ".aethyra/"; #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 << "Ae_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())) @@ -403,61 +405,61 @@ void Game::logic() while (!done) { - // Handle all necessary game logic - while (get_elapsed_time(gameTime) > 0) - { - handleInput(); - engine->logic(); - gameTime++; - } + // 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; + // 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) + // 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) { - // 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); - } + 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); - mDrawTime = tick_time * 10; } + } + else + { + SDL_Delay(10); + mDrawTime = tick_time * 10; + } - // Handle network stuff - mNetwork->flush(); - mNetwork->dispatchMessages(); + // Handle network stuff + mNetwork->flush(); + mNetwork->dispatchMessages(); - if (!mNetwork->isConnected()) + if (!mNetwork->isConnected()) + { + if (!disconnectedDialog) { - 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 = new + OkDialog("Network Error", + "The connection to the server was lost, the program will now quit"); + disconnectedDialog->addActionListener(&exitListener); + disconnectedDialog->requestMoveToTop(); } } + } } void Game::handleInput() @@ -478,7 +480,7 @@ void Game::handleInput() { gcn::Window *requestedWindow = NULL; - if (setupWindow->isVisible() && + if (setupWindow->isVisible() && keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE) { keyboard.setNewKey((int) event.key.keysym.sym); @@ -534,194 +536,202 @@ void Game::handleInput() } used = true; break; - } } + } - // Smilie - if (keyboard.isKeyActive(keyboard.KEY_SMILIE)) + // Smilie + if (keyboard.isKeyActive(keyboard.KEY_SMILIE)) + { + // Emotions + Uint8 emotion; + switch (event.key.keysym.sym) { - // 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()) { - 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; + chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL); + used = true; } + break; - if (emotion) + case SDLK_PAGEDOWN: + if (chatWindow->isVisible()) { - player_node->emote(emotion); + chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL); used = true; return; } - } - switch (event.key.keysym.sym) - { - case SDLK_PAGEUP: - if (chatWindow->isVisible()) - { - chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL); - used = true; - } - break; + break; - case SDLK_PAGEDOWN: - if (chatWindow->isVisible()) - { - chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL); - used = true; - } + 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_RETURN: + // Input chat window + if (chatWindow->isInputFocused() || + deathNotice != NULL || + weightNotice != NULL) + { break; + } - case SDLK_F1: - // In-game Help - if (helpWindow->isVisible()) - { - helpWindow->setVisible(false); - } - else - { - helpWindow->loadHelp("index"); - helpWindow->requestMoveToTop(); - } + // 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")); + } + // Proceed to the next dialog option, or close the window + else if (npcTextDialog->isVisible()) + { + npcTextDialog->action(gcn::ActionEvent(NULL, "ok")); + } + // Choose the currently highlighted dialogue option + else if (npcListDialog->isVisible()) + { + npcListDialog->action(gcn::ActionEvent(NULL, "ok")); + } + // Else, open the chat edit box + else + { + chatWindow->requestChatFocus(); 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; - } + } + 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; - // 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); - default: - break; - } - if (keyboard.isEnabled() && !chatWindow->isInputFocused()) + // Do not activate shortcuts if tradewindow is visible + if (!tradeWindow->isVisible()) { - 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++) { - // 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; - } + if (tKey == i && !used) { + itemShortcut->useItem(i - KeyboardConfig::KEY_SHORTCUT_0); + break; } } - switch (tKey) { - case KeyboardConfig::KEY_PICKUP: + } + 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; + switch (player_node->getSpriteDirection()) { - 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->findByCoordinates(x, y); - } + case DIRECTION_UP : --y; break; + case DIRECTION_DOWN : ++y; break; + case DIRECTION_LEFT : --x; break; + case DIRECTION_RIGHT: ++x; break; + default: break; + } + item = floorItemManager->findByCoordinates(x, y); + } - if (item) - player_node->pickUp(item); + 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; + 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; } } @@ -756,7 +766,6 @@ void Game::handleInput() logger->log("Warning: guichan input exception: %s", err); } } - } // End while // If the user is configuring the keys then don't respond. if (!keyboard.isEnabled()) @@ -782,7 +791,7 @@ void Game::handleInput() direction |= Being::UP; } else if (keyboard.isKeyActive(keyboard.KEY_MOVE_DOWN) || - (joystick && joystick->isDown())) + (joystick && joystick->isDown())) { direction |= Being::DOWN; } @@ -802,60 +811,88 @@ void Game::handleInput() // Attacking monsters if (keyboard.isKeyActive(keyboard.KEY_ATTACK) || - (joystick && joystick->buttonPressed(0))) + (joystick && joystick->buttonPressed(0))) { - Being *target = NULL; - bool newTarget = keyboard.isKeyActive(keyboard.KEY_TARGET); + Being *target = beingManager->findNearestLivingBeing(x, y, 20, Being::MONSTER); + + 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++; + 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); + target = beingManager->findBeing(targetX, targetY, Being::MONSTER); if (!target) - target = beingManager->findBeing( - targetX, targetY, Being::PLAYER); + target = beingManager->findBeing(targetX, targetY, Being::PLAYER); } player_node->attack(target, newTarget); } - // Target the nearest player - if (keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER)) + // 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); + Being *target = beingManager->findNearestLivingBeing(player_node, 20, Being::PLAYER); - if (target) - { - player_node->setTarget(target); - } + player_node->setTarget(target); + } + + // Target the nearest monster if 'a' pressed + 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); + + player_node->setTarget(target); } - // Target the nearest monster - if (keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) - || (joystick && joystick->buttonPressed(3))) + // 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::MONSTER); + Being *target = beingManager->findNearestLivingBeing(x, y, 20, Being::NPC); - if (target) + 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(); + } } } + // Stop attacking if shift is pressed + if (keyboard.isKeyActive(keyboard.KEY_TARGET)) + { + player_node->stopAttack(); + } + if (joystick) { if (joystick->buttonPressed(1)) |