diff options
Diffstat (limited to 'src/game.cpp')
-rw-r--r-- | src/game.cpp | 1444 |
1 files changed, 137 insertions, 1307 deletions
diff --git a/src/game.cpp b/src/game.cpp index e4064040..dcd7b9d9 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -31,19 +31,14 @@ #include <guichan/sdl/sdlinput.hpp> -#include "being.h" +#include "beingmanager.h" #include "configuration.h" #include "engine.h" -#include "equipment.h" #include "floor_item.h" #include "graphics.h" -#include "inventory.h" -#include "item.h" +#include "localplayer.h" #include "log.h" -#include "main.h" -#include "map.h" -#include "playerinfo.h" -#include "sound.h" +#include "npc.h" #include "gui/buy.h" #include "gui/buysell.h" @@ -54,10 +49,8 @@ #include "gui/help.h" #include "gui/inventorywindow.h" #include "gui/minimap.h" -#include "gui/npc.h" +#include "gui/npclistdialog.h" #include "gui/npc_text.h" -#include "gui/ok_dialog.h" -#include "gui/requesttrade.h" #include "gui/sell.h" #include "gui/setup.h" #include "gui/skill.h" @@ -67,32 +60,36 @@ #include "gui/trade.h" #include "gui/debugwindow.h" -#include "net/messagein.h" -#include "net/messageout.h" +#include "net/beinghandler.h" +#include "net/buysellhandler.h" +#include "net/chathandler.h" +#include "net/equipmenthandler.h" +#include "net/inventoryhandler.h" +#include "net/itemhandler.h" #include "net/network.h" -#include "net/protocol.h" +#include "net/npchandler.h" +#include "net/playerhandler.h" +#include "net/skillhandler.h" +#include "net/tradehandler.h" #include "resources/imagewriter.h" extern Graphics *graphics; extern gcn::SDLInput *guiInput; +class Map; + std::string map_path; -std::string tradePartnerName; -bool refresh_beings = false; -unsigned char keyb_state; +bool done = false; volatile int tick_time; volatile bool action_time = false; -int server_tick; -int fps = 0, frame = 0, current_npc = 0; -Uint16 startX = 0, startY = 0; -Being *autoTarget = NULL; +int fps = 0, frame = 0; Engine *engine = NULL; SDL_Joystick *joypad = NULL; /**< Joypad object */ -OkDialog *weightNotice = NULL; -OkDialog *deathNotice = NULL; +extern Window *weightNotice; +extern Window *deathNotice; ConfirmDialog *exitConfirm = NULL; ChatWindow *chatWindow; @@ -116,41 +113,17 @@ TradeWindow *tradeWindow; HelpWindow *helpWindow; DebugWindow *debugWindow; -Inventory *inventory = NULL; +BeingManager *beingManager = NULL; -const int EMOTION_TIME = 150; /**< Duration of emotion icon */ const int MAX_TIME = 10000; -class WeightNoticeListener : public gcn::ActionListener -{ - public: - void action(const std::string &eventId) - { - weightNotice = NULL; - } -} weightNoticeListener; - - -/** - * Listener used for handling death message. - */ -class DeathNoticeListener : public gcn::ActionListener { - public: - void action(const std::string &eventId) { - MessageOut outMsg; - outMsg.writeInt16(0x00b2); - outMsg.writeInt8(0); - deathNotice = NULL; - } -} deathNoticeListener; - /** * Listener used for exitting handling. */ class ExitListener : public gcn::ActionListener { void action(const std::string &eventId) { if (eventId == "yes") { - state = EXIT_STATE; + done = true; } exitConfirm = NULL; } @@ -191,16 +164,16 @@ int get_elapsed_time(int start_time) /** * Create all the various globally accessible gui windows */ -void createGuiWindows() +void createGuiWindows(Network *network) { // Create dialogs chatWindow = new ChatWindow( - config.getValue("homeDir", "") + std::string("/chatlog.txt")); + config.getValue("homeDir", "") + std::string("/chatlog.txt"), network); menuWindow = new MenuWindow(); - statusWindow = new StatusWindow(); + statusWindow = new StatusWindow(player_node); miniStatusWindow = new MiniStatusWindow(); - buyDialog = new BuyDialog(); - sellDialog = new SellDialog(); + buyDialog = new BuyDialog(network); + sellDialog = new SellDialog(network); buySellDialog = new BuySellDialog(); inventoryWindow = new InventoryWindow(); npcTextDialog = new NpcTextDialog(); @@ -209,9 +182,9 @@ void createGuiWindows() //newSkillWindow = new NewSkillDialog(); setupWindow = new Setup(); minimap = new Minimap(); - equipmentWindow = new EquipmentWindow(); + equipmentWindow = new EquipmentWindow(player_node->mEquipment); chargeDialog = new ChargeDialog(); - tradeWindow = new TradeWindow(); + tradeWindow = new TradeWindow(network); //buddyWindow = new BuddyWindow(); helpWindow = new HelpWindow(); debugWindow = new DebugWindow(); @@ -278,9 +251,9 @@ void destroyGuiWindows() delete debugWindow; } -void do_init() +void do_init(Network *network) { - engine->changeMap(map_path); + beingManager = new BeingManager(network); // Initialize timers tick_time = 0; @@ -288,18 +261,9 @@ void do_init() SDL_AddTimer(1000, nextSecond, NULL); // Seconds counter // Initialize beings - player_node = createBeing(account_ID, 0, engine->getCurrentMap()); - player_node->x = startX; - player_node->y = startY; - player_node->setHairColor(player_info->hairColor); - player_node->setHairStyle(player_info->hairStyle); - - if (player_info->weapon == 11) - { - player_info->weapon = 2; - } - - player_node->setWeapon(player_info->weapon); + beingManager->setPlayer(player_node); + player_node->setNetwork(network); + engine->changeMap(map_path); // Initialize joypad SDL_InitSubSystem(SDL_INIT_JOYSTICK); @@ -350,23 +314,42 @@ bool saveScreenshot(SDL_Surface *screenshot) return ImageWriter::writePNG(screenshot, filename.str()); } -void game() +void game(Network *network) { - // Needs to be initialised _before_ the engine is created... - inventory = new Inventory(); - - createGuiWindows(); - engine = new Engine(); - do_init(); + createGuiWindows(network); + engine = new Engine(network); + do_init(network); int gameTime = tick_time; - while (state == GAME_STATE) + BeingHandler beingHandler; + BuySellHandler buySellHandler; + ChatHandler chatHandler; + EquipmentHandler equipmentHandler; + InventoryHandler inventoryHandler; + ItemHandler itemHandler; + NPCHandler npcHandler; + PlayerHandler playerHandler; + SkillHandler skillHandler; + TradeHandler tradeHandler; + + network->registerHandler(&beingHandler); + network->registerHandler(&buySellHandler); + network->registerHandler(&chatHandler); + network->registerHandler(&equipmentHandler); + network->registerHandler(&inventoryHandler); + network->registerHandler(&itemHandler); + network->registerHandler(&npcHandler); + network->registerHandler(&playerHandler); + network->registerHandler(&skillHandler); + network->registerHandler(&tradeHandler); + + while (!done) { // Handle all necessary game logic while (get_elapsed_time(gameTime) > 0) { - do_input(); + do_input(network); engine->logic(); gameTime++; } @@ -385,22 +368,22 @@ void game() SDL_Delay(10); } - // Handle network stuff and flush it - do_parse(); - flush(); + // Handle network stuff + while(network->messageReady()) + network->dispatchMessages(); + + network->flush(); } - do_exit(); + do_exit(network); } -void do_exit() +void do_exit(Network *network) { delete engine; delete player_node; destroyGuiWindows(); - closeConnection(); - - delete inventory; + network->disconnect(); if (joypad != NULL) { @@ -408,7 +391,7 @@ void do_exit() } } -void do_input() +void do_input(Network *network) { // Get the state of the keyboard keys Uint8* keys; @@ -503,7 +486,7 @@ void do_input() // Quit by pressing Enter if the exit confirm is there if (exitConfirm) { - state = EXIT_STATE; + done = true; } // Close the Browser if opened else if (helpWindow->isVisible()) @@ -528,12 +511,12 @@ void do_input() case SDLK_z: if (!chatWindow->isFocused()) { - Uint32 id = find_floor_item_by_cor( + FloorItem *item = find_floor_item_by_cor( player_node->x, player_node->y); // If none below the player, try the tile in front of // the player - if (!id) { + if (!item) { Uint16 x = player_node->x; Uint16 y = player_node->y; @@ -549,11 +532,11 @@ void do_input() case Being::SE: x++; y++; break; default: break; } - id = find_floor_item_by_cor(x, y); + item = find_floor_item_by_cor(x, y); } - if (id) - pickUp(id); + if (item) + player_node->pickUp(item); used = true; } @@ -595,11 +578,7 @@ void do_input() break; } - switch (player_node->action) - { - case Being::STAND: action(2, 0); break; - case Being::SIT: action(3, 0); break; - } + player_node->toggleSit(); used = true; break; @@ -647,9 +626,7 @@ void do_input() if (emotion) { - MessageOut outMsg; - outMsg.writeInt16(0x00bf); - outMsg.writeInt8(emotion); + player_node->emote(emotion); action_time = false; used = true; } @@ -660,7 +637,7 @@ void do_input() // Quit event else if (event.type == SDL_QUIT) { - state = EXIT_STATE; + done = true; } // Push input to GUI when not used @@ -677,1258 +654,111 @@ void do_input() { Uint16 x = player_node->x; Uint16 y = player_node->y; - Sint16 xDirection = 0; - Sint16 yDirection = 0; Being::Direction Direction = Being::DIR_NONE; // Translate pressed keys to movement and direction if (keys[SDLK_UP] || keys[SDLK_KP8] || joy[JOY_UP]) { - yDirection = -1; - if (player_node->action != Being::WALK) - Direction = Being::NORTH; + Direction = Being::NORTH; } if (keys[SDLK_DOWN] || keys[SDLK_KP2] || joy[JOY_DOWN]) { - yDirection = 1; - if (player_node->action != Being::WALK) - Direction = Being::SOUTH; + Direction = Being::SOUTH; } if (keys[SDLK_LEFT] || keys[SDLK_KP4] || joy[JOY_LEFT]) { - xDirection = -1; - if (player_node->action != Being::WALK) + // Allow diagonal walking + // TODO: Make this nicer, once we got a bitfield for directions + if (Direction == Being::NORTH) + Direction = Being::NW; + else if (Direction == Being::SOUTH) + Direction = Being::SW; + else Direction = Being::WEST; } if (keys[SDLK_RIGHT] || keys[SDLK_KP6] || joy[JOY_RIGHT]) { - xDirection = 1; - if (player_node->action != Being::WALK) + // Allow diagonal walking + // TODO: Make this nicer, once we got a bitfield for directions + if (Direction == Being::NORTH) + Direction = Being::NE; + else if (Direction == Being::SOUTH) + Direction = Being::SE; + else Direction = Being::EAST; } if (keys[SDLK_KP1]) // Bottom Left { - xDirection = -1; - yDirection = 1; - if (player_node->action != Being::WALK) - Direction = Being::SW; + Direction = Being::SW; } if (keys[SDLK_KP3]) // Bottom Right { - xDirection = 1; - yDirection = 1; - if (player_node->action != Being::WALK) - Direction = Being::SE; + Direction = Being::SE; } if (keys[SDLK_KP7]) // Top Left { - xDirection = -1; - yDirection = -1; - if (player_node->action != Being::WALK) - Direction = Being::NW; + Direction = Being::NW; } if (keys[SDLK_KP9]) // Top Right { - xDirection = 1; - yDirection = -1; - if (player_node->action != Being::WALK) - Direction = Being::NE; + Direction = Being::NE; } - Map *tiledMap = engine->getCurrentMap(); - - // Allow keyboard control to interrupt an existing path - if ((xDirection != 0 || yDirection != 0) && - player_node->action == Being::WALK) - { - player_node->setDestination(x, y); - } - - if (player_node->action != Being::WALK) - { - // Prevent skipping corners over colliding tiles - if ((xDirection != 0) && tiledMap->tileCollides(x + xDirection, y)) - xDirection = 0; - if ((yDirection != 0) && tiledMap->tileCollides(x, y + yDirection)) - yDirection = 0; - - // Choose a straight direction when diagonal target is blocked - if ((yDirection != 0) && (xDirection != 0) && - !tiledMap->getWalk(x + xDirection, y + yDirection)) - xDirection = 0; - - // Walk to where the player can actually go - if (((xDirection != 0) || (yDirection != 0)) && - tiledMap->getWalk(x + xDirection, y + yDirection)) - { - walk(x + xDirection, y + yDirection, Direction); - player_node->setDestination(x + xDirection, y + yDirection); - } - else if (Direction != Being::DIR_NONE) - { - // Update the player direction to where he wants to walk - // Warning: Not communicated to the server yet - player_node->direction = Direction; - } - } + player_node->walk(Direction); // Attacking monsters - if (player_node->action == Being::STAND) - { - if (keys[SDLK_LCTRL] || keys[SDLK_RCTRL] || joy[JOY_BTN0]) - { - Being *monster = attack(x, y, player_node->direction); - if (monster == NULL && autoTarget != NULL && - monster != player_node) - { - attack(autoTarget); - } - else if ((keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]) && monster != player_node) - { - autoTarget = monster; - } - } - } - - if (joy[JOY_BTN1]) - { - Uint32 id = find_floor_item_by_cor(player_node->x, player_node->y); - - if (id) - pickUp(id); - } - else if (joy[JOY_BTN2] && action_time) + if (keys[SDLK_LCTRL] || keys[SDLK_RCTRL] || joy[JOY_BTN0]) { - if (player_node->action == Being::STAND) - action(2, 0); - else if (player_node->action == Being::SIT) - action(3, 0); - action_time = false; - } - } -} - -void do_parse() -{ - Map *tiledMap = engine->getCurrentMap(); - Equipment *equipment = Equipment::getInstance(); - - int n_items; - Being *being; - - // We need at least 2 bytes to identify a packet - while (packetReady()) - { - MessageIn msg = get_next_message(); - - // Parse packet based on their id - switch (msg.getId()) - { - case SMSG_LOGIN_SUCCESS: - // Connected to game server succesfully, set spawn point - msg.readInt32(); // server tick - msg.readCoordinates(player_node->x, player_node->y, - player_node->direction); - msg.skip(2); // unknown - break; - - // Received speech from being - case SMSG_BEING_CHAT: - { - Sint16 chatMsgLength = msg.readInt16() - 8; - being = findNode(msg.readInt32()); - - if (!being || chatMsgLength <= 0) - { - break; - } - - std::string chatMsg = msg.readString(chatMsgLength); - - chatWindow->chatLog(chatMsg, BY_OTHER); - - chatMsg.erase(0, chatMsg.find(" : ", 0) + 3); - being->setSpeech(chatMsg, SPEECH_TIME); - } - break; - - case SMSG_PLAYER_CHAT: - case SMSG_GM_CHAT: - { - Sint16 chatMsgLength = msg.readInt16() - 4; - - if (chatMsgLength <= 0) - { - break; - } - - std::string chatMsg = msg.readString(chatMsgLength); - - if (msg.getId() == SMSG_PLAYER_CHAT) - { - chatWindow->chatLog(chatMsg, BY_PLAYER); - - std::string::size_type pos = chatMsg.find(" : ", 0); - if (pos != std::string::npos) - { - chatMsg.erase(0, pos + 3); - } - player_node->setSpeech(chatMsg, SPEECH_TIME); - } - else - { - chatWindow->chatLog(chatMsg, BY_GM); - } - } - break; - - case SMSG_WALK_RESPONSE: - // It is assumed by the client any request to walk actually - // succeeds on the server. The plan is to have a correction - // message when the server senses the client has the wrong - // idea. - break; - - case SMSG_BEING_VISIBLE: - case SMSG_BEING_MOVE: - // Information about a being in range - { - Uint32 id = msg.readInt32(); - Uint16 speed = msg.readInt16(); - msg.readInt16(); // unknown - msg.readInt16(); // unknown - msg.readInt16(); // option - Uint16 job = msg.readInt16(); // class - - being = findNode(id); + Being *target = NULL; + bool newTarget = keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]; - if (being == NULL) - { - // Being with id >= 110000000 and job 0 are better - // known as ghosts, so don't create those. - if (job == 0 && id >= 110000000) - { - break; - } - - being = createBeing(id, job, tiledMap); - } - else if (msg.getId() == 0x0078) - { - being->clearPath(); - being->mFrame = 0; - being->walk_time = tick_time; - being->action = Being::STAND; - } - - // Prevent division by 0 when calculating frame - if (speed == 0) { speed = 150; } - - being->setWalkSpeed(speed); - being->job = job; - being->setHairStyle(msg.readInt16()); - being->setWeapon(msg.readInt16()); - msg.readInt16(); // head option bottom - - if (msg.getId() == SMSG_BEING_MOVE) - { - msg.readInt32(); // server tick - } - - msg.readInt16(); // shield - msg.readInt16(); // head option top - msg.readInt16(); // head option mid - being->setHairColor(msg.readInt16()); - msg.readInt16(); // unknown - msg.readInt16(); // head dir - msg.readInt16(); // guild - msg.readInt16(); // unknown - msg.readInt16(); // unknown - msg.readInt16(); // manner - msg.readInt16(); // karma - msg.readInt8(); // unknown - msg.readInt8(); // sex - - if (msg.getId() == SMSG_BEING_MOVE) - { - Uint16 srcX, srcY, dstX, dstY; - msg.readCoordinatePair(srcX, srcY, dstX, dstY); - being->action = Being::STAND; - being->x = srcX; - being->y = srcY; - being->setDestination(dstX, dstY); - } - else - { - msg.readCoordinates(being->x, being->y, - being->direction); - } - - msg.readInt8(); // unknown - msg.readInt8(); // unknown - msg.readInt8(); // unknown / sit - } - break; - - case SMSG_BEING_REMOVE: - // A being should be removed or has died - being = findNode(msg.readInt32()); - - if (being != NULL) - { - if (msg.readInt8() == 1) - { - // Death - switch (being->getType()) - { - case Being::MONSTER: - being->action = Being::MONSTER_DEAD; - being->mFrame = 0; - being->walk_time = tick_time; - break; - - default: - being->action = Being::DEAD; - break; - } - } - else - { - remove_node(being); - } - - if (being == autoTarget) - { - autoTarget = NULL; - } - } - break; - - case SMSG_PLAYER_UPDATE_1: - case SMSG_PLAYER_UPDATE_2: - case SMSG_PLAYER_MOVE: - // An update about a player, potentially including movement. - { - Uint32 id = msg.readInt32(); - Uint16 speed = msg.readInt16(); - msg.readInt16(); // option 1 - msg.readInt16(); // option 2 - msg.readInt16(); // option - Uint16 job = msg.readInt16(); - - being = findNode(id); - - if (being == NULL) - { - being = createBeing(id, job, tiledMap); - } - - being->setWalkSpeed(speed); - being->job = job; - being->setHairStyle(msg.readInt16()); - being->setWeaponById(msg.readInt16()); // item id 1 - msg.readInt16(); // item id 2 - msg.readInt16(); // head option bottom - - if (msg.getId() == SMSG_PLAYER_MOVE) - { - msg.readInt32(); // server tick - } - - msg.readInt16(); // head option top - msg.readInt16(); // head option mid - being->setHairColor(msg.readInt16()); - msg.readInt16(); // unknown - msg.readInt16(); // head dir - msg.readInt32(); // guild - msg.readInt32(); // emblem - msg.readInt16(); // manner - msg.readInt8(); // karma - msg.readInt8(); // sex - - if (msg.getId() == SMSG_PLAYER_MOVE) - { - Uint16 srcX, srcY, dstX, dstY; - msg.readCoordinatePair(srcX, srcY, dstX, dstY); - being->x = srcX; - being->y = srcY; - being->setDestination(dstX, dstY); - } - else - { - msg.readCoordinates(being->x, being->y, - being->direction); - } - - msg.readInt8(); // unknown - msg.readInt8(); // unknown - - if (msg.getId() == SMSG_PLAYER_UPDATE_1) - { - if (msg.readInt8() == 2) - { - being->action = Being::SIT; - } - } - else if (msg.getId() == SMSG_PLAYER_MOVE) - { - msg.readInt8(); // unknown - } - - msg.readInt8(); // Lv - msg.readInt8(); // unknown - - being->walk_time = tick_time; - being->mFrame = 0; - } - break; - - case SMSG_NPC_MESSAGE: - msg.readInt16(); // length - current_npc = msg.readInt32(); - npcTextDialog->addText(msg.readString(msg.getLength() - 8)); - npcListDialog->setVisible(false); - npcTextDialog->setVisible(true); - break; - - case SMSG_NPC_NEXT: - case SMSG_NPC_CLOSE: - // Next/Close button in NPC dialog, currently unused - break; - - case SMSG_TRADE_REQUEST: - // If a trade window or request window is already open, send a - // trade cancel to any other trade request. - // - // Note that it would be nice if the server would prevent this - // situation, and that the requesting player would get a - // special message about the player being occupied. - - if (tradeWindow->isVisible() || requestTradeDialogOpen) - { - MessageOut outMsg; - outMsg.writeInt16(CMSG_TRADE_RESPONSE); - outMsg.writeInt8(4); - break; - } - - requestTradeDialogOpen = true; - tradePartnerName = msg.readString(24); - new RequestTradeDialog(tradePartnerName); - break; - - case SMSG_TRADE_RESPONSE: - switch (msg.readInt8()) - { - case 0: // Too far away - chatWindow->chatLog("Trading isn't possible. " - "Trade partner is too far away.", - BY_SERVER); - break; - case 1: // Character doesn't exist - chatWindow->chatLog("Trading isn't possible. " - "Character doesn't exist.", - BY_SERVER); - break; - case 2: // Invite request check failed... - chatWindow->chatLog("Trade canceled due to an " - "unknown reason.", BY_SERVER); - break; - case 3: // Trade accepted - tradeWindow->reset(); - tradeWindow->setCaption( - "Trade: You and " + tradePartnerName); - tradeWindow->setVisible(true); - requestTradeDialogOpen = false; - break; - case 4: // Trade canceled - chatWindow->chatLog("Trade canceled.", BY_SERVER); - tradeWindow->setVisible(false); - break; - default: // Shouldn't happen as well, but to be sure - chatWindow->chatLog("Unhandled trade cancel packet", - BY_SERVER); - break; - } - break; - - case SMSG_TRADE_ITEM_ADD: - { - Sint32 amount = msg.readInt32(); - Sint16 type = msg.readInt16(); - msg.readInt8(); // identified flag - msg.readInt8(); // attribute - msg.readInt8(); // refine - msg.skip(8); // card (4 shorts) - - // TODO: handle also identified, etc - if (type == 0) { - tradeWindow->addMoney(amount); - } else { - tradeWindow->addItem(type, false, amount, false); - } - } - break; - - case SMSG_TRADE_ITEM_ADD_RESPONSE: - // Trade: New Item add response (was 0x00ea, now 01b1) - { - Item *item = inventory->getItem(msg.readInt16()); - Sint16 quantity = msg.readInt16(); - - switch (msg.readInt8()) - { - case 0: - // Successfully added item - if (item->isEquipment() && item->isEquipped()) - { - inventory->unequipItem(item); - } - tradeWindow->addItem(item->getId(), true, quantity, - item->isEquipment()); - item->increaseQuantity(-quantity); - break; - case 1: - // Add item failed - player overweighted - chatWindow->chatLog("Failed adding item. Trade " - "partner is over weighted.", - BY_SERVER); - break; - default: - chatWindow->chatLog("Failed adding item for " - "unknown reason.", BY_SERVER); - break; - } - } - break; - - case SMSG_TRADE_OK: - // 0 means ok from myself, 1 means ok from other; - tradeWindow->receivedOk(msg.readInt8() == 0); - break; - - case SMSG_TRADE_CANCEL: - chatWindow->chatLog("Trade canceled.", BY_SERVER); - tradeWindow->setVisible(false); - tradeWindow->reset(); - break; - - case SMSG_TRADE_COMPLETE: - chatWindow->chatLog("Trade completed.", BY_SERVER); - tradeWindow->setVisible(false); - tradeWindow->reset(); - break; - - case SMSG_PLAYER_INVENTORY: - { - // Only called on map load / warp. First reset all items - // to not load them twice on map change. - inventory->resetItems(); - msg.readInt16(); // length - Sint32 number = (msg.getLength() - 4) / 18; - - for (int loop = 0; loop < number; loop++) - { - Sint16 index = msg.readInt16(); - Sint16 itemId = msg.readInt16(); - msg.readInt8(); // type - msg.readInt8(); // identify flag - Sint16 amount = msg.readInt16(); - msg.skip(2); // unknown - msg.skip(8); // card (4 shorts) - - inventory->addItem(index, itemId, amount, false); - - // Trick because arrows are not considered equipment - if (itemId == 1199 || itemId == 529) - { - inventory->getItem(index)->setEquipment(true); - } - } - } - break; - - case SMSG_PLAYER_EQUIPMENT: - { - msg.readInt16(); // length - Sint32 number = (msg.getLength() - 4) / 20; - - for (int loop = 0; loop < number; loop++) - { - Sint16 index = msg.readInt16(); - Sint16 itemId = msg.readInt16(); - msg.readInt8(); // type - msg.readInt8(); // identify flag - msg.readInt16(); // equip type - Sint16 equipPoint = msg.readInt16(); - msg.readInt8(); // attribute - msg.readInt8(); // refine - msg.skip(8); // card - - inventory->addItem(index, itemId, 1, true); - - if (equipPoint) - { - int mask = 1; - int position = 0; - while (!(equipPoint & mask)) - { - mask <<= 1; - position++; - } - Item *item = inventory->getItem(index); - item->setEquipped(true); - equipment->setEquipment(position - 1, item); - } - } - } - break; - - case SMSG_ITEM_USE_RESPONSE: - { - Sint16 index = msg.readInt16(); - Sint16 amount = msg.readInt16(); - - if (msg.readInt8() == 0) { - chatWindow->chatLog("Failed to use item", BY_SERVER); - } else { - inventory->getItem(index)->setQuantity(amount); - } - } - break; - - case SMSG_PLAYER_WARP: - { - // Set new map path - map_path = "maps/" + msg.readString(16); - map_path = map_path.substr(0, map_path.rfind(".")) + - ".tmx.gz"; - - Uint16 x = msg.readInt16(); - Uint16 y = msg.readInt16(); - - logger->log("Warping to %s (%d, %d)", - map_path.c_str(), x, y); - - // Switch the actual map, deleting the previous one - engine->changeMap(map_path); - tiledMap = engine->getCurrentMap(); - - autoTarget = NULL; - current_npc = 0; - - player_node->action = Being::STAND; - player_node->mFrame = 0; - player_node->x = x; - player_node->y = y; - - // Send "map loaded" - MessageOut outMsg; - outMsg.writeInt16(CMSG_MAP_LOADED); - } - break; - - case SMSG_SKILL_FAILED: - // Action failed (ex. sit because you have not reached the - // right level) - CHATSKILL action; - action.skill = msg.readInt16(); - action.bskill = msg.readInt16(); - action.unused = msg.readInt16(); // unknown - action.success = msg.readInt8(); - action.reason = msg.readInt8(); - if (action.success != SKILL_FAILED && - action.bskill == BSKILL_EMOTE) - { - printf("Action: %d/%d", action.bskill, action.success); - } - chatWindow->chatLog(action); - break; - - case SMSG_PLAYER_STAT_UPDATE_1: - { - Sint16 type = msg.readInt16(); - Sint32 value = msg.readInt32(); - - switch (type) - { - //case 0x0000: - // player_node->setWalkSpeed(msg.readInt32()); - // break; - case 0x0005: player_info->hp = value; break; - case 0x0006: player_info->maxHp = value; break; - case 0x0007: player_info->mp = value; break; - case 0x0008: player_info->maxMp = value; break; - case 0x000b: player_info->lvl = value; break; - case 0x000c: - player_info->skillPoint = value; - skillDialog->setPoints(player_info->skillPoint); - break; - case 0x0018: - if (value >= player_info->maxWeight / 2 && - player_info->totalWeight < - player_info->maxWeight / 2) - { - weightNotice = new OkDialog("Message", - "You are carrying more then half your " - "weight. You are unable to regain " - "health.", - &weightNoticeListener); - } - player_info->totalWeight = value; - break; - case 0x0019: player_info->maxWeight = value; break; - case 0x0037: player_info->jobLvl = value; break; - case 0x0009: - player_info->statsPointsToAttribute = value; - break; - case 0x0029: player_info->ATK = value; break; - case 0x002b: player_info->MATK = value; break; - case 0x002d: player_info->DEF = value; break; - case 0x002f: player_info->MDEF = value; break; - case 0x0031: player_info->HIT = value; break; - case 0x0032: player_info->FLEE = value; break; - case 0x0035: player_node->aspd = value; break; - } + // A set target has highest priority + if (newTarget || !player_node->getTarget()) + { + Uint16 targetX = x, targetY = y; - if (player_info->hp == 0 && deathNotice == NULL) - { - deathNotice = new OkDialog("Message", - "You're now dead, press ok to restart", - &deathNoticeListener); - player_node->action = Being::DEAD; - } - } - break; - - // Stop walking - // case 0x0088: // Disabled because giving some problems - //if (being = findNode(readInt32(2))) { - // if (being->getId() != player_node->getId()) { - // being->action = STAND; - // being->mFrame = 0; - // set_coordinates(being->coordinates, - // readWord(6), readWord(8), - // get_direction(being->coordinates)); - // } - //} - //break; - - case SMSG_BEING_ACTION: + switch (player_node->direction) { - Being *srcBeing = findNode(msg.readInt32()); - Being *dstBeing = findNode(msg.readInt32()); - msg.readInt32(); // server tick - msg.readInt32(); // src speed - msg.readInt32(); // dst speed - Sint16 param1 = msg.readInt16(); - msg.readInt16(); // param 2 - Sint8 type = msg.readInt8(); - msg.readInt16(); // param 3 - - switch (type) - { - case 0: // Damage - if (dstBeing == NULL) break; - - dstBeing->setDamage(param1, SPEECH_TIME); - - if (srcBeing != NULL && - srcBeing != player_node) - { - // buggy - srcBeing->action = Being::ATTACK; - srcBeing->mFrame = 0; - srcBeing->walk_time = tick_time; - } - break; - - case 2: // Sit - if (srcBeing == NULL) break; - srcBeing->mFrame = 0; - srcBeing->action = Being::SIT; - break; - - case 3: // Stand up - if (srcBeing == NULL) break; - srcBeing->mFrame = 0; - srcBeing->action = Being::STAND; - break; - } - } - break; - - case SMSG_PLAYER_STAT_UPDATE_2: - switch (msg.readInt16()) { - case 0x0001: - player_info->xp = msg.readInt32(); - break; - case 0x0002: - player_info->jobXp = msg.readInt32(); - break; - case 0x0014: - player_info->gp = msg.readInt32(); + case Being::SOUTH: + targetY++; break; - case 0x0016: - player_info->xpForNextLevel = msg.readInt32(); - break; - case 0x0017: - player_info->jobXpForNextLevel = msg.readInt32(); - break; - } - break; - - case SMSG_BEING_LEVELUP: - if ((Uint32)msg.readInt32() == player_node->getId()) { - logger->log("Level up"); - sound.playSfx("sfx/levelup.ogg"); - } else { - logger->log("Someone else went level up"); - } - msg.readInt32(); // type - break; - - case SMSG_BEING_EMOTION: - if (!(being = findNode(msg.readInt32()))) - { - break; - } - - being->emotion = msg.readInt8(); - being->emotion_time = EMOTION_TIME; - break; - - case SMSG_PLAYER_STAT_UPDATE_3: - { - Sint32 type = msg.readInt32(); - Sint32 base = msg.readInt32(); - Sint32 bonus = msg.readInt32(); - Sint32 total = base + bonus; - - switch (type) { - case 0x000d: player_info->STR = total; break; - case 0x000e: player_info->AGI = total; break; - case 0x000f: player_info->VIT = total; break; - case 0x0010: player_info->INT = total; break; - case 0x0011: player_info->DEX = total; break; - case 0x0012: player_info->LUK = total; break; - } - } - break; - - case SMSG_NPC_BUY_SELL_CHOICE: - buyDialog->setVisible(false); - buyDialog->reset(); - sellDialog->setVisible(false); - sellDialog->reset(); - buySellDialog->setVisible(true); - current_npc = msg.readInt32(); - break; - - case SMSG_NPC_BUY: - msg.readInt16(); // length - n_items = (msg.getLength() - 4) / 11; - buyDialog->reset(); - buyDialog->setMoney(player_info->gp); - buyDialog->setVisible(true); - - for (int k = 0; k < n_items; k++) - { - Sint32 value = msg.readInt32(); - msg.readInt32(); // DCvalue - msg.readInt8(); // type - Sint16 itemId = msg.readInt16(); - buyDialog->addItem(itemId, value); - } - break; - - case SMSG_NPC_SELL: - msg.readInt16(); // length - n_items = (msg.getLength() - 4) / 10; - if (n_items > 0) { - sellDialog->reset(); - sellDialog->setVisible(true); - - for (int k = 0; k < n_items; k++) - { - Sint16 index = msg.readInt16(); - Sint32 value = msg.readInt32(); - msg.readInt32(); // OCvalue - - Item *item = inventory->getItem(index); - if (item && !(item->isEquipped())) { - sellDialog->addItem(item, value); - } - } - } - else { - chatWindow->chatLog("Nothing to sell", BY_SERVER); - current_npc = 0; - } - break; - - case SMSG_NPC_BUY_RESPONSE: - if (msg.readInt8() == 0) { - chatWindow->chatLog("Thanks for buying", BY_SERVER); - } else { - chatWindow->chatLog("Unable to buy", BY_SERVER); - } - break; - - case SMSG_NPC_SELL_RESPONSE: - if (msg.readInt8() == 0) { - chatWindow->chatLog("Thanks for selling", BY_SERVER); - } else { - chatWindow->chatLog("Unable to sell", BY_SERVER); - } - break; - - case SMSG_PLAYER_INVENTORY_ADD: - { - Sint16 index = msg.readInt16(); - Sint16 amount = msg.readInt16(); - Sint16 itemId = msg.readInt16(); - msg.readInt8(); // identify flag - msg.readInt8(); // attribute - msg.readInt8(); // refine - msg.skip(8); // card - Sint16 equipType = msg.readInt16(); - msg.readInt8(); // type - Sint8 fail = msg.readInt8(); - - if (fail > 0) { - chatWindow->chatLog("Unable to pick up item", - BY_SERVER); - } else { - inventory->addItem(index, itemId, amount, - equipType != 0); - } - } - break; - - case SMSG_PLAYER_INVENTORY_REMOVE: - { - Sint16 index = msg.readInt16(); - Sint16 amount = msg.readInt16(); - inventory->getItem(index)->increaseQuantity(-amount); - } - break; - - case SMSG_PLAYER_INVENTORY_USE: - { - Sint16 index = msg.readInt16(); - msg.readInt16(); // item id - msg.readInt32(); // id - Sint16 amountLeft = msg.readInt16(); - msg.readInt8(); // type - - inventory->getItem(index)->setQuantity(amountLeft); - } - break; - - case SMSG_PLAYER_SKILLS: - msg.readInt16(); // length - n_items = (msg.getLength() - 4) / 37; - skillDialog->cleanList(); - - for (int k = 0; k < n_items; k++) - { - Sint16 skillId = msg.readInt16(); - msg.readInt16(); // target type - msg.readInt16(); // unknown - Sint16 level = msg.readInt16(); - Sint16 sp = msg.readInt16(); - msg.readInt16(); // range - std::string skillName = msg.readString(24); - Sint8 up = msg.readInt8(); - - if (level != 0 || up != 0) - { - if (skillDialog->hasSkill(skillId)) { - skillDialog->setSkill(skillId, level, sp); - } - else { - skillDialog->addSkill(skillId, level, sp); - } - } - } - break; - - case 0x010c: - // Display MVP player - msg.readInt32(); // id - chatWindow->chatLog("MVP player", BY_SERVER); - break; - - case SMSG_ITEM_VISIBLE: - case SMSG_ITEM_DROPPED: - { - Uint32 id = msg.readInt32(); - Sint16 itemId = msg.readInt16(); - msg.readInt8(); // identify flag - Uint16 x = msg.readInt16(); - Uint16 y = msg.readInt16(); - msg.skip(4); // amount,subX,subY / subX,subY,amount - - add_floor_item(new FloorItem(id, itemId, x, y, tiledMap)); - } - break; - - case SMSG_ITEM_REMOVE: - remove_floor_item(msg.readInt32()); - break; - - case SMSG_NPC_CHOICE: - msg.readInt16(); // length - current_npc = msg.readInt32(); - npcListDialog->parseItems(msg.readString(msg.getLength() - 8)); - npcListDialog->setVisible(true); - break; - - case SMSG_BEING_CHANGE_LOOKS: - if (!(being = findNode(msg.readInt32()))) - { - break; - } - switch (msg.readInt8()) { - case 1: - being->setHairStyle(msg.readInt8()); - break; - case 2: - being->setWeapon(msg.readInt8()); - break; - case 6: - being->setHairColor(msg.readInt8()); - break; - default: - msg.readInt8(); // unsupported + case Being::WEST: + targetX--; break; - } - break; - - case SMSG_PLAYER_EQUIP: - { - Sint16 index = msg.readInt16(); - Sint16 equipPoint = msg.readInt16(); - Sint8 type = msg.readInt8(); - - logger->log("Equipping: %i %i %i", - index, equipPoint, type); - if (type == 0) { - chatWindow->chatLog("Unable to equip.", BY_SERVER); - } - else if (equipPoint) - { - // Unequip any existing equipped item in this position - int mask = 1; - int position = 0; - while (!(equipPoint & mask)) { - mask <<= 1; - position++; - } - logger->log("Position %i", position - 1); - Item *item = equipment->getEquipment(position - 1); - if (item) { - item->setEquipped(false); - } - - item = inventory->getItem(index); - item->setEquipped(true); - equipment->setEquipment(position - 1, item); - player_node->setWeaponById(item->getId()); - } - } - break; - - case 0x01d7: - // Equipment related - { - being = findNode(msg.readInt32()); - msg.readInt8(); // equip point - Sint16 itemId1 = msg.readInt16(); - msg.readInt16(); // item id 2 - - if (being != NULL) - { - being->setWeaponById(itemId1); - } - } - break; - - case SMSG_PLAYER_UNEQUIP: - { - Sint16 index = msg.readInt16(); - Sint16 equipPoint = msg.readInt16(); - Sint8 type = msg.readInt8(); - - if (type == 0) { - chatWindow->chatLog("Unable to unequip.", BY_SERVER); + case Being::NORTH: + targetY--; break; - } - if (equipPoint == 0) { - // No point given, no point in searching + case Being::EAST: + targetX++; break; - } - - int mask = 1; - int position = 0; - while (!(equipPoint & mask)) { - mask <<= 1; - position++; - } - - Item *item = inventory->getItem(index); - - if (item != NULL) - { - item->setEquipped(false); - - switch (item->getId()) { - case 529: - case 1199: - equipment->setArrows(NULL); - break; - case 521: - case 522: - case 530: - case 536: - case 1200: - case 1201: - player_node->setWeapon(0); - // TODO: Why this break? Shouldn't a weapon be - // unequipped in inventory too? - break; - default: - equipment->removeEquipment(position - 1); - break; - } - logger->log("Unequipping: %i %i(%i) %i", - index, equipPoint, type, position - 1); - } - } - break; - - case SMSG_PLAYER_ARROW_EQUIP: - { - Sint16 id = msg.readInt16(); - - if (id > 1) { - Item *item = inventory->getItem(id); - if (item) { - item->setEquipped(true); - equipment->setArrows(item); - logger->log("Arrows equipped: %i", id); - } - } } - break; - case SMSG_PLAYER_ARROW_MESSAGE: - { - Sint16 type = msg.readInt16(); - - switch (type) { - case 0: - chatWindow->chatLog("Equip arrows first", - BY_SERVER); - break; - default: - logger->log("0x013b: Unhandled message %i", type); - break; - } - } - break; - - case SMSG_PLAYER_STAT_UPDATE_4: - { - Sint16 type = msg.readInt16(); - Sint8 fail = msg.readInt8(); - Sint8 value = msg.readInt8(); - - if (fail == 1) - { - switch (type) { - case 0x000d: player_info->STR = value; break; - case 0x000e: player_info->AGI = value; break; - case 0x000f: player_info->VIT = value; break; - case 0x0010: player_info->INT = value; break; - case 0x0011: player_info->DEX = value; break; - case 0x0012: player_info->LUK = value; break; - } - } - } - break; - - // Updates stats and status points - case SMSG_PLAYER_STAT_UPDATE_5: - player_info->statsPointsToAttribute = msg.readInt16(); - player_info->STR = msg.readInt8(); - player_info->STRUp = msg.readInt8(); - player_info->AGI = msg.readInt8(); - player_info->AGIUp = msg.readInt8(); - player_info->VIT = msg.readInt8(); - player_info->VITUp = msg.readInt8(); - player_info->INT = msg.readInt8(); - player_info->INTUp = msg.readInt8(); - player_info->DEX = msg.readInt8(); - player_info->DEXUp = msg.readInt8(); - player_info->LUK = msg.readInt8(); - player_info->LUKUp = msg.readInt8(); - player_info->ATK = msg.readInt16(); // ATK - player_info->ATKBonus = msg.readInt16(); // ATK bonus - player_info->MATK = msg.readInt16(); // MATK max - player_info->MATKBonus = msg.readInt16(); // MATK min - player_info->DEF = msg.readInt16(); // DEF - player_info->DEFBonus = msg.readInt16(); // DEF bonus - player_info->MDEF = msg.readInt16(); // MDEF - player_info->MDEFBonus = msg.readInt16(); // MDEF bonus - player_info->HIT = msg.readInt16(); // HIT - player_info->FLEE = msg.readInt16(); // FLEE - player_info->FLEEBonus = msg.readInt16(); // FLEE bonus - msg.readInt16(); // critical - msg.readInt16(); // unknown - break; - - case SMSG_PLAYER_STAT_UPDATE_6: - switch (msg.readInt16()) { - case 0x0020: player_info->STRUp = msg.readInt8(); break; - case 0x0021: player_info->AGIUp = msg.readInt8(); break; - case 0x0022: player_info->VITUp = msg.readInt8(); break; - case 0x0023: player_info->INTUp = msg.readInt8(); break; - case 0x0024: player_info->DEXUp = msg.readInt8(); break; - case 0x0025: player_info->LUKUp = msg.readInt8(); break; - } - break; + // Attack priorioty is: Monster, Player, auto target + target = beingManager->findBeing( + targetX, targetY, Being::MONSTER); + if (!target) + target = beingManager->findBeing( + targetX, targetY, Being::PLAYER); + } - case SMSG_BEING_NAME_RESPONSE: - if ((being = findNode(msg.readInt32()))) - { - being->setName(msg.readString(24)); - } - break; - - case SMSG_WHO_ANSWER: - { - std::stringstream userMsg; - userMsg << "Online users: "; - userMsg << msg.readInt32(); - chatWindow->chatLog(userMsg.str(), BY_SERVER); - } - break; + player_node->attack(target, newTarget); + } - case 0x0119: - // Change in players look - break; + if (joy[JOY_BTN1]) + { + FloorItem *item = find_floor_item_by_cor( + player_node->x, player_node->y); - default: - // Manage non implemented packets - logger->log("Unhandled packet: %x", msg.getId()); - break; + if (item) + player_node->pickUp(item); + } + else if (joy[JOY_BTN2] && action_time) + { + player_node->toggleSit(); + action_time = false; } - - skip(msg.getLength()); } } |