void ItemHandler::handleMessage(MessageIn &msg) { switch (msg.getId()) { case GPMSG_ITEM_APPEAR: case GPMSG_ITEMS: { while (msg.getUnreadLength()) { int itemId = msg.readInt16(); int x = msg.readInt16(); int y = msg.readInt16(); int id = (x << 16) | y; // dummy id if (itemId) { actorSpriteManager->createItem(id, itemId, Vector(x, y)); } else if (FloorItem *item = actorSpriteManager->findItem(id)) { actorSpriteManager->destroy(item); } } } break; } }
void InventoryHandler::handleMessage(MessageIn &msg) { switch (msg.getId()) { case GPMSG_INVENTORY_FULL: player_node->clearInventory(); // no break! case GPMSG_INVENTORY: while (msg.getUnreadLength()) { int slot = msg.readInt8(); if (slot == 255) { player_node->setMoney(msg.readInt32()); continue; } int id = msg.readInt16(); if (slot < EQUIPMENT_SIZE) { player_node->mEquipment->setEquipment(slot, id); } else if (slot >= 32 && slot < 32 + INVENTORY_SIZE) { int amount = id ? msg.readInt8() : 0; player_node->setInvItem(slot - 32, id, amount); } }; break; } }
void ItemHandler::handleMessage(MessageIn &msg) { Uint32 id; Uint16 x, y; int itemId; switch (msg.getId()) { case SMSG_ITEM_VISIBLE: case SMSG_ITEM_DROPPED: id = msg.readInt32(); itemId = msg.readInt16(); msg.readInt8(); // identify flag x = msg.readInt16(); y = msg.readInt16(); msg.skip(4); // amount,subX,subY / subX,subY,amount floorItemManager->create(id, itemId, x, y, engine->getCurrentMap()); break; case SMSG_ITEM_REMOVE: FloorItem *item; item = floorItemManager->findById(msg.readInt32()); if (item) floorItemManager->destroy(item); break; } }
void ItemHandler::handleMessage(MessageIn &msg) { switch (msg.getId()) { case GPMSG_ITEM_APPEAR: case GPMSG_ITEMS: { while (msg.getUnreadLength()) { int itemId = msg.readInt16(); int x = msg.readInt16(); int y = msg.readInt16(); int id = (x << 16) | y; // dummy id if (itemId) { floorItemManager->create(id, itemId, x / 32, y / 32, engine->getCurrentMap()); } else if (FloorItem *item = floorItemManager->findById(id)) { floorItemManager->destroy(item); } } } break; } }
void ItemHandler::handleMessage(MessageIn &msg) { switch (msg.getId()) { case SMSG_ITEM_VISIBLE: case SMSG_ITEM_DROPPED: { int id = msg.readInt32(); int itemId = msg.readInt16(); msg.readInt8(); // identify flag int x = msg.readInt16(); int y = msg.readInt16(); msg.skip(4); // amount,subX,subY / subX,subY,amount Game *game = Game::instance(); if (!game) break; if (Map *map = game->getCurrentMap()) actorSpriteManager->createItem(id, itemId, map->getTileCenter(x, y)); } break; case SMSG_ITEM_REMOVE: if (FloorItem *item = actorSpriteManager->findItem(msg.readInt32())) actorSpriteManager->destroyActor(item); break; } }
void GameHandler::handleNpc(GameClient &client, MessageIn &message) { int id = message.readInt16(); Actor *actor = findActorNear(client.character, id); if (!actor || actor->getType() != OBJECT_NPC) { sendNpcError(client, id, "Not close enough to NPC\n"); return; } Being *npc = static_cast<Being*>(actor); switch (message.getId()) { case PGMSG_NPC_SELECT: Npc::integerReceived(client.character, message.readInt8()); break; case PGMSG_NPC_NUMBER: Npc::integerReceived(client.character, message.readInt32()); break; case PGMSG_NPC_STRING: Npc::stringReceived(client.character, message.readString()); break; case PGMSG_NPC_TALK: Npc::start(npc, client.character); break; case PGMSG_NPC_TALK_NEXT: default: Npc::resume(client.character); break; } }
void Network::dispatchMessages() { while (messageReady()) { MessageIn msg = getNextMessage(); MessageHandlerIterator iter = mMessageHandlers.find(msg.getId()); if (msg.getLength() == 0) logger->error("Zero length packet received. Exiting."); if (iter != mMessageHandlers.end()) { iter->second->handleMessage(msg); } else { logger->log("Unhandled packet: %x", msg.getId()); } skip(msg.getLength()); } }
void GameHandler::handleTrade(GameClient &client, MessageIn &message) { auto *characterComponent = client.character->getComponent<CharacterComponent>(); int databaseId = characterComponent->getDatabaseID(); std::stringstream str; Trade *t = characterComponent->getTrading(); if (!t) return; switch (message.getId()) { case PGMSG_TRADE_CANCEL: t->cancel(); break; case PGMSG_TRADE_CONFIRM: t->confirm(client.character); break; case PGMSG_TRADE_AGREED: t->agree(client.character); // log transaction accountHandler->sendTransaction(databaseId, TRANS_TRADE_END, "User finished trading"); break; case PGMSG_TRADE_SET_MONEY: { int money = message.readInt32(); t->setMoney(client.character, money); // log transaction str << "User added " << money << " money to trade."; accountHandler->sendTransaction(databaseId, TRANS_TRADE_MONEY, str.str()); } break; case PGMSG_TRADE_ADD_ITEM: { int slot = message.readInt8(); t->addItem(client.character, slot, message.readInt8()); // log transaction str << "User add item from slot " << slot; accountHandler->sendTransaction(databaseId, TRANS_TRADE_ITEM, str.str()); } break; } }
void ChatHandler::handleMessage(MessageIn &msg) { switch (msg.getId()) { case GPMSG_SAY: handleGameChatMessage(msg); break; case CPMSG_ENTER_CHANNEL_RESPONSE: handleEnterChannelResponse(msg); break; case CPMSG_LIST_CHANNELS_RESPONSE: handleListChannelsResponse(msg); break; case CPMSG_PRIVMSG: handlePrivateMessage(msg); break; case CPMSG_ANNOUNCEMENT: handleAnnouncement(msg); break; case CPMSG_PUBMSG: handleChatMessage(msg); break; case CPMSG_QUIT_CHANNEL_RESPONSE: handleQuitChannelResponse(msg); break; case CPMSG_LIST_CHANNELUSERS_RESPONSE: handleListChannelUsersResponse(msg); break; case CPMSG_CHANNEL_EVENT: handleChannelEvent(msg); break; case CPMSG_WHO_RESPONSE: handleWhoResponse(msg); break; } }
void EffectHandler::handleMessage(MessageIn &msg) { switch (msg.getId()) { case GPMSG_CREATE_EFFECT_POS: handleCreateEffectPos(msg); break; case GPMSG_CREATE_EFFECT_BEING: handleCreateEffectBeing(msg); break; case GPMSG_CREATE_TEXT_PARTICLE: handleCreateTextParticle(msg); break; case GPMSG_SHAKE: handleShake(msg); break; default: break; } }
void BuySellHandler::handleMessage(MessageIn &msg) { Being *being = beingManager->findBeing(msg.readInt16()); if (!being || being->getType() != Being::NPC) { return; } current_npc = being->getId(); switch (msg.getId()) { case GPMSG_NPC_BUY: buyDialog->reset(); buyDialog->setMoney(player_node->getMoney()); buyDialog->setVisible(true); while (msg.getUnreadLength()) { int itemId = msg.readInt16(); int amount = msg.readInt16(); int value = msg.readInt16(); buyDialog->addItem(itemId, amount, value); } break; case GPMSG_NPC_SELL: sellDialog->setMoney(player_node->getMoney()); sellDialog->reset(); sellDialog->setVisible(true); while (msg.getUnreadLength()) { int itemId = msg.readInt16(); int amount = msg.readInt16(); int value = msg.readInt16(); sellDialog->addItem(new Item(itemId, amount, false), value); } break; } }
void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg) { GameServer *server = static_cast<GameServer *>(comp); switch (msg.getId()) { case GAMSG_REGISTER: { LOG_DEBUG("GAMSG_REGISTER"); // TODO: check the credentials of the game server server->address = msg.readString(); server->port = msg.readInt16(); const std::string password = msg.readString(); // checks the version of the remote item database with our local copy unsigned int dbversion = msg.readInt32(); LOG_INFO("Game server uses itemsdatabase with version " << dbversion); LOG_DEBUG("AGMSG_REGISTER_RESPONSE"); MessageOut outMsg(AGMSG_REGISTER_RESPONSE); if (dbversion == storage->getItemDatabaseVersion()) { LOG_DEBUG("Item databases between account server and " "gameserver are in sync"); outMsg.writeInt16(DATA_VERSION_OK); } else { LOG_DEBUG("Item database of game server has a wrong version"); outMsg.writeInt16(DATA_VERSION_OUTDATED); } if (password == Configuration::getValue("net_password", "changeMe")) { outMsg.writeInt16(PASSWORD_OK); // transmit global world state variables std::map<std::string, std::string> variables; variables = storage->getAllWorldStateVars(Storage::WorldMap); for (std::map<std::string, std::string>::iterator i = variables.begin(); i != variables.end(); i++) { outMsg.writeString(i->first); outMsg.writeString(i->second); } comp->send(outMsg); } else { LOG_INFO("The password given by " << server->address << ':' << server->port << " was bad."); outMsg.writeInt16(PASSWORD_BAD); comp->disconnect(outMsg); break; } LOG_INFO("Game server " << server->address << ':' << server->port << " wants to register " << (msg.getUnreadLength() / 2) << " maps."); while (msg.getUnreadLength()) { int id = msg.readInt16(); LOG_INFO("Registering map " << id << '.'); if (GameServer *s = getGameServerFromMap(id)) { LOG_ERROR("Server Handler: map is already registered by " << s->address << ':' << s->port << '.'); } else { MessageOut outMsg(AGMSG_ACTIVE_MAP); // Map variables outMsg.writeInt16(id); std::map<std::string, std::string> variables; variables = storage->getAllWorldStateVars(id); // Map vars number outMsg.writeInt16(variables.size()); for (std::map<std::string, std::string>::iterator i = variables.begin(); i != variables.end(); i++) { outMsg.writeString(i->first); outMsg.writeString(i->second); } // Persistent Floor Items std::list<FloorItem> items; items = storage->getFloorItemsFromMap(id); outMsg.writeInt16(items.size()); //number of floor items // Send each map item: item_id, amount, pos_x, pos_y for (std::list<FloorItem>::iterator i = items.begin(); i != items.end(); ++i) { outMsg.writeInt32(i->getItemId()); outMsg.writeInt16(i->getItemAmount()); outMsg.writeInt16(i->getPosX()); outMsg.writeInt16(i->getPosY()); } comp->send(outMsg); MapStatistics &m = server->maps[id]; m.nbEntities = 0; m.nbMonsters = 0; } } } break; case GAMSG_PLAYER_DATA: { LOG_DEBUG("GAMSG_PLAYER_DATA"); int id = msg.readInt32(); if (Character *ptr = storage->getCharacter(id, NULL)) { deserializeCharacterData(*ptr, msg); if (!storage->updateCharacter(ptr)) { LOG_ERROR("Failed to update character " << id << '.'); } delete ptr; } else { LOG_ERROR("Received data for non-existing character " << id << '.'); } } break; case GAMSG_PLAYER_SYNC: { LOG_DEBUG("GAMSG_PLAYER_SYNC"); GameServerHandler::syncDatabase(msg); } break; case GAMSG_REDIRECT: { LOG_DEBUG("GAMSG_REDIRECT"); int id = msg.readInt32(); std::string magic_token(utils::getMagicToken()); if (Character *ptr = storage->getCharacter(id, NULL)) { int mapId = ptr->getMapId(); if (GameServer *s = getGameServerFromMap(mapId)) { registerGameClient(s, magic_token, ptr); MessageOut result(AGMSG_REDIRECT_RESPONSE); result.writeInt32(id); result.writeString(magic_token, MAGIC_TOKEN_LENGTH); result.writeString(s->address); result.writeInt16(s->port); comp->send(result); } else { LOG_ERROR("Server Change: No game server for map " << mapId << '.'); } delete ptr; } else { LOG_ERROR("Received data for non-existing character " << id << '.'); } } break; case GAMSG_PLAYER_RECONNECT: { LOG_DEBUG("GAMSG_PLAYER_RECONNECT"); int id = msg.readInt32(); std::string magic_token = msg.readString(MAGIC_TOKEN_LENGTH); if (Character *ptr = storage->getCharacter(id, NULL)) { int accountID = ptr->getAccountID(); AccountClientHandler::prepareReconnect(magic_token, accountID); delete ptr; } else { LOG_ERROR("Received data for non-existing character " << id << '.'); } } break; case GAMSG_GET_VAR_CHR: { int id = msg.readInt32(); std::string name = msg.readString(); std::string value = storage->getQuestVar(id, name); MessageOut result(AGMSG_GET_VAR_CHR_RESPONSE); result.writeInt32(id); result.writeString(name); result.writeString(value); comp->send(result); } break; case GAMSG_SET_VAR_CHR: { int id = msg.readInt32(); std::string name = msg.readString(); std::string value = msg.readString(); storage->setQuestVar(id, name, value); } break; case GAMSG_SET_VAR_WORLD: { std::string name = msg.readString(); std::string value = msg.readString(); // save the new value to the database storage->setWorldStateVar(name, value, Storage::WorldMap); // relay the new value to all gameservers for (ServerHandler::NetComputers::iterator i = clients.begin(); i != clients.end(); i++) { MessageOut varUpdateMessage(AGMSG_SET_VAR_WORLD); varUpdateMessage.writeString(name); varUpdateMessage.writeString(value); (*i)->send(varUpdateMessage); } } break; case GAMSG_SET_VAR_MAP: { int mapid = msg.readInt32(); std::string name = msg.readString(); std::string value = msg.readString(); storage->setWorldStateVar(name, value, mapid); } break; case GAMSG_BAN_PLAYER: { int id = msg.readInt32(); int duration = msg.readInt32(); storage->banCharacter(id, duration); } break; case GAMSG_CHANGE_PLAYER_LEVEL: { int id = msg.readInt32(); int level = msg.readInt16(); storage->setPlayerLevel(id, level); } break; case GAMSG_CHANGE_ACCOUNT_LEVEL: { int id = msg.readInt32(); int level = msg.readInt16(); // get the character so we can get the account id Character *c = storage->getCharacter(id, NULL); if (c) { storage->setAccountLevel(c->getAccountID(), level); } } break; case GAMSG_STATISTICS: { while (msg.getUnreadLength()) { int mapId = msg.readInt16(); ServerStatistics::iterator i = server->maps.find(mapId); if (i == server->maps.end()) { LOG_ERROR("Server " << server->address << ':' << server->port << " should not be sending stati" "stics for map " << mapId << '.'); // Skip remaining data. break; } MapStatistics &m = i->second; m.nbEntities = msg.readInt16(); m.nbMonsters = msg.readInt16(); int nb = msg.readInt16(); m.players.resize(nb); for (int j = 0; j < nb; ++j) { m.players[j] = msg.readInt32(); } } } break; case GCMSG_REQUEST_POST: { // Retrieve the post for user LOG_DEBUG("GCMSG_REQUEST_POST"); MessageOut result(CGMSG_POST_RESPONSE); // get the character id int characterId = msg.readInt32(); // send the character id of sender result.writeInt32(characterId); // get the character based on the id Character *ptr = storage->getCharacter(characterId, NULL); if (!ptr) { // Invalid character LOG_ERROR("Error finding character id for post"); break; } // get the post for that character Post *post = postalManager->getPost(ptr); // send the post if valid if (post) { for (unsigned int i = 0; i < post->getNumberOfLetters(); ++i) { // get each letter, send the sender's name, // the contents and any attachments Letter *letter = post->getLetter(i); result.writeString(letter->getSender()->getName()); result.writeString(letter->getContents()); std::vector<InventoryItem> items = letter->getAttachments(); for (unsigned int j = 0; j < items.size(); ++j) { result.writeInt16(items[j].itemId); result.writeInt16(items[j].amount); } } // clean up postalManager->clearPost(ptr); } comp->send(result); } break; case GCMSG_STORE_POST: { // Store the letter for the user LOG_DEBUG("GCMSG_STORE_POST"); MessageOut result(CGMSG_STORE_POST_RESPONSE); // get the sender and receiver int senderId = msg.readInt32(); std::string receiverName = msg.readString(); // for sending it back result.writeInt32(senderId); // get their characters Character *sender = storage->getCharacter(senderId, NULL); Character *receiver = storage->getCharacter(receiverName); if (!sender || !receiver) { // Invalid character LOG_ERROR("Error finding character id for post"); result.writeInt8(ERRMSG_INVALID_ARGUMENT); break; } // get the letter contents std::string contents = msg.readString(); std::vector< std::pair<int, int> > items; while (msg.getUnreadLength()) { items.push_back(std::pair<int, int>(msg.readInt16(), msg.readInt16())); } // save the letter LOG_DEBUG("Creating letter"); Letter *letter = new Letter(0, sender, receiver); letter->addText(contents); for (unsigned int i = 0; i < items.size(); ++i) { InventoryItem item; item.itemId = items[i].first; item.amount = items[i].second; letter->addAttachment(item); } postalManager->addLetter(letter); result.writeInt8(ERRMSG_OK); comp->send(result); } break; case GAMSG_TRANSACTION: { LOG_DEBUG("TRANSACTION"); int id = msg.readInt32(); int action = msg.readInt32(); std::string message = msg.readString(); Transaction trans; trans.mCharacterId = id; trans.mAction = action; trans.mMessage = message; storage->addTransaction(trans); } break; case GCMSG_PARTY_INVITE: chatHandler->handlePartyInvite(msg); break; case GAMSG_CREATE_ITEM_ON_MAP: { int mapId = msg.readInt32(); int itemId = msg.readInt32(); int amount = msg.readInt16(); int posX = msg.readInt16(); int posY = msg.readInt16(); LOG_DEBUG("Gameserver create item " << itemId << " on map " << mapId); storage->addFloorItem(mapId, itemId, amount, posX, posY); } break; case GAMSG_REMOVE_ITEM_ON_MAP: { int mapId = msg.readInt32(); int itemId = msg.readInt32(); int amount = msg.readInt16(); int posX = msg.readInt16(); int posY = msg.readInt16(); LOG_DEBUG("Gameserver removed item " << itemId << " from map " << mapId); storage->removeFloorItem(mapId, itemId, amount, posX, posY); } break; case GAMSG_ANNOUNCE: { const std::string message = msg.readString(); const int senderId = msg.readInt16(); const std::string senderName = msg.readString(); chatHandler->handleAnnounce(message, senderId, senderName); } break; default: LOG_WARN("ServerHandler::processMessage, Invalid message type: " << msg.getId()); MessageOut result(XXMSG_INVALID); comp->send(result); break; } }
void CharServerHandler::handleMessage(MessageIn &msg) { int slot; LocalPlayer *tempPlayer; switch (msg.getId()) { case APMSG_CHAR_CREATE_RESPONSE: handleCharCreateResponse(msg); break; case APMSG_CHAR_DELETE_RESPONSE: { int errMsg = msg.readInt8(); // Character deletion successful if (errMsg == ERRMSG_OK) { delete mCharInfo->getEntry(); mCharInfo->setEntry(0); mCharInfo->unlock(); new OkDialog("Info", "Player deleted"); } // Character deletion failed else { std::string message = ""; switch (errMsg) { case ERRMSG_NO_LOGIN: message = "Not logged in"; break; case ERRMSG_INVALID_ARGUMENT: message = "Selection out of range"; break; default: message = "Unknown error"; } mCharInfo->unlock(); new OkDialog("Error", message); } } break; case APMSG_CHAR_INFO: tempPlayer = readPlayerData(msg, slot); mCharInfo->unlock(); mCharInfo->select(slot); mCharInfo->setEntry(tempPlayer); // Close the character create dialog if (mCharCreateDialog) { mCharCreateDialog->scheduleDelete(); mCharCreateDialog = 0; } break; case APMSG_CHAR_SELECT_RESPONSE: handleCharSelectResponse(msg); break; } }
void PlayerHandler::handleMessage(MessageIn &msg) { switch (msg.getId()) { case SMSG_WALK_RESPONSE: /* * This client assumes that all walk messages succeed, * and that the server will send a correction notice * otherwise. */ break; case SMSG_PLAYER_WARP: { std::string mapPath = msg.readString(16); bool nearby; Uint16 x = msg.readInt16(); Uint16 y = msg.readInt16(); logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y); /* * We must clear the local player's target *before* the call * to changeMap, as it deletes all beings. */ player_node->stopAttack(); nearby = (engine->getCurrentMapName() == mapPath); // Switch the actual map, deleting the previous one if necessary mapPath = mapPath.substr(0, mapPath.rfind(".")); engine->changeMap(mapPath); float scrollOffsetX = 0.0f; float scrollOffsetY = 0.0f; /* Scroll if neccessary */ if (!nearby || (abs(x - player_node->getTileX()) > MAP_TELEPORT_SCROLL_DISTANCE) || (abs(y - player_node->getTileY()) > MAP_TELEPORT_SCROLL_DISTANCE)) { scrollOffsetX = (x - player_node->getTileX()) * 32; scrollOffsetY = (y - player_node->getTileY()) * 32; } player_node->setAction(Being::STAND); player_node->mFrame = 0; player_node->setTileCoords(x, y); logger->log("Adjust scrolling by %d:%d", (int) scrollOffsetX, (int) scrollOffsetY); viewport->scrollBy(scrollOffsetX, scrollOffsetY); } break; case SMSG_PLAYER_STAT_UPDATE_1: { int type = msg.readInt16(); int value = msg.readInt32(); switch (type) { case 0x0000: player_node->setWalkSpeed(value); break; case 0x0004: break; // manner case 0x0005: player_node->setHp(value); break; case 0x0006: player_node->setMaxHp(value); break; case 0x0007: player_node->setMP(value); break; case 0x0008: player_node->setMaxMP(value); break; case 0x0009: player_node->setCharacterPoints(value); break; case 0x000b: player_node->setLevel(value); break; case 0x000c: player_node->setSkillPoints(value); break; case 0x0018: if (value >= player_node->getMaxWeight() / 2 && player_node->getTotalWeight() < player_node->getMaxWeight() / 2) { weightNotice = new OkDialog(_("Message"), _("You are carrying more than " "half your weight. You are " "unable to regain health.")); weightNotice->addActionListener( &weightListener); } player_node->setTotalWeight(value); break; case 0x0019: player_node->setMaxWeight(value); break; case 0x0029: player_node->setAttributeEffective(ATK, value + ATTR_BONUS(ATK)); player_node->setAttributeBase(ATK, value); break; case 0x002a: value += player_node->getAttributeBase(ATK); player_node->setAttributeEffective(ATK, value); break; case 0x002b: player_node->setAttributeEffective(MATK, value + ATTR_BONUS(MATK)); player_node->setAttributeBase(MATK, value); statusWindow->update(StatusWindow::MP); break; case 0x002c: value += player_node->getAttributeBase(MATK); player_node->setAttributeEffective(MATK, value); statusWindow->update(StatusWindow::MP); break; case 0x002d: player_node->setAttributeEffective(DEF, value + ATTR_BONUS(DEF)); player_node->setAttributeBase(DEF, value); break; case 0x002e: value += player_node->getAttributeBase(DEF); player_node->setAttributeEffective(DEF, value); break; case 0x002f: player_node->setAttributeEffective(MDEF, value + ATTR_BONUS(MDEF)); player_node->setAttributeBase(MDEF, value); break; case 0x0030: value += player_node->getAttributeBase(MDEF); player_node->setAttributeEffective(MDEF, value); break; case 0x0031: player_node->setAttributeBase(HIT, value); player_node->setAttributeEffective(HIT, value); break; case 0x0032: player_node->setAttributeEffective(FLEE, value + ATTR_BONUS(FLEE)); player_node->setAttributeBase(FLEE, value); break; case 0x0033: value += player_node->getAttributeBase(FLEE); player_node->setAttributeEffective(FLEE, value); break; case 0x0034: player_node->setAttributeBase(CRIT, value); player_node->setAttributeEffective(CRIT, value); break; case 0x0035: player_node->mAttackSpeed = value; break; case 0x0037: player_node->setAttributeBase(JOB, value); player_node->setAttributeEffective(JOB, value); break; case 500: player_node->setGMLevel(value); break; } if (player_node->getHp() == 0 && !deathNotice) { deathNotice = new OkDialog(_("Message"), randomDeathMessage()); deathNotice->addActionListener(&deathListener); player_node->setAction(Being::DEAD); } } break; case SMSG_PLAYER_STAT_UPDATE_2: switch (msg.readInt16()) { case 0x0001: player_node->setExp(msg.readInt32()); break; case 0x0002: player_node->setExperience(JOB, msg.readInt32(), player_node->getExperience(JOB).second); break; case 0x0014: { int curGp = player_node->getMoney(); player_node->setMoney(msg.readInt32()); if (player_node->getMoney() > curGp) localChatTab->chatLog(strprintf(_("You picked up " "%s."), Units::formatCurrency(player_node->getMoney() - curGp).c_str()), BY_SERVER); } break; case 0x0016: player_node->setExpNeeded(msg.readInt32()); break; case 0x0017: player_node->setExperience(JOB, player_node->getExperience(JOB).first, msg.readInt32()); break; } break; case SMSG_PLAYER_STAT_UPDATE_3: // Update a base attribute { int type = msg.readInt32(); int base = msg.readInt32(); int bonus = msg.readInt32(); player_node->setAttributeBase(type, base); player_node->setAttributeEffective(type, base + bonus); } break; case SMSG_PLAYER_STAT_UPDATE_4: // Attribute increase ack { int type = msg.readInt16(); int fail = msg.readInt8(); int value = msg.readInt8(); if (fail != 1) break; int bonus = ATTR_BONUS(type); player_node->setAttributeBase(type, value); player_node->setAttributeEffective(type, value + bonus); } break; // Updates stats and status points case SMSG_PLAYER_STAT_UPDATE_5: player_node->setCharacterPoints(msg.readInt16()); { int val = msg.readInt8(); player_node->setAttributeEffective(STR, val + ATTR_BONUS(STR)); player_node->setAttributeBase(STR, val); statusWindow->setPointsNeeded(STR, msg.readInt8()); val = msg.readInt8(); player_node->setAttributeEffective(AGI, val + ATTR_BONUS(AGI)); player_node->setAttributeBase(AGI, val); statusWindow->setPointsNeeded(AGI, msg.readInt8()); val = msg.readInt8(); player_node->setAttributeEffective(VIT, val + ATTR_BONUS(VIT)); player_node->setAttributeBase(VIT, val); statusWindow->setPointsNeeded(VIT, msg.readInt8()); val = msg.readInt8(); player_node->setAttributeEffective(INTT, val + ATTR_BONUS(INTT)); player_node->setAttributeBase(INTT, val); statusWindow->setPointsNeeded(INTT, msg.readInt8()); val = msg.readInt8(); player_node->setAttributeEffective(DEX, val + ATTR_BONUS(DEX)); player_node->setAttributeBase(DEX, val); statusWindow->setPointsNeeded(DEX, msg.readInt8()); val = msg.readInt8(); player_node->setAttributeEffective(LUK, val + ATTR_BONUS(LUK)); player_node->setAttributeBase(LUK, val); statusWindow->setPointsNeeded(LUK, msg.readInt8()); val = msg.readInt16(); // ATK player_node->setAttributeBase(ATK, val); val += msg.readInt16(); // ATK bonus player_node->setAttributeEffective(ATK, val); val = msg.readInt16(); // MATK player_node->setAttributeBase(MATK, val); val += msg.readInt16(); // MATK bonus player_node->setAttributeEffective(MATK, val); statusWindow->update(StatusWindow::MP); val = msg.readInt16(); // DEF player_node->setAttributeBase(DEF, val); val += msg.readInt16(); // DEF bonus player_node->setAttributeEffective(DEF, val); val = msg.readInt16(); // MDEF player_node->setAttributeBase(MDEF, val); val += msg.readInt16(); // MDEF bonus player_node->setAttributeEffective(MDEF, val); val = msg.readInt16(); // HIT player_node->setAttributeBase(ATK, val); player_node->setAttributeEffective(ATK, val); val = msg.readInt16(); // FLEE player_node->setAttributeBase(FLEE, val); val += msg.readInt16(); // FLEE bonus player_node->setAttributeEffective(FLEE, val); val = msg.readInt16(); player_node->setAttributeBase(CRIT, val); player_node->setAttributeEffective(CRIT, val); } msg.readInt16(); // manner break; case SMSG_PLAYER_STAT_UPDATE_6: switch (msg.readInt16()) { case 0x0020: statusWindow->setPointsNeeded(STR, msg.readInt8()); break; case 0x0021: statusWindow->setPointsNeeded(AGI, msg.readInt8()); break; case 0x0022: statusWindow->setPointsNeeded(VIT, msg.readInt8()); break; case 0x0023: statusWindow->setPointsNeeded(INTT, msg.readInt8()); break; case 0x0024: statusWindow->setPointsNeeded(DEX, msg.readInt8()); break; case 0x0025: statusWindow->setPointsNeeded(LUK, msg.readInt8()); break; } break; case SMSG_PLAYER_ARROW_MESSAGE: { int type = msg.readInt16(); switch (type) { case 0: localChatTab->chatLog(_("Equip arrows first."), BY_SERVER); break; default: logger->log("0x013b: Unhandled message %i", type); break; } } break; } }
void AccountHandler::processMessage(NetComputer *comp, MessageIn &message) { AccountClient &client = *static_cast< AccountClient * >(comp); switch (message.getId()) { case PAMSG_LOGIN_RNDTRGR: LOG_DEBUG("Received msg ... PAMSG_LOGIN_RANDTRIGGER"); handleLoginRandTriggerMessage(client, message); break; case PAMSG_LOGIN: LOG_DEBUG("Received msg ... PAMSG_LOGIN"); handleLoginMessage(client, message); break; case PAMSG_LOGOUT: LOG_DEBUG("Received msg ... PAMSG_LOGOUT"); handleLogoutMessage(client); break; case PAMSG_RECONNECT: LOG_DEBUG("Received msg ... PAMSG_RECONNECT"); handleReconnectMessage(client, message); break; case PAMSG_REGISTER: LOG_DEBUG("Received msg ... PAMSG_REGISTER"); handleRegisterMessage(client, message); break; case PAMSG_UNREGISTER: LOG_DEBUG("Received msg ... PAMSG_UNREGISTER"); handleUnregisterMessage(client, message); break; case PAMSG_REQUEST_REGISTER_INFO : LOG_DEBUG("Received msg ... REQUEST_REGISTER_INFO"); handleRequestRegisterInfoMessage(client, message); break; case PAMSG_EMAIL_CHANGE: LOG_DEBUG("Received msg ... PAMSG_EMAIL_CHANGE"); handleEmailChangeMessage(client, message); break; case PAMSG_PASSWORD_CHANGE: LOG_DEBUG("Received msg ... PAMSG_PASSWORD_CHANGE"); handlePasswordChangeMessage(client, message); break; case PAMSG_CHAR_CREATE: LOG_DEBUG("Received msg ... PAMSG_CHAR_CREATE"); handleCharacterCreateMessage(client, message); break; case PAMSG_CHAR_SELECT: LOG_DEBUG("Received msg ... PAMSG_CHAR_SELECT"); handleCharacterSelectMessage(client, message); break; case PAMSG_CHAR_DELETE: LOG_DEBUG("Received msg ... PAMSG_CHAR_DELETE"); handleCharacterDeleteMessage(client, message); break; default: LOG_WARN("AccountHandler::processMessage, Invalid message type " << message.getId()); MessageOut result(XXMSG_INVALID); client.send(result); break; } }
void BuySellHandler::handleMessage(MessageIn &msg) { int n_items; switch (msg.getId()) { case SMSG_NPC_BUY_SELL_CHOICE: buyDialog->setVisible(false); buyDialog->reset(); sellDialog->setVisible(false); sellDialog->reset(); current_npc = msg.readInt32(); buySellDialog->setVisible(true); break; case SMSG_NPC_BUY: msg.readInt16(); // length n_items = (msg.getLength() - 4) / 11; buyDialog->reset(); buyDialog->setMoney(player_node->getMoney()); buyDialog->setVisible(true); for (int k = 0; k < n_items; k++) { int value = msg.readInt32(); msg.readInt32(); // DCvalue msg.readInt8(); // type int itemId = msg.readInt16(); buyDialog->addItem(itemId, 0, value); } break; case SMSG_NPC_SELL: msg.readInt16(); // length n_items = (msg.getLength() - 4) / 10; if (n_items > 0) { sellDialog->setMoney(player_node->getMoney()); sellDialog->reset(); sellDialog->setVisible(true); for (int k = 0; k < n_items; k++) { int index = msg.readInt16() - INVENTORY_OFFSET; int value = msg.readInt32(); msg.readInt32(); // OCvalue Item *item = player_node->getInventory()->getItem(index); if (item && !(item->isEquipped())) sellDialog->addItem(item, value); } } else { localChatTab->chatLog(_("Nothing to sell."), BY_SERVER); current_npc = 0; } break; case SMSG_NPC_BUY_RESPONSE: if (msg.readInt8() == 0) { localChatTab->chatLog(_("Thanks for buying."), BY_SERVER); } else { // Reset player money since buy dialog already assumed purchase // would go fine buyDialog->setMoney(player_node->getMoney()); localChatTab->chatLog(_("Unable to buy."), BY_SERVER); } break; case SMSG_NPC_SELL_RESPONSE: if (msg.readInt8() == 0) localChatTab->chatLog(_("Thanks for selling."), BY_SERVER); else localChatTab->chatLog(_("Unable to sell."), BY_SERVER); break; } }
void SkillHandler::handleMessage(MessageIn &msg) { int skillCount; switch (msg.getId()) { case SMSG_PLAYER_SKILLS: msg.readInt16(); // length skillCount = (msg.getLength() - 4) / 37; skillDialog->cleanList(); for (int k = 0; k < skillCount; k++) { int skillId = msg.readInt16(); msg.readInt16(); // target type msg.readInt16(); // unknown int level = msg.readInt16(); int sp = msg.readInt16(); msg.readInt16(); // range std::string skillName = msg.readString(24); int up = msg.readInt8(); if (level != 0 || up != 0) { if (skillDialog->hasSkill(skillId)) { skillDialog->setSkill(skillId, level, sp); } else { skillDialog->addSkill(skillId, level, sp); } } } skillDialog->update(); break; case SMSG_SKILL_FAILED: // Action failed (ex. sit because you have not reached the // right level) short skill = msg.readInt16(); short bskill = msg.readInt16(); msg.readInt16(); // unknown char success = msg.readInt8(); char reason = msg.readInt8(); if (success != SKILL_FAILED && bskill == BSKILL_EMOTE) { logger->log("Action: %d/%d", bskill, success); } std::string msg; if (success == SKILL_FAILED && skill == SKILL_BASIC) { switch (bskill) { case BSKILL_TRADE: msg = _("Trade failed!"); break; case BSKILL_EMOTE: msg = _("Emote failed!"); break; case BSKILL_SIT: msg = _("Sit failed!"); break; case BSKILL_CREATECHAT: msg = _("Chat creating failed!"); break; case BSKILL_JOINPARTY: msg = _("Could not join party!"); break; case BSKILL_SHOUT: msg = _("Cannot shout!"); break; } msg += " "; switch (reason) { case RFAIL_SKILLDEP: msg += _("You have not yet reached a high enough lvl!"); break; case RFAIL_INSUFHP: msg += _("Insufficient HP!"); break; case RFAIL_INSUFSP: msg += _("Insufficient SP!"); break; case RFAIL_NOMEMO: msg += _("You have no memos!"); break; case RFAIL_SKILLDELAY: msg += _("You cannot do that right now!"); break; case RFAIL_ZENY: msg += _("Seems you need more money... ;-)"); break; case RFAIL_WEAPON: msg += _("You cannot use this skill with that kind of weapon!"); break; case RFAIL_REDGEM: msg += _("You need another red gem!"); break; case RFAIL_BLUEGEM: msg += _("You need another blue gem!"); break; case RFAIL_OVERWEIGHT: msg += _("You're carrying to much to do this!"); break; default: msg += _("Huh? What's that?"); break; } } else { switch (skill) { case SKILL_WARP : msg = _("Warp failed..."); break; case SKILL_STEAL : msg = _("Could not steal anything..."); break; case SKILL_ENVENOM : msg = _("Poison had no effect..."); break; } } localChatTab->chatLog(msg); break; } }
void EquipmentHandler::handleMessage(MessageIn &msg) { int itemCount; int index, equipPoint, itemId; int type; Inventory *inventory = player_node->getInventory(); switch (msg.getId()) { case SMSG_PLAYER_EQUIPMENT: msg.readInt16(); // length itemCount = (msg.getLength() - 4) / 20; for (int loop = 0; loop < itemCount; loop++) { index = msg.readInt16() - INVENTORY_OFFSET; itemId = msg.readInt16(); msg.readInt8(); // type msg.readInt8(); // identify flag msg.readInt16(); // equip type equipPoint = msg.readInt16(); msg.readInt8(); // attribute msg.readInt8(); // refine msg.skip(8); // card inventory->setItem(index, itemId, 1, true); setEquipment(equipPoint, index, true); } break; case SMSG_PLAYER_EQUIP: index = msg.readInt16() - INVENTORY_OFFSET; equipPoint = msg.readInt16(); type = msg.readInt8(); if (!type) { localChatTab->chatLog(_("Unable to equip."), BY_SERVER); break; } setEquipment(equipPoint, index, true); break; case SMSG_PLAYER_UNEQUIP: index = msg.readInt16() - INVENTORY_OFFSET; equipPoint = msg.readInt16(); type = msg.readInt8(); if (!type) { localChatTab->chatLog(_("Unable to unequip."), BY_SERVER); break; } setEquipment(equipPoint, index, false); break; case SMSG_PLAYER_ATTACK_RANGE: player_node->setAttackRange(msg.readInt16()); break; case SMSG_PLAYER_ARROW_EQUIP: index = msg.readInt16(); if (index <= 1) break; index -= INVENTORY_OFFSET; logger->log("Arrows equipped: %i", index); setEquipment(0x8000, index, true); break; } }
void InventoryHandler::handleMessage(MessageIn &msg) { int number; int index, amount, itemId, equipType, arrow; int identified, cards[4], itemType; Inventory *inventory = player_node->getInventory(); Inventory *storage = player_node->getStorage(); switch (msg.getId()) { case SMSG_PLAYER_INVENTORY: case SMSG_PLAYER_STORAGE_ITEMS: if (msg.getId() == SMSG_PLAYER_INVENTORY) { // Clear inventory - this will be a complete refresh clearEquipment(); inventory->clear(); } else { /* * This packet will always be followed by a * SMSG_PLAYER_STORAGE_EQUIP packet. The two packets * together comprise a complete refresh of storage, so * clear storage here */ storage->clear(); } msg.readInt16(); // length number = (msg.getLength() - 4) / 18; for (int loop = 0; loop < number; loop++) { index = msg.readInt16(); itemId = msg.readInt16(); itemType = msg.readInt8(); identified = msg.readInt8(); amount = msg.readInt16(); arrow = msg.readInt16(); for (int i = 0; i < 4; i++) cards[i] = msg.readInt16(); index -= (msg.getId() == SMSG_PLAYER_INVENTORY) ? INVENTORY_OFFSET : STORAGE_OFFSET; if (debugInventory) { logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " "Qty: %d, Cards: %d, %d, %d, %d", index, itemId, itemType, identified, amount, cards[0], cards[1], cards[2], cards[3]); } if (msg.getId() == SMSG_PLAYER_INVENTORY) { inventory->setItem(index, itemId, amount, false); // Trick because arrows are not considered equipment if (arrow & 0x8000) { if (Item *item = inventory->getItem(index)) item->setEquipment(true); } } else { storage->setItem(index, itemId, amount, false); } } break; case SMSG_PLAYER_STORAGE_EQUIP: msg.readInt16(); // length number = (msg.getLength() - 4) / 20; for (int loop = 0; loop < number; loop++) { index = msg.readInt16() - STORAGE_OFFSET; itemId = msg.readInt16(); itemType = msg.readInt8(); identified = msg.readInt8(); amount = 1; msg.readInt16(); // Equip Point? msg.readInt16(); // Another Equip Point? msg.readInt8(); // Attribute (broken) msg.readInt8(); // Refine level for (int i = 0; i < 4; i++) cards[i] = msg.readInt16(); if (debugInventory) { logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " "Qty: %d, Cards: %d, %d, %d, %d", index, itemId, itemType, identified, amount, cards[0], cards[1], cards[2], cards[3]); } storage->setItem(index, itemId, amount, false); } break; case SMSG_PLAYER_INVENTORY_ADD: index = msg.readInt16() - INVENTORY_OFFSET; amount = msg.readInt16(); itemId = msg.readInt16(); identified = msg.readInt8(); msg.readInt8(); // attribute msg.readInt8(); // refine for (int i = 0; i < 4; i++) cards[i] = msg.readInt16(); equipType = msg.readInt16(); itemType = msg.readInt8(); { const ItemInfo &itemInfo = ItemDB::get(itemId); if (msg.readInt8() > 0) { player_node->pickedUp(itemInfo, 0); } else { player_node->pickedUp(itemInfo, amount); Item *item = inventory->getItem(index); if (item && item->getId() == itemId) amount += inventory->getItem(index)->getQuantity(); inventory->setItem(index, itemId, amount, equipType != 0); } } break; case SMSG_PLAYER_INVENTORY_REMOVE: index = msg.readInt16() - INVENTORY_OFFSET; amount = msg.readInt16(); if (Item *item = inventory->getItem(index)) { item->increaseQuantity(-amount); if (item->getQuantity() == 0) inventory->removeItemAt(index); } break; case SMSG_PLAYER_INVENTORY_USE: index = msg.readInt16() - INVENTORY_OFFSET; msg.readInt16(); // item id msg.readInt32(); // id amount = msg.readInt16(); msg.readInt8(); // type if (Item *item = inventory->getItem(index)) item->setQuantity(amount); break; case SMSG_ITEM_USE_RESPONSE: index = msg.readInt16() - INVENTORY_OFFSET; amount = msg.readInt16(); if (msg.readInt8() == 0) { localChatTab->chatLog(_("Failed to use item."), BY_SERVER); } else { if (Item *item = inventory->getItem(index)) item->setQuantity(amount); } break; case SMSG_PLAYER_STORAGE_STATUS: /* * This is the closest we get to an "Open Storage" packet from the * server. It always comes after the two SMSG_PLAYER_STORAGE_... * packets that update storage contents. */ player_node->setInStorage(true); msg.readInt16(); // Storage capacity msg.readInt16(); // Used count break; case SMSG_PLAYER_STORAGE_ADD: /* * Move an item into storage */ index = msg.readInt16() - STORAGE_OFFSET; amount = msg.readInt32(); itemId = msg.readInt16(); identified = msg.readInt8(); msg.readInt8(); // attribute msg.readInt8(); // refine for (int i = 0; i < 4; i++) cards[i] = msg.readInt16(); if (Item *item = storage->getItem(index)) { item->setId(itemId); item->increaseQuantity(amount); } else { storage->setItem(index, itemId, amount, false); } break; case SMSG_PLAYER_STORAGE_REMOVE: /* * Move an item out of storage */ index = msg.readInt16() - STORAGE_OFFSET; amount = msg.readInt16(); if (Item *item = storage->getItem(index)) { item->increaseQuantity(-amount); if (item->getQuantity() == 0) storage->removeItemAt(index); } break; case SMSG_PLAYER_STORAGE_CLOSE: /* * Storage access has been closed */ player_node->setInStorage(false); break; } }
void ChatHandler::handleMessage(MessageIn &msg) { Being *being; std::string chatMsg; std::string nick; int chatMsgLength; switch (msg.getId()) { case SMSG_WHISPER_RESPONSE: switch (msg.readInt8()) { case 0x00: // comment out since we'll local echo in chat.cpp instead, then only report failures //localChatTab->chatLog("Whisper sent", BY_SERVER); break; case 0x01: localChatTab->chatLog(_("Whisper could not be sent, user " "is offline."), BY_SERVER); break; case 0x02: localChatTab->chatLog(_("Whisper could not be sent, " "ignored by user."), BY_SERVER); break; } break; // Received whisper case SMSG_WHISPER: chatMsgLength = msg.readInt16() - 28; nick = msg.readString(24); if (chatMsgLength <= 0) break; chatMsg = msg.readString(chatMsgLength); if (nick != "Server") { if (player_relations.hasPermission(nick, PlayerRelation::WHISPER)) chatWindow->whisper(nick, chatMsg); } else { localChatTab->chatLog(chatMsg, BY_SERVER); } break; // Received speech from being case SMSG_BEING_CHAT: { chatMsgLength = msg.readInt16() - 8; being = beingManager->findBeing(msg.readInt32()); if (!being || chatMsgLength <= 0) break; chatMsg = msg.readString(chatMsgLength); std::string::size_type pos = chatMsg.find(" : ", 0); std::string sender_name = ((pos == std::string::npos) ? "" : chatMsg.substr(0, pos)); // We use getIgnorePlayer instead of ignoringPlayer here because ignorePlayer' side // effects are triggered right below for Being::IGNORE_SPEECH_FLOAT. if (player_relations.checkPermissionSilently(sender_name, PlayerRelation::SPEECH_LOG)) localChatTab->chatLog(chatMsg, BY_OTHER); chatMsg.erase(0, pos + 3); trim(chatMsg); if (player_relations.hasPermission(sender_name, PlayerRelation::SPEECH_FLOAT)) being->setSpeech(chatMsg, SPEECH_TIME); break; } case SMSG_PLAYER_CHAT: case SMSG_GM_CHAT: { chatMsgLength = msg.readInt16() - 4; if (chatMsgLength <= 0) break; chatMsg = msg.readString(chatMsgLength); std::string::size_type pos = chatMsg.find(" : ", 0); if (msg.getId() == SMSG_PLAYER_CHAT) { if (localChatTab) localChatTab->chatLog(chatMsg, BY_PLAYER); if (pos != std::string::npos) chatMsg.erase(0, pos + 3); trim(chatMsg); player_node->setSpeech(chatMsg, SPEECH_TIME); } else { localChatTab->chatLog(chatMsg, BY_GM); } break; } case SMSG_MVP: // Display MVP player msg.readInt32(); // id localChatTab->chatLog(_("MVP player."), BY_SERVER); break; } }
void LoginHandler::handleMessage(MessageIn &msg) { switch (msg.getId()) { case APMSG_LOGIN_RESPONSE: handleLoginResponse(msg); break; case APMSG_REGISTER_RESPONSE: handleRegisterResponse(msg); break; case APMSG_RECONNECT_RESPONSE: { int errMsg = msg.readInt8(); // Successful login if (errMsg == ERRMSG_OK) { state = STATE_CHAR_SELECT; } // Login failed else { switch (errMsg) { case ERRMSG_INVALID_ARGUMENT: errorMessage = _("Wrong magic_token"); break; case ERRMSG_FAILURE: errorMessage = _("Already logged in"); break; case LOGIN_SERVER_FULL: errorMessage = _("Server is full"); break; default: errorMessage = _("Unknown error"); break; } state = STATE_ERROR; } } break; case APMSG_PASSWORD_CHANGE_RESPONSE: { int errMsg = msg.readInt8(); // Successful pass change if (errMsg == ERRMSG_OK) { state = STATE_CHANGEPASSWORD; } // pass change failed else { switch (errMsg) { case ERRMSG_INVALID_ARGUMENT: errorMessage = _("New password incorrect"); break; case ERRMSG_FAILURE: errorMessage = _("Old password incorrect"); break; case ERRMSG_NO_LOGIN: errorMessage = _("Account not connected. Please login first."); break; default: errorMessage = _("Unknown error"); break; } state = STATE_ACCOUNTCHANGE_ERROR; } } break; case APMSG_EMAIL_CHANGE_RESPONSE: { int errMsg = msg.readInt8(); // Successful pass change if (errMsg == ERRMSG_OK) { state = STATE_CHANGEEMAIL; } // pass change failed else { switch (errMsg) { case ERRMSG_INVALID_ARGUMENT: errorMessage = _("New email address incorrect"); break; case ERRMSG_FAILURE: errorMessage = _("Old email address incorrect"); break; case ERRMSG_NO_LOGIN: errorMessage = _("Account not connected. Please login first."); break; case ERRMSG_EMAIL_ALREADY_EXISTS: errorMessage = _("The new Email Address already exists."); break; default: errorMessage = _("Unknown error"); break; } state = STATE_ACCOUNTCHANGE_ERROR; } } break; } }
void PlayerHandler::handleMessage(MessageIn &msg) { switch (msg.getId()) { case SMSG_WALK_RESPONSE: /* * This client assumes that all walk messages succeed, * and that the server will send a correction notice * otherwise. */ break; case SMSG_PLAYER_WARP: { std::string mapPath = msg.readString(16); bool nearby; Uint16 x = msg.readInt16(); Uint16 y = msg.readInt16(); logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y); /* * We must clear the local player's target *before* the call * to changeMap, as it deletes all beings. */ player_node->stopAttack(); nearby = (engine->getCurrentMapName() == mapPath); // Switch the actual map, deleting the previous one if necessary mapPath = mapPath.substr(0, mapPath.rfind(".")); engine->changeMap(mapPath); float scrollOffsetX = 0.0f; float scrollOffsetY = 0.0f; /* Scroll if neccessary */ if (!nearby || (abs(x - player_node->mX) > MAP_TELEPORT_SCROLL_DISTANCE) || (abs(y - player_node->mY) > MAP_TELEPORT_SCROLL_DISTANCE)) { scrollOffsetX = (x - player_node->mX) * 32; scrollOffsetY = (y - player_node->mY) * 32; } player_node->setAction(Being::STAND); player_node->mFrame = 0; player_node->mX = x; player_node->mY = y; logger->log("Adjust scrolling by %d:%d", (int) scrollOffsetX, (int) scrollOffsetY); viewport->scrollBy(scrollOffsetX, scrollOffsetY); } break; case SMSG_PLAYER_STAT_UPDATE_1: { int type = msg.readInt16(); int value = msg.readInt32(); switch (type) { //case 0x0000: // player_node->setWalkSpeed(msg.readInt32()); // break; case 0x0005: player_node->setHp(value); break; case 0x0006: player_node->setMaxHp(value); break; case 0x0007: player_node->mMp = value; break; case 0x0008: player_node->mMaxMp = value; break; case 0x0009: player_node->mStatsPointsToAttribute = value; break; case 0x000b: player_node->setLevel(value); break; case 0x000c: player_node->mSkillPoint = value; skillDialog->update(); break; case 0x0018: if (value >= player_node->getMaxWeight() / 2 && player_node->getTotalWeight() < player_node->getMaxWeight() / 2) { weightNotice = new OkDialog(_("Message"), _("You are carrying more than " "half your weight. You are " "unable to regain health.")); weightNotice->addActionListener(&weightListener); } player_node->setTotalWeight(value); break; case 0x0019: player_node->setMaxWeight(value); break; case 0x0029: player_node->ATK = value; break; case 0x002b: player_node->MATK = value; break; case 0x002d: player_node->DEF = value; break; case 0x002e: player_node->DEF_BONUS = value; break; case 0x002f: player_node->MDEF = value; break; case 0x0031: player_node->HIT = value; break; case 0x0032: player_node->FLEE = value; break; case 0x0035: player_node->mAttackSpeed = value; break; case 0x0037: player_node->mJobLevel = value; break; case 500: player_node->setGMLevel(value); break; } if (player_node->getHp() == 0 && !deathNotice) { if (true) { game.wasKilled = true; Net::getPlayerHandler()->respawn(); } else { deathNotice = new OkDialog(_("Message"), randomDeathMessage()); deathNotice->addActionListener(&deathListener); player_node->setAction(Being::DEAD); } } } break; case SMSG_PLAYER_STAT_UPDATE_2: switch (msg.readInt16()) { case 0x0001: player_node->setXp(msg.readInt32()); break; case 0x0002: player_node->mJobXp = msg.readInt32(); break; case 0x0014: { int curGp = player_node->getMoney(); player_node->setMoney(msg.readInt32()); if (player_node->getMoney() > curGp) localChatTab->chatLog( _("You picked up ") + Units::formatCurrency( player_node->getMoney() - curGp), BY_SERVER); } break; case 0x0016: player_node->mXpForNextLevel = msg.readInt32(); break; case 0x0017: player_node->mJobXpForNextLevel = msg.readInt32(); break; } break; case SMSG_PLAYER_STAT_UPDATE_3: { int type = msg.readInt32(); int base = msg.readInt32(); int bonus = msg.readInt32(); int total = base + bonus; switch (type) { case 0x000d: player_node->mAttr[LocalPlayer::STR] = total; break; case 0x000e: player_node->mAttr[LocalPlayer::AGI] = total; break; case 0x000f: player_node->mAttr[LocalPlayer::VIT] = total; break; case 0x0010: player_node->mAttr[LocalPlayer::INT] = total; break; case 0x0011: player_node->mAttr[LocalPlayer::DEX] = total; break; case 0x0012: player_node->mAttr[LocalPlayer::LUK] = total; break; } } break; case SMSG_PLAYER_STAT_UPDATE_4: { int type = msg.readInt16(); int fail = msg.readInt8(); int value = msg.readInt8(); if (fail != 1) break; switch (type) { case 0x000d: player_node->mAttr[LocalPlayer::STR] = value; break; case 0x000e: player_node->mAttr[LocalPlayer::AGI] = value; break; case 0x000f: player_node->mAttr[LocalPlayer::VIT] = value; break; case 0x0010: player_node->mAttr[LocalPlayer::INT] = value; break; case 0x0011: player_node->mAttr[LocalPlayer::DEX] = value; break; case 0x0012: player_node->mAttr[LocalPlayer::LUK] = value; break; } } break; // Updates stats and status points case SMSG_PLAYER_STAT_UPDATE_5: player_node->mStatsPointsToAttribute = msg.readInt16(); player_node->mAttr[LocalPlayer::STR] = msg.readInt8(); player_node->mAttrUp[LocalPlayer::STR] = msg.readInt8(); player_node->mAttr[LocalPlayer::AGI] = msg.readInt8(); player_node->mAttrUp[LocalPlayer::AGI] = msg.readInt8(); player_node->mAttr[LocalPlayer::VIT] = msg.readInt8(); player_node->mAttrUp[LocalPlayer::VIT] = msg.readInt8(); player_node->mAttr[LocalPlayer::INT] = msg.readInt8(); player_node->mAttrUp[LocalPlayer::INT] = msg.readInt8(); player_node->mAttr[LocalPlayer::DEX] = msg.readInt8(); player_node->mAttrUp[LocalPlayer::DEX] = msg.readInt8(); player_node->mAttr[LocalPlayer::LUK] = msg.readInt8(); player_node->mAttrUp[LocalPlayer::LUK] = msg.readInt8(); player_node->ATK = msg.readInt16(); // ATK player_node->ATK_BONUS = msg.readInt16(); // ATK bonus player_node->MATK = msg.readInt16(); // MATK max player_node->MATK_BONUS = msg.readInt16(); // MATK min player_node->DEF = msg.readInt16(); // DEF player_node->DEF_BONUS = msg.readInt16(); // DEF bonus player_node->MDEF = msg.readInt16(); // MDEF player_node->MDEF_BONUS = msg.readInt16(); // MDEF bonus player_node->HIT = msg.readInt16(); // HIT player_node->FLEE = msg.readInt16(); // FLEE player_node->FLEE_BONUS = msg.readInt16(); // FLEE bonus msg.readInt16(); // critical msg.readInt16(); // unknown break; case SMSG_PLAYER_STAT_UPDATE_6: switch (msg.readInt16()) { case 0x0020: player_node->mAttrUp[LocalPlayer::STR] = msg.readInt8(); break; case 0x0021: player_node->mAttrUp[LocalPlayer::AGI] = msg.readInt8(); break; case 0x0022: player_node->mAttrUp[LocalPlayer::VIT] = msg.readInt8(); break; case 0x0023: player_node->mAttrUp[LocalPlayer::INT] = msg.readInt8(); break; case 0x0024: player_node->mAttrUp[LocalPlayer::DEX] = msg.readInt8(); break; case 0x0025: player_node->mAttrUp[LocalPlayer::LUK] = msg.readInt8(); break; } break; case SMSG_PLAYER_ARROW_MESSAGE: { int type = msg.readInt16(); switch (type) { case 0: localChatTab->chatLog(_("Equip arrows first."), BY_SERVER); break; default: logger->log("0x013b: Unhandled message %i", type); break; } } break; } }
void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) { ChatClient &computer = *static_cast< ChatClient * >(comp); MessageOut result; if (computer.characterName.empty()) { if (message.getId() != PCMSG_CONNECT) return; std::string magic_token = message.readString(MAGIC_TOKEN_LENGTH); mTokenCollector.addPendingClient(magic_token, &computer); sendGuildRejoin(computer); return; } switch (message.getId()) { case PCMSG_CHAT: handleChatMessage(computer, message); break; case PCMSG_ANNOUNCE: handleAnnounceMessage(computer, message); break; case PCMSG_PRIVMSG: handlePrivMsgMessage(computer, message); break; case PCMSG_WHO: handleWhoMessage(computer); break; case PCMSG_ENTER_CHANNEL: handleEnterChannelMessage(computer, message); break; case PCMSG_USER_MODE: handleModeChangeMessage(computer, message); break; case PCMSG_KICK_USER: handleKickUserMessage(computer, message); case PCMSG_QUIT_CHANNEL: handleQuitChannelMessage(computer, message); break; case PCMSG_LIST_CHANNELS: handleListChannelsMessage(computer, message); break; case PCMSG_LIST_CHANNELUSERS: handleListChannelUsersMessage(computer, message); break; case PCMSG_TOPIC_CHANGE: handleTopicChange(computer, message); break; case PCMSG_DISCONNECT: handleDisconnectMessage(computer, message); break; case PCMSG_GUILD_CREATE: handleGuildCreation(computer, message); break; case PCMSG_GUILD_INVITE: handleGuildInvitation(computer, message); break; case PCMSG_GUILD_ACCEPT: handleGuildAcceptInvite(computer, message); break; case PCMSG_GUILD_GET_MEMBERS: handleGuildRetrieveMembers(computer, message); break; case PCMSG_GUILD_PROMOTE_MEMBER: handleGuildMemberLevelChange(computer, message); break; case PCMSG_GUILD_KICK_MEMBER: handleGuildMemberKick(computer, message); case PCMSG_GUILD_QUIT: handleGuildQuit(computer, message); break; case PCMSG_PARTY_INVITE: handlePartyInvite(computer, message); break; case PCMSG_PARTY_ACCEPT_INVITE: handlePartyAcceptInvite(computer, message); break; case PCMSG_PARTY_QUIT: handlePartyQuit(computer); break; case PCMSG_PARTY_REJECT_INVITE: handlePartyRejection(computer, message); break; default: LOG_WARN("ChatHandler::processMessage, Invalid message type" << message.getId()); result.writeShort(XXMSG_INVALID); break; } if (result.getLength() > 0) computer.send(result); }
void PlayerHandler::handleMessage(MessageIn &msg) { switch (msg.getId()) { case GPMSG_PLAYER_MAP_CHANGE: handleMapChangeMessage(msg); break; case GPMSG_PLAYER_SERVER_CHANGE: { // TODO: Fix the servers to test this netToken = msg.readString(32); std::string address = msg.readString(); int port = msg.readInt16(); logger->log("Changing server to %s:%d", address.c_str(), port); gameServer.hostname = address; gameServer.port = port; gameServerConnection->disconnect(); Client::setState(STATE_CHANGE_MAP); local_player->setMap(0); } break; case GPMSG_PLAYER_ATTRIBUTE_CHANGE: { while (msg.getUnreadLength()) { int attrId = msg.readInt16(); double base = msg.readInt32() / 256.0; double value = msg.readInt32() / 256.0; // Set the core player attribute the stat // depending on attribute link. int playerInfoId = Attributes::getPlayerInfoIdFromAttrId(attrId); if (playerInfoId > -1) { PlayerInfo::setAttribute(playerInfoId, value); } else { PlayerInfo::setStatBase(attrId, base); PlayerInfo::setStatMod(attrId, value - base); } } } break; case GPMSG_PLAYER_EXP_CHANGE: { logger->log("EXP Update"); while (msg.getUnreadLength()) { int skill = msg.readInt16(); int current = msg.readInt32(); int next = msg.readInt32(); int level = msg.readInt16(); PlayerInfo::setStatExperience(skill, current, next); PlayerInfo::setStatBase(skill, level); } } break; case GPMSG_LEVELUP: { PlayerInfo::setAttribute(LEVEL, msg.readInt16()); PlayerInfo::setAttribute(CHAR_POINTS, msg.readInt16()); PlayerInfo::setAttribute(CORR_POINTS, msg.readInt16()); Particle* effect = particleEngine->addEffect( paths.getStringValue("particles") + paths.getStringValue("levelUpEffectFile") ,0, 0); local_player->controlParticle(effect); } break; case GPMSG_LEVEL_PROGRESS: { PlayerInfo::setAttribute(EXP, msg.readInt8()); } break; case GPMSG_RAISE_ATTRIBUTE_RESPONSE: { int errCode = msg.readInt8(); int attrNum = msg.readInt16(); switch (errCode) { case ATTRIBMOD_OK: { // feel(acknowledgment); } break; case ATTRIBMOD_INVALID_ATTRIBUTE: { logger->log("Warning: Server denied increase of attribute %d (unknown attribute) ", attrNum); } break; case ATTRIBMOD_NO_POINTS_LEFT: { // when the server says "you got no points" it // has to be correct. The server is always right! // undo attribute change and set points to 0 logger->log("Warning: Server denied increase of attribute %d (no points left) ", attrNum); int attrValue = PlayerInfo::getStatBase(attrNum) - 1; PlayerInfo::setAttribute(CHAR_POINTS, 0); PlayerInfo::setStatBase(attrNum, attrValue); } break; case ATTRIBMOD_DENIED: { // undo attribute change logger->log("Warning: Server denied increase of attribute %d (reason unknown) ", attrNum); int points = PlayerInfo::getAttribute(CHAR_POINTS) - 1; PlayerInfo::setAttribute(CHAR_POINTS, points); int attrValue = PlayerInfo::getStatBase(attrNum) - 1; PlayerInfo::setStatBase(attrNum, attrValue); } break; } } break; case GPMSG_LOWER_ATTRIBUTE_RESPONSE: { int errCode = msg.readInt8(); int attrNum = msg.readInt16(); switch (errCode) { case ATTRIBMOD_OK: { // feel(acknowledgment); } break; case ATTRIBMOD_INVALID_ATTRIBUTE: { logger->log("Warning: Server denied reduction of attribute %d (unknown attribute) ", attrNum); } break; case ATTRIBMOD_NO_POINTS_LEFT: { // when the server says "you got no points" it // has to be correct. The server is always right! // undo attribute change and set points to 0 logger->log("Warning: Server denied reduction of attribute %d (no points left) ", attrNum); int attrValue = PlayerInfo::getStatBase(attrNum) + 1; // TODO are these right? PlayerInfo::setAttribute(CHAR_POINTS, 0); PlayerInfo::setAttribute(CORR_POINTS, 0); PlayerInfo::setStatBase(attrNum, attrValue); } break; case ATTRIBMOD_DENIED: { // undo attribute change logger->log("Warning: Server denied reduction of attribute %d (reason unknown) ", attrNum); int charaPoints = PlayerInfo::getAttribute(CHAR_POINTS) - 1; PlayerInfo::setAttribute(CHAR_POINTS, charaPoints); int correctPoints = PlayerInfo::getAttribute(CORR_POINTS) + 1; PlayerInfo::setAttribute(CORR_POINTS, correctPoints); int attrValue = PlayerInfo::getStatBase(attrNum) + 1; PlayerInfo::setStatBase(attrNum, attrValue); } break; } } break; case GPMSG_SPECIAL_STATUS : { while (msg.getUnreadLength()) { // { B specialID, L current, L max, L recharge } int id = msg.readInt8(); int current = msg.readInt32(); int max = msg.readInt32(); int recharge = msg.readInt32(); PlayerInfo::setSpecialStatus(id, current, max, recharge); } } break; /* case SMSG_PLAYER_ARROW_MESSAGE: { Sint16 type = msg.readInt16(); switch (type) { case 0: localChatTab->chatLog(_("Equip arrows first."), BY_SERVER); break; default: logger->log("0x013b: Unhandled message %i", type); break; } } break; */ } }
void GuildHandler::handleMessage(MessageIn &msg) { switch (msg.getId()) { case CPMSG_GUILD_CREATE_RESPONSE: { logger->log("Received CPMSG_GUILD_CREATE_RESPONSE"); if(msg.readInt8() == ERRMSG_OK) { // TODO - Acknowledge guild was created localChatTab->chatLog(_("Guild created.")); joinedGuild(msg); } else { localChatTab->chatLog(_("Error creating guild.")); } } break; case CPMSG_GUILD_INVITE_RESPONSE: { logger->log("Received CPMSG_GUILD_INVITE_RESPONSE"); if(msg.readInt8() == ERRMSG_OK) { // TODO - Acknowledge invite was sent localChatTab->chatLog(_("Invite sent.")); } } break; case CPMSG_GUILD_ACCEPT_RESPONSE: { logger->log("Received CPMSG_GUILD_ACCEPT_RESPONSE"); if(msg.readInt8() == ERRMSG_OK) { // TODO - Acknowledge accepted into guild joinedGuild(msg); } } break; case CPMSG_GUILD_GET_MEMBERS_RESPONSE: { logger->log("Received CPMSG_GUILD_GET_MEMBERS_RESPONSE"); if(msg.readInt8() == ERRMSG_OK) { std::string guildMember; bool online; std::string guildName; Guild *guild; short guildId = msg.readInt16(); guild = player_node->getGuild(guildId); if (!guild) return; guildName = guild->getName(); while(msg.getUnreadLength()) { guildMember = msg.readString(); online = msg.readInt8(); if(guildMember != "") { guild->addMember(guildMember); guildWindow->setOnline(guildName, guildMember, online); } } guildWindow->updateTab(); } } break; case CPMSG_GUILD_UPDATE_LIST: { logger->log("Received CPMSG_GUILD_UPDATE_LIST"); short guildId = msg.readInt16(); std::string guildMember = msg.readString(); char eventId = msg.readInt8(); Guild *guild = player_node->getGuild(guildId); if (guild) { switch(eventId) { case GUILD_EVENT_NEW_PLAYER: guild->addMember(guildMember); guildWindow->setOnline(guild->getName(), guildMember, true); break; case GUILD_EVENT_LEAVING_PLAYER: guild->removeMember(guildMember); break; case GUILD_EVENT_ONLINE_PLAYER: guildWindow->setOnline(guild->getName(), guildMember, true); break; case GUILD_EVENT_OFFLINE_PLAYER: guildWindow->setOnline(guild->getName(), guildMember, false); break; default: logger->log("Invalid guild event"); } } guildWindow->updateTab(); } break; case CPMSG_GUILD_INVITED: { logger->log("Received CPMSG_GUILD_INVITED"); std::string inviterName = msg.readString(); std::string guildName = msg.readString(); // Open a dialog asking if the player accepts joining the guild. guildWindow->openAcceptDialog(inviterName, guildName); } break; case CPMSG_GUILD_PROMOTE_MEMBER_RESPONSE: { logger->log("Received CPMSG_GUILD_PROMOTE_MEMBER_RESPONSE"); if (msg.readInt8() == ERRMSG_OK) { // promotion succeeded localChatTab->chatLog(_("Member was promoted successfully.")); } else { // promotion failed localChatTab->chatLog(_("Failed to promote member.")); } } case CPMSG_GUILD_REJOIN: { logger->log("Received CPMSG_GUILD_REJOIN"); joinedGuild(msg); } break; case CPMSG_GUILD_QUIT_RESPONSE: { logger->log("Received CPMSG_GUILD_QUIT_RESPONSE"); if (msg.readInt8() == ERRMSG_OK) { // Must remove tab first, as it wont find the guild // name after its removed from the player int guildId = msg.readInt16(); Guild *guild = player_node->getGuild(guildId); if (guild) { Channel *channel = channelManager->findByName(guild->getName()); channelManager->removeChannel(channel); guildWindow->removeTab(guildId); player_node->removeGuild(guildId); } } } break; } }
void GameHandler::processMessage(NetComputer *computer, MessageIn &message) { GameClient &client = *static_cast<GameClient *>(computer); if (client.status == CLIENT_LOGIN) { if (message.getId() != PGMSG_CONNECT) return; std::string magic_token = message.readString(MAGIC_TOKEN_LENGTH); client.status = CLIENT_QUEUED; // Before the addPendingClient mTokenCollector.addPendingClient(magic_token, &client); return; } else if (client.status != CLIENT_CONNECTED) { return; } switch (message.getId()) { case PGMSG_SAY: handleSay(client, message); break; case PGMSG_NPC_TALK: case PGMSG_NPC_TALK_NEXT: case PGMSG_NPC_SELECT: case PGMSG_NPC_NUMBER: case PGMSG_NPC_STRING: handleNpc(client, message); break; case PGMSG_PICKUP: handlePickup(client, message); break; case PGMSG_USE_ITEM: handleUseItem(client, message); break; case PGMSG_DROP: handleDrop(client, message); break; case PGMSG_WALK: handleWalk(client, message); break; case PGMSG_EQUIP: handleEquip(client, message); break; case PGMSG_UNEQUIP: handleUnequip(client, message); break; case PGMSG_MOVE_ITEM: handleMoveItem(client, message); break; case PGMSG_ATTACK: handleAttack(client, message); break; case PGMSG_USE_SPECIAL_ON_BEING: handleUseSpecialOnBeing(client, message); break; case PGMSG_USE_SPECIAL_ON_POINT: handleUseSpecialOnPoint(client, message); break; case PGMSG_ACTION_CHANGE: handleActionChange(client, message); break; case PGMSG_DIRECTION_CHANGE: handleDirectionChange(client, message); break; case PGMSG_DISCONNECT: handleDisconnect(client, message); break; case PGMSG_TRADE_REQUEST: handleTradeRequest(client, message); break; case PGMSG_TRADE_CANCEL: case PGMSG_TRADE_AGREED: case PGMSG_TRADE_CONFIRM: case PGMSG_TRADE_ADD_ITEM: case PGMSG_TRADE_SET_MONEY: handleTrade(client, message); break; case PGMSG_NPC_BUYSELL: handleNpcBuySell(client, message); break; case PGMSG_RAISE_ATTRIBUTE: handleRaiseAttribute(client, message); break; case PGMSG_LOWER_ATTRIBUTE: handleLowerAttribute(client, message); break; case PGMSG_RESPAWN: // plausibility check is done by character class client.character->respawn(); break; case PGMSG_NPC_POST_SEND: handleNpcPostSend(client, message); break; case PGMSG_PARTY_INVITE: handlePartyInvite(client, message); break; case PGMSG_BEING_EMOTE: handleTriggerEmoticon(client, message); break; default: LOG_WARN("Invalid message type"); client.send(MessageOut(XXMSG_INVALID)); break; } }
void ChatHandler::handleMessage(MessageIn &msg) { Being *being; std::string chatMsg; std::string nick; int chatMsgLength; switch (msg.getId()) { case SMSG_WHISPER_RESPONSE: if (mSentWhispers.empty()) nick = "user"; else { nick = mSentWhispers.front(); mSentWhispers.pop(); } switch (msg.readInt8()) { case 0x00: // Success (don't need to report) break; case 0x01: { Event event(Event::WhisperError); event.setString("nick", nick); event.setString("error", strprintf(_("Whisper could " "not be sent, %s is offline."), nick.c_str())); event.trigger(Event::ChatChannel); } break; case 0x02: { Event event(Event::WhisperError); event.setString("nick", nick); event.setString("error", strprintf(_("Whisper could " "not be sent, ignored by %s."), nick.c_str())); event.Event::trigger(Event::ChatChannel); } break; } break; // Received whisper case SMSG_WHISPER: chatMsgLength = msg.readInt16() - 28; nick = msg.readString(24); if (chatMsgLength <= 0) break; chatMsg = msg.readString(chatMsgLength); // This is a sure sign of some special command, none of which are // supported at the moment. if (chatMsg.compare(0, 3, "\302\202!") == 0) return; if (nick != "Server") { // Ignore the shop commands since this client doesn't support // them at the moment. if (chatMsg.find("!selllist ") == 0 || chatMsg.find("!buylist ") == 0 || chatMsg.find("!buyitem ") == 0 || chatMsg.find("!sellitem ") == 0) return; if (player_relations.hasPermission(nick, PlayerRelation::WHISPER)) { Event event(Event::Whisper); event.setString("nick", nick); event.setString("message", chatMsg); event.trigger(Event::ChatChannel); } } else { SERVER_NOTICE(chatMsg) } break; // Received speech from being case SMSG_BEING_CHAT: { chatMsgLength = msg.readInt16() - 8; int beingId = msg.readInt32(); being = actorSpriteManager->findBeing(beingId); if (!being || chatMsgLength <= 0) break; chatMsg = msg.readString(chatMsgLength); std::string::size_type pos = chatMsg.find(" : ", 0); std::string sender_name = ((pos == std::string::npos) ? "" : chatMsg.substr(0, pos)); if (sender_name != being->getName() && being->getType() == Being::PLAYER) { if (!being->getName().empty()) sender_name = being->getName(); } else { chatMsg.erase(0, pos + 3); } int perms; if (being->getType() == Being::PLAYER) { perms = player_relations.checkPermissionSilently(sender_name, PlayerRelation::SPEECH_LOG | PlayerRelation::SPEECH_FLOAT); } else { perms = player_relations.getDefault() & (PlayerRelation::SPEECH_LOG | PlayerRelation::SPEECH_FLOAT); } trim(chatMsg); std::string reducedMessage = chatMsg; chatMsg = removeColors(sender_name) + " : " + reducedMessage; Event event(Event::Being); event.setString("message", chatMsg); event.setString("text", reducedMessage); event.setString("nick", sender_name); event.setInt("beingId", beingId); event.setInt("permissions", perms); event.trigger(Event::ChatChannel); break; } case SMSG_PLAYER_CHAT: case SMSG_GM_CHAT: { chatMsgLength = msg.readInt16() - 4; if (chatMsgLength <= 0) break; chatMsg = msg.readString(chatMsgLength); if (msg.getId() == SMSG_PLAYER_CHAT) { std::string::size_type pos = chatMsg.find(" : ", 0); std::string mes = chatMsg; if (pos != std::string::npos) chatMsg.erase(0, pos + 3); trim(chatMsg); Event event(Event::Player); event.setString("message", mes); event.setString("text", chatMsg); event.setString("nick", local_player->getName()); event.setInt("beingId", local_player->getId()); event.setInt("permissions", player_relations.getDefault() & (PlayerRelation::SPEECH_LOG | PlayerRelation::SPEECH_FLOAT)); event.trigger(Event::ChatChannel); } else { Event event(Event::Announcement); event.setString("message", chatMsg); event.trigger(Event::ChatChannel); } break; } case SMSG_MVP: // Display MVP player msg.readInt32(); // id SERVER_NOTICE(_("MVP player.")) break; } }
void GameHandler::processMessage(NetComputer *comp, MessageIn &message) { GameClient &computer = *static_cast< GameClient * >(comp); MessageOut result; if (computer.status == CLIENT_LOGIN) { if (message.getId() != PGMSG_CONNECT) return; std::string magic_token = message.readString(MAGIC_TOKEN_LENGTH); computer.status = CLIENT_QUEUED; // Before the addPendingClient mTokenCollector.addPendingClient(magic_token, &computer); return; } else if (computer.status != CLIENT_CONNECTED) { return; } switch (message.getId()) { case PGMSG_SAY: { std::string say = message.readString(); if (say.empty()) break; if (say[0] == '@') { CommandHandler::handleCommand(computer.character, say); break; } GameState::sayAround(computer.character, say); std::string msg = computer.character->getName() + " said " + say; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_MSG_PUBLIC, msg); } break; case PGMSG_NPC_TALK: case PGMSG_NPC_TALK_NEXT: case PGMSG_NPC_SELECT: case PGMSG_NPC_NUMBER: case PGMSG_NPC_STRING: { int id = message.readShort(); Actor *o = findActorNear(computer.character, id); if (!o || o->getType() != OBJECT_NPC) { sendError(comp, id, "Not close enough to NPC\n"); break; } NPC *q = static_cast< NPC * >(o); if (message.getId() == PGMSG_NPC_SELECT) { q->select(computer.character, message.readByte()); } else if (message.getId() == PGMSG_NPC_NUMBER) { q->integerReceived(computer.character, message.readLong()); } else if (message.getId() == PGMSG_NPC_STRING) { q->stringReceived(computer.character, message.readString()); } else { q->prompt(computer.character, message.getId() == PGMSG_NPC_TALK); } } break; case PGMSG_PICKUP: { int x = message.readShort(); int y = message.readShort(); Point ppos = computer.character->getPosition(); // TODO: use a less arbitrary value. if (std::abs(x - ppos.x) + std::abs(y - ppos.y) < 48) { MapComposite *map = computer.character->getMap(); Point ipos(x, y); for (FixedActorIterator i(map->getAroundPointIterator(ipos, 0)); i; ++i) { Actor *o = *i; Point opos = o->getPosition(); if (o->getType() == OBJECT_ITEM && opos.x == x && opos.y == y) { Item *item = static_cast< Item * >(o); ItemClass *ic = item->getItemClass(); Inventory(computer.character) .insert(ic->getDatabaseID(), item->getAmount()); GameState::remove(item); // log transaction std::stringstream str; str << "User picked up item " << ic->getDatabaseID() << " at " << opos.x << "x" << opos.y; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ITEM_PICKUP, str.str()); break; } } } } break; case PGMSG_USE_ITEM: { int slot = message.readByte(); Inventory inv(computer.character); if (ItemClass *ic = ItemManager::getItem(inv.getItem(slot))) { if (ic->use(computer.character)) { inv.removeFromSlot(slot, 1); // log transaction std::stringstream str; str << "User used item " << ic->getDatabaseID() << " from slot " << slot; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ITEM_USED, str.str()); } } } break; case PGMSG_DROP: { int slot = message.readByte(); int amount = message.readByte(); Inventory inv(computer.character); if (ItemClass *ic = ItemManager::getItem(inv.getItem(slot))) { int nb = inv.removeFromSlot(slot, amount); Item *item = new Item(ic, amount - nb); item->setMap(computer.character->getMap()); item->setPosition(computer.character->getPosition()); if (!GameState::insert(item)) { // The map is full. Put back into inventory. inv.insert(ic->getDatabaseID(), amount - nb); delete item; break; } // log transaction Point pt = computer.character->getPosition(); std::stringstream str; str << "User dropped item " << ic->getDatabaseID() << " at " << pt.x << "x" << pt.y; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ITEM_DROP, str.str()); } } break; case PGMSG_WALK: { handleWalk(&computer, message); } break; case PGMSG_EQUIP: { int slot = message.readByte(); Inventory(computer.character).equip(slot); } break; case PGMSG_UNEQUIP: { int slot = message.readByte(); if (slot >= 0 && slot < EQUIP_PROJECTILE_SLOT) { Inventory(computer.character).unequip(slot); } } break; case PGMSG_MOVE_ITEM: { int slot1 = message.readByte(); int slot2 = message.readByte(); int amount = message.readByte(); Inventory(computer.character).move(slot1, slot2, amount); // log transaction std::stringstream str; str << "User moved item " << " from slot " << slot1 << " to slot " << slot2; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ITEM_MOVE, str.str()); } break; case PGMSG_ATTACK: { int id = message.readShort(); LOG_DEBUG("Character " << computer.character->getPublicID() << " attacked being " << id); Actor *o = findActorNear(computer.character, id); if (o && o->getType() != OBJECT_NPC) { Being *being = static_cast<Being*>(o); computer.character->setTarget(being); computer.character->setAction(Being::ATTACK); } } break; case PGMSG_USE_SPECIAL: { int specialID = message.readByte(); LOG_DEBUG("Character " << computer.character->getPublicID() << " tries to use his special attack "<<specialID); computer.character->useSpecial(specialID); } case PGMSG_ACTION_CHANGE: { Being::Action action = (Being::Action)message.readByte(); Being::Action current = (Being::Action)computer.character->getAction(); bool logActionChange = true; switch (action) { case Being::STAND: { if (current == Being::SIT) { computer.character->setAction(Being::STAND); logActionChange = false; } } break; case Being::SIT: { if (current == Being::STAND) { computer.character->setAction(Being::SIT); logActionChange = false; } } break; default: break; } // Log the action change only when this is relevant. if (logActionChange) { // log transaction std::stringstream str; str << "User changed action from " << current << " to " << action; accountHandler->sendTransaction( computer.character->getDatabaseID(), TRANS_ACTION_CHANGE, str.str()); } } break; case PGMSG_DIRECTION_CHANGE: { computer.character->setDirection(message.readByte()); } break; case PGMSG_DISCONNECT: { bool reconnectAccount = (bool) message.readByte(); result.writeShort(GPMSG_DISCONNECT_RESPONSE); result.writeByte(ERRMSG_OK); // It is, when control reaches here if (reconnectAccount) { std::string magic_token(utils::getMagicToken()); result.writeString(magic_token, MAGIC_TOKEN_LENGTH); // No accountserver data, the client should remember that accountHandler->playerReconnectAccount( computer.character->getDatabaseID(), magic_token); } // TODO: implement a delayed remove GameState::remove(computer.character); accountHandler->sendCharacterData(computer.character); // Done with the character computer.character->disconnected(); delete computer.character; computer.character = NULL; computer.status = CLIENT_LOGIN; } break; case PGMSG_TRADE_REQUEST: { int id = message.readShort(); if (Trade *t = computer.character->getTrading()) { if (t->request(computer.character, id)) break; } Character *q = findCharacterNear(computer.character, id); if (!q || q->isBusy()) { result.writeShort(GPMSG_TRADE_CANCEL); break; } new Trade(computer.character, q); // log transaction std::string str; str = "User requested trade with " + q->getName(); accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_TRADE_REQUEST, str); } break; case PGMSG_TRADE_CANCEL: case PGMSG_TRADE_AGREED: case PGMSG_TRADE_CONFIRM: case PGMSG_TRADE_ADD_ITEM: case PGMSG_TRADE_SET_MONEY: { std::stringstream str; Trade *t = computer.character->getTrading(); if (!t) break; switch (message.getId()) { case PGMSG_TRADE_CANCEL: t->cancel(); break; case PGMSG_TRADE_CONFIRM: t->confirm(computer.character); break; case PGMSG_TRADE_AGREED: t->agree(computer.character); // log transaction accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_TRADE_END, "User finished trading"); break; case PGMSG_TRADE_SET_MONEY: { int money = message.readLong(); t->setMoney(computer.character, money); // log transaction str << "User added " << money << " money to trade."; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_TRADE_MONEY, str.str()); } break; case PGMSG_TRADE_ADD_ITEM: { int slot = message.readByte(); t->addItem(computer.character, slot, message.readByte()); // log transaction str << "User add item from slot " << slot; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_TRADE_ITEM, str.str()); } break; } } break; case PGMSG_NPC_BUYSELL: { BuySell *t = computer.character->getBuySell(); if (!t) break; int id = message.readShort(); int amount = message.readShort(); t->perform(id, amount); } break; case PGMSG_RAISE_ATTRIBUTE: { int attribute = message.readByte(); AttribmodResponseCode retCode; retCode = computer.character->useCharacterPoint(attribute); result.writeShort(GPMSG_RAISE_ATTRIBUTE_RESPONSE); result.writeByte(retCode); result.writeByte(attribute); if (retCode == ATTRIBMOD_OK ) { accountHandler->updateCharacterPoints( computer.character->getDatabaseID(), computer.character->getCharacterPoints(), computer.character->getCorrectionPoints(), attribute, computer.character->getAttribute(attribute)); // log transaction std::stringstream str; str << "User increased attribute " << attribute; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ATTR_INCREASE, str.str()); } } break; case PGMSG_LOWER_ATTRIBUTE: { int attribute = message.readByte(); AttribmodResponseCode retCode; retCode = computer.character->useCorrectionPoint(attribute); result.writeShort(GPMSG_LOWER_ATTRIBUTE_RESPONSE); result.writeByte(retCode); result.writeByte(attribute); if (retCode == ATTRIBMOD_OK ) { accountHandler->updateCharacterPoints( computer.character->getDatabaseID(), computer.character->getCharacterPoints(), computer.character->getCorrectionPoints(), attribute, computer.character->getAttribute(attribute)); // log transaction std::stringstream str; str << "User decreased attribute " << attribute; accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_ATTR_DECREASE, str.str()); } } break; case PGMSG_RESPAWN: { computer.character->respawn(); // plausibility check is done by character class } break; case PGMSG_NPC_POST_SEND: { handleSendPost(&computer, message); } break; default: LOG_WARN("Invalid message type"); result.writeShort(XXMSG_INVALID); break; } if (result.getLength() > 0) computer.send(result); }
void AccountConnection::processMessage(MessageIn &msg) { LOG_DEBUG("Received message " << msg << " from account server"); switch (msg.getId()) { case AGMSG_REGISTER_RESPONSE: { if (msg.readInt16() != DATA_VERSION_OK) { LOG_ERROR("Item database is outdated! Please update to " "prevent inconsistencies"); stop(); // Disconnect gracefully from account server. // Stop gameserver to prevent inconsistencies. exit(EXIT_DB_EXCEPTION); } else { LOG_DEBUG("Local item database is " "in sync with account server."); } if (msg.readInt16() != PASSWORD_OK) { LOG_ERROR("This game server sent a invalid password"); stop(); exit(EXIT_BAD_CONFIG_PARAMETER); } // read world state variables while (msg.getUnreadLength()) { std::string key = msg.readString(); std::string value = msg.readString(); if (!key.empty() && !value.empty()) { GameState::setVariableFromDbserver(key, value); } } } break; case AGMSG_PLAYER_ENTER: { std::string token = msg.readString(MAGIC_TOKEN_LENGTH); Character *ptr = new Character(msg); gameHandler->addPendingCharacter(token, ptr); } break; case AGMSG_ACTIVE_MAP: { int mapId = msg.readInt16(); if (MapManager::activateMap(mapId)) { // Set map variables MapComposite *m = MapManager::getMap(mapId); int mapVarsNumber = msg.readInt16(); for(int i = 0; i < mapVarsNumber; ++i) { std::string key = msg.readString(); std::string value = msg.readString(); if (!key.empty() && !value.empty()) m->setVariableFromDbserver(key, value); } // Recreate potential persistent floor items LOG_DEBUG("Recreate persistant items on map " << mapId); int floorItemsNumber = msg.readInt16(); for (int i = 0; i < floorItemsNumber; ++i) { int itemId = msg.readInt32(); int amount = msg.readInt16(); int posX = msg.readInt16(); int posY = msg.readInt16(); if (ItemClass *ic = itemManager->getItem(itemId)) { Item *item = new Item(ic, amount); item->setMap(m); Point dst(posX, posY); item->setPosition(dst); if (!GameState::insertOrDelete(item)) { // The map is full. LOG_WARN("Couldn't add floor item(s) " << itemId << " into map " << mapId); return; } } } } } break; case AGMSG_SET_VAR_WORLD: { std::string key = msg.readString(); std::string value = msg.readString(); GameState::setVariableFromDbserver(key, value); LOG_DEBUG("Global variable \"" << key << "\" has changed to \"" << value << "\""); } break; case AGMSG_REDIRECT_RESPONSE: { int id = msg.readInt32(); std::string token = msg.readString(MAGIC_TOKEN_LENGTH); std::string address = msg.readString(); int port = msg.readInt16(); gameHandler->completeServerChange(id, token, address, port); } break; case AGMSG_GET_VAR_CHR_RESPONSE: { int id = msg.readInt32(); std::string name = msg.readString(); std::string value = msg.readString(); recoveredQuestVar(id, name, value); } break; case CGMSG_CHANGED_PARTY: { // Character DB id int charid = msg.readInt32(); // Party id, 0 for none int partyid = msg.readInt32(); gameHandler->updateCharacter(charid, partyid); } break; case CGMSG_POST_RESPONSE: { // get the character Character *character = postMan->getCharacter(msg.readInt32()); // check character is still valid if (!character) { break; } std::string sender = msg.readString(); std::string letter = msg.readString(); postMan->gotPost(character, sender, letter); } break; case CGMSG_STORE_POST_RESPONSE: { // get character Character *character = postMan->getCharacter(msg.readInt32()); // check character is valid if (!character) { break; } // TODO: Get NPC to tell character if the sending of post // was successful or not } break; default: LOG_WARN("Invalid message type"); break; } }