void NpcHandler::handleMessage(Net::MessageIn &msg) { if (msg.getId() == SMSG_NPC_CHOICE || msg.getId() == SMSG_NPC_MESSAGE) { msg.readInt16(); // length } int npcId = msg.readInt32(); Event *event = 0; switch (msg.getId()) { case SMSG_NPC_CHOICE: event = new Event(Event::Menu); event->setInt("id", npcId); parseMenu(event, msg.readString(msg.getLength() - 8)); event->trigger(Event::NpcChannel); break; case SMSG_NPC_MESSAGE: event = new Event(Event::Message); event->setInt("id", npcId); event->setString("text", msg.readString(msg.getLength() - 8)); event->trigger(Event::NpcChannel); break; case SMSG_NPC_CLOSE: // Show the close button event = new Event(Event::Close); event->setInt("id", npcId); event->trigger(Event::NpcChannel); break; case SMSG_NPC_NEXT: // Show the next button event = new Event(Event::Next); event->setInt("id", npcId); event->trigger(Event::NpcChannel); break; case SMSG_NPC_INT_INPUT: // Request for an integer event = new Event(Event::IntegerInput); event->setInt("id", npcId); event->trigger(Event::NpcChannel); break; case SMSG_NPC_STR_INPUT: // Request for a string event = new Event(Event::StringInput); event->setInt("id", npcId); event->trigger(Event::NpcChannel); break; } delete event; if (local_player->getCurrentAction() != Being::SIT) local_player->setAction(Being::STAND); }
void CharServerHandler::processCharLogin(Net::MessageIn &msg) { msg.skip(2); // Length word const int slots = msg.readInt16(); if (slots > 0 && slots < 30) loginData.characterSlots = static_cast<uint16_t>(slots); msg.skip(18); // 0 Unused delete_all(mCharacters); mCharacters.clear(); // Derive number of characters from message length const int count = (msg.getLength() - 24) / 106; for (int i = 0; i < count; ++i) { Net::Character *const character = new Net::Character; readPlayerData(msg, character, false); mCharacters.push_back(character); if (character->dummy) { logger->log("CharServer: Player: %s (%d)", character->dummy->getName().c_str(), character->slot); } } client->setState(STATE_CHAR_SELECT); }
void BuySellHandler::processNpcSell(Net::MessageIn &msg) { msg.readInt16("len"); const int n_items = (msg.getLength() - 4) / 10; if (n_items > 0) { SellDialog *const dialog = new NpcSellDialog(mNpcId); dialog->postInit(); dialog->setMoney(PlayerInfo::getAttribute(Attributes::MONEY)); for (int k = 0; k < n_items; k++) { const int index = msg.readInt16("index") - INVENTORY_OFFSET; const int value = msg.readInt32("value"); msg.readInt32("value?"); const Item *const item = PlayerInfo::getInventory() ->getItem(index); if (item && item->isEquipped() == Equipped_false) dialog->addItem(item, value); } } else { NotifyManager::notify(NotifyTypes::SELL_LIST_EMPTY); } }
void CharServerHandler::processCharLogin(Net::MessageIn &msg) { msg.skip(2); // Length word int slots = msg.readInt16(); if (slots > 0 && slots < 30) loginData.characterSlots = static_cast<short unsigned int>(slots); bool version = msg.readInt8() == 1 && serverVersion > 0; msg.skip(17); // 0 Unused delete_all(mCharacters); mCharacters.clear(); // Derive number of characters from message length int count = (msg.getLength() - 24); if (version) count /= 120; else count /= 106; for (int i = 0; i < count; ++i) { Net::Character *character = new Net::Character; readPlayerData(msg, character, version); mCharacters.push_back(character); if (character && character->dummy) { logger->log("CharServer: Player: %s (%d)", character->dummy->getName().c_str(), character->slot); } } Client::setState(STATE_CHAR_SELECT); }
void CharServerHandler::processCharLogin(Net::MessageIn &msg) { msg.skip(2, "packet len"); const int slots = msg.readInt8("MAX_CHARS"); msg.readInt8("sd->char_slots"); msg.readInt8("MAX_CHARS"); loginData.characterSlots = static_cast<uint16_t>(slots); msg.skip(20, "unused 0"); delete_all(mCharacters); mCharacters.clear(); // Derive number of characters from message length const int count = (msg.getLength() - 27) / (106 + 4 + 2 + 16 + 4 + 4 + 4 + 4); for (int i = 0; i < count; ++i) { Net::Character *const character = new Net::Character; readPlayerData(msg, character); mCharacters.push_back(character); if (character->dummy) { logger->log("CharServer: Player: %s (%d)", character->dummy->getName().c_str(), character->slot); } } client->setState(STATE_CHAR_SELECT); }
void SkillHandler::processPlayerSkills(Net::MessageIn &msg) const { msg.readInt16(); // length const int skillCount = (msg.getLength() - 4) / 37; int updateSkill = 0; for (int k = 0; k < skillCount; k++) { const int skillId = msg.readInt16(); msg.readInt16(); // target type msg.skip(2); // skill pool flags const int level = msg.readInt16(); msg.readInt16(); // sp const int range = msg.readInt16(); msg.skip(24); // 0 unused const int up = msg.readInt8(); const int oldLevel = PlayerInfo::getSkillLevel(skillId); if (oldLevel && oldLevel != level) updateSkill = skillId; PlayerInfo::setSkillLevel(skillId, level); if (skillDialog) { if (!skillDialog->updateSkill(skillId, range, up)) skillDialog->addSkill(skillId, level, range, up); } } if (updateSkill && skillDialog) skillDialog->playUpdateEffect(updateSkill); }
void BuySellHandler::processNpcSell(Net::MessageIn &msg, int offset) { msg.readInt16(); // length int n_items = (msg.getLength() - 4) / 10; if (n_items > 0) { SellDialog *dialog = new SellDialog(mNpcId); dialog->setMoney(PlayerInfo::getAttribute(MONEY)); for (int k = 0; k < n_items; k++) { int index = msg.readInt16() - offset; int value = msg.readInt32(); msg.readInt32(); // OCvalue Item *item = PlayerInfo::getInventory()->getItem(index); if (item && !(item->isEquipped())) dialog->addItem(item, value); } } else { SERVER_NOTICE(_("Nothing to sell.")) } }
void SkillRecv::processPlayerSkills(Net::MessageIn &msg) { msg.readInt16("len"); const int sz = (serverVersion > 0) ? 41 : 37; const int skillCount = (msg.getLength() - 4) / sz; int updateSkill = 0; if (skillDialog != nullptr) skillDialog->hideSkills(SkillOwner::Player); for (int k = 0; k < skillCount; k++) { const int skillId = msg.readInt16("skill id"); const SkillType::SkillType inf = static_cast<SkillType::SkillType>( msg.readInt32("inf")); if (serverVersion > 0) msg.readInt32("inf2"); const int level = msg.readInt16("skill level"); const int sp = msg.readInt16("sp"); const int range = msg.readInt16("range"); const std::string name = msg.readString(24, "skill name"); const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable); const int oldLevel = PlayerInfo::getSkillLevel(skillId); if ((oldLevel != 0) && oldLevel != level) updateSkill = skillId; PlayerInfo::setSkillLevel(skillId, level); if (skillDialog != nullptr) { if (!skillDialog->updateSkill(skillId, range, up, inf, sp)) { skillDialog->addSkill(SkillOwner::Player, skillId, name, level, range, up, inf, sp); } } } if (skillDialog != nullptr) { skillDialog->update(); skillDialog->updateModelsHidden(); if (updateSkill != 0) skillDialog->playUpdateEffect(updateSkill); } }
void BuySellRecv::processNpcBuy(Net::MessageIn &msg) { msg.readInt16("len"); const unsigned int n_items = (msg.getLength() - 4U) / 11; CREATEWIDGETV(Ea::BuySellRecv::mBuyDialog, BuyDialog, Ea::BuySellRecv::mNpcId); Ea::BuySellRecv::mBuyDialog->setMoney( PlayerInfo::getAttribute(Attributes::MONEY)); for (unsigned int k = 0; k < n_items; k++) { const int value = msg.readInt32("price"); msg.readInt32("dc value?"); const int type = msg.readUInt8("type"); const int itemId = msg.readInt16("item id"); const ItemColor color = ItemColor_one; Ea::BuySellRecv::mBuyDialog->addItem(itemId, type, color, 0, value); } Ea::BuySellRecv::mBuyDialog->sort(); }
void LoginHandler::processLoginData(Net::MessageIn &msg) { // Skip the length word msg.skip(2); // size clearWorlds(); const int worldCount = (msg.getLength() - 47) / 32; mToken.session_ID1 = msg.readInt32(); mToken.account_ID = msg.readInt32(); mToken.session_ID2 = msg.readInt32(); msg.skip(4); // old ip loginData.lastLogin = msg.readString(24); msg.skip(2); // 0 unused bytes // msg.skip(30); // unknown // reserve bits for future usage mToken.sex = Being::intToGender(static_cast<uint8_t>( msg.readUInt8() & 3U)); for (int i = 0; i < worldCount; i++) { WorldInfo *const world = new WorldInfo; world->address = msg.readInt32(); world->port = msg.readInt16(); world->name = msg.readString(20); world->online_users = msg.readInt16(); config.setValue("updatehost", mUpdateHost); world->updateHost = mUpdateHost; msg.skip(2); // maintenance msg.skip(2); // new logger->log("Network: Server: %s (%s:%d)", world->name.c_str(), ipToString(world->address), world->port); mWorlds.push_back(world); } client->setState(STATE_WORLD_SELECT); }
void BuySellHandler::processNpcBuy(Net::MessageIn &msg) { msg.readInt16(); // length int sz = 11; if (serverVersion > 0) sz += 1; const int n_items = (msg.getLength() - 4) / sz; mBuyDialog = new BuyDialog(mNpcId); mBuyDialog->setMoney(PlayerInfo::getAttribute(PlayerInfo::MONEY)); for (int k = 0; k < n_items; k++) { const int value = msg.readInt32(); msg.readInt32(); // DCvalue msg.readInt8(); // type const int itemId = msg.readInt16(); unsigned char color = 1; if (serverVersion > 0) color = msg.readInt8(); mBuyDialog->addItem(itemId, color, 0, value); } }
void SkillRecv::processPlayerSkills(Net::MessageIn &msg) { msg.readInt16("len"); const int skillCount = (msg.getLength() - 4) / 37; int updateSkill = 0; for (int k = 0; k < skillCount; k++) { const int skillId = msg.readInt16("skill id"); const SkillType::SkillType inf = static_cast<SkillType::SkillType>( msg.readInt16("inf")); msg.readInt16("skill pool flags"); const int level = msg.readInt16("skill level"); const int sp = msg.readInt16("sp"); const int range = msg.readInt16("range"); msg.skip(24, "unused"); const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable); const int oldLevel = PlayerInfo::getSkillLevel(skillId); if (oldLevel && oldLevel != level) updateSkill = skillId; PlayerInfo::setSkillLevel(skillId, level); if (skillDialog) { if (!skillDialog->updateSkill(skillId, range, up, inf, sp)) { skillDialog->addSkill(SkillOwner::Player, skillId, "", level, range, up, inf, sp); } } } if (skillDialog) { skillDialog->update(); if (updateSkill) skillDialog->playUpdateEffect(updateSkill); } }
void SpecialHandler::handleMessage(Net::MessageIn &msg) { int skillCount; int skillId; switch (msg.getId()) { case SMSG_PLAYER_SKILLS: msg.readInt16(); // length skillCount = (msg.getLength() - 4) / 37; for (int k = 0; k < skillCount; k++) { skillId = msg.readInt16(); msg.readInt16(); // target type msg.skip(2); // unused int level = msg.readInt16(); msg.readInt16(); // sp msg.readInt16(); // range msg.skip(24); // unused int up = msg.readInt8(); PlayerInfo::setStatBase(skillId, level); if (skillDialog) skillDialog->setModifiable(skillId, up); } break; case SMSG_PLAYER_SKILL_UP: { skillId = msg.readInt16(); int level = msg.readInt16(); msg.readInt16(); // sp msg.readInt16(); // range int up = msg.readInt8(); PlayerInfo::setStatBase(skillId, level); skillDialog->setModifiable(skillId, up); } break; case SMSG_SKILL_FAILED: // Action failed (ex. sit because you have not reached the // right level) skillId = 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 && skillId == 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 (skillId) { 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; } } SERVER_NOTICE(msg) break; } }
void LoginHandler::handleMessage(Net::MessageIn &msg) { int code, worldCount; switch (msg.getId()) { case SMSG_CHAR_PASSWORD_RESPONSE: { // 0: acc not found, 1: success, 2: password mismatch, 3: pass too short int errMsg = msg.readInt8(); // Successful pass change if (errMsg == 1) { Client::setState(STATE_CHANGEPASSWORD_SUCCESS); } // pass change failed else { switch (errMsg) { case 0: errorMessage = _("Account was not found. Please re-login."); break; case 2: errorMessage = _("Old password incorrect."); break; case 3: errorMessage = _("New password too short."); break; default: errorMessage = _("Unknown error."); break; } Client::setState(STATE_ACCOUNTCHANGE_ERROR); } } break; case SMSG_UPDATE_HOST: int len; len = msg.readInt16() - 4; mUpdateHost = msg.readString(len); loginData.updateHost = mUpdateHost; logger->log("Received update host \"%s\" from login server.", mUpdateHost.c_str()); break; case SMSG_LOGIN_DATA: // Skip the length word msg.skip(2); clearWorlds(); worldCount = (msg.getLength() - 47) / 32; mToken.session_ID1 = msg.readInt32(); mToken.account_ID = msg.readInt32(); mToken.session_ID2 = msg.readInt32(); msg.skip(30); // unknown mToken.sex = msg.readInt8() ? GENDER_MALE : GENDER_FEMALE; for (int i = 0; i < worldCount; i++) { WorldInfo *world = new WorldInfo; world->address = msg.readInt32(); world->port = msg.readInt16(); world->name = msg.readString(20); world->online_users = msg.readInt32(); world->updateHost = mUpdateHost; msg.skip(2); // unknown logger->log("Network: Server: %s (%s:%d)", world->name.c_str(), ipToString(world->address), world->port); mWorlds.push_back(world); } Client::setState(STATE_WORLD_SELECT); break; case SMSG_LOGIN_ERROR: code = msg.readInt8(); logger->log("Login::error code: %i", code); switch (code) { case 0: errorMessage = _("Unregistered ID."); break; case 1: errorMessage = _("Wrong password."); break; case 2: errorMessage = _("Account expired."); break; case 3: errorMessage = _("Rejected from server."); break; case 4: errorMessage = _("You have been permanently banned from " "the game. Please contact the GM team."); break; case 5: errorMessage = _("Client too old."); break; case 6: errorMessage = strprintf(_("You have been temporarily " "banned from the game until " "%s.\nPlease contact the GM " "team via the forums."), msg.readString(20).c_str()); break; case 7: errorMessage = _("Server overpopulated."); break; case 9: errorMessage = _("This user name is already taken."); break; case 99: errorMessage = _("Username permanently erased."); break; default: errorMessage = _("Unknown error."); break; } Client::setState(STATE_ERROR); break; case SMSG_SERVER_VERSION_RESPONSE: { // TODO: verify these! msg.readInt8(); // -1 msg.readInt8(); // T msg.readInt8(); // M msg.readInt8(); // W unsigned int options = msg.readInt32(); mRegistrationEnabled = (options & 1); // Leave this last mVersionResponse = true; } break; } }
void CharServerHandler::handleMessage(Net::MessageIn &msg) { switch (msg.getId()) { case SMSG_CHAR_LOGIN: { msg.skip(2); // Length word msg.skip(20); // Unused // Derive number of characters from message length const int count = (msg.getLength() - 24) / 106; for (int i = 0; i < count; ++i) { Net::Character *character = new Net::Character; readPlayerData(msg, character); mCharacters.push_back(character); logger->log("CharServer: Player: %s (%d)", character->dummy->getName().c_str(), character->slot); } Client::setState(STATE_CHAR_SELECT); } break; case SMSG_CHAR_LOGIN_ERROR: switch (msg.readInt8()) { case 0: errorMessage = _("Access denied. Most likely, there are " "too many players on this server."); break; case 1: errorMessage = _("Cannot use this ID."); break; default: errorMessage = _("Unknown char-server failure."); break; } Client::setState(STATE_ERROR); break; case SMSG_CHAR_CREATE_SUCCEEDED: { Net::Character *character = new Net::Character; readPlayerData(msg, character); mCharacters.push_back(character); updateCharSelectDialog(); // Close the character create dialog if (mCharCreateDialog) { mCharCreateDialog->scheduleDelete(); mCharCreateDialog = 0; } } break; case SMSG_CHAR_CREATE_FAILED: new OkDialog(_("Error"), _("Failed to create character. Most " "likely the name is already taken.")); if (mCharCreateDialog) mCharCreateDialog->unlock(); break; case SMSG_CHAR_DELETE_SUCCEEDED: delete mSelectedCharacter; mCharacters.remove(mSelectedCharacter); mSelectedCharacter = 0; updateCharSelectDialog(); unlockCharSelectDialog(); new OkDialog(_("Info"), _("Character deleted.")); break; case SMSG_CHAR_DELETE_FAILED: unlockCharSelectDialog(); new OkDialog(_("Error"), _("Failed to delete character.")); break; case SMSG_CHAR_MAP_INFO: { msg.skip(4); // CharID, must be the same as player_node->charID GameHandler *gh = static_cast<GameHandler*>(Net::getGameHandler()); gh->setMap(msg.readString(16)); mapServer.hostname = ipToString(msg.readInt32()); mapServer.port = msg.readInt16(); // Prevent the selected local player from being deleted player_node = mSelectedCharacter->dummy; PlayerInfo::setBackend(mSelectedCharacter->data); mSelectedCharacter->dummy = 0; delete_all(mCharacters); mCharacters.clear(); updateCharSelectDialog(); mNetwork->disconnect(); Client::setState(STATE_CONNECT_GAME); } break; case SMSG_CHANGE_MAP_SERVER: { GameHandler *gh = static_cast<GameHandler*>(Net::getGameHandler()); gh->setMap(msg.readString(16)); int x = msg.readInt16(); int y = msg.readInt16(); mapServer.hostname = ipToString(msg.readInt32()); mapServer.port = msg.readInt16(); mNetwork->disconnect(); Client::setState(STATE_CHANGE_MAP); player_node->setTileCoords(x, y); player_node->setMap(0); } break; } }
void LoginRecv::processLoginData(Net::MessageIn &msg) { msg.readInt16("len"); loginHandler->clearWorlds(); int offset = 0; int serverLen = 0; if (msg.getVersion() >= 20170315) { offset = 47 + 17; serverLen = 32 + 128; } else { offset = 47; serverLen = 32; } const int worldCount = (msg.getLength() - offset) / serverLen; Ea::LoginRecv::mToken.session_ID1 = msg.readInt32("session id1"); Ea::LoginRecv::mToken.account_ID = msg.readBeingId("accound id"); Ea::LoginRecv::mToken.session_ID2 = msg.readInt32("session id2"); msg.readInt32("old ip"); loginData.lastLogin = msg.readString(24, "last login"); msg.readInt16("unused"); // reserve bits for future usage Ea::LoginRecv::mToken.sex = Being::intToGender(CAST_U8( msg.readUInt8("gender") & 3U)); if (msg.getVersion() >= 20170315) { msg.readString(16, "twitter auth token"); msg.readUInt8("twitter flag"); } for (int i = 0; i < worldCount; i++) { WorldInfo *const world = new WorldInfo; world->address = msg.readInt32("ip address"); world->port = msg.readInt16("port"); world->name = msg.readString(20, "name"); world->online_users = msg.readInt16("online number"); config.setValue("updatehost", Ea::LoginRecv::mUpdateHost); world->updateHost = Ea::LoginRecv::mUpdateHost; msg.readInt16("maintenance"); msg.readInt16("new"); if (msg.getVersion() >= 20170315) { for (int f = 0; f < 32; f ++) msg.readInt32("unused2"); } logger->log("Network: Server: %s (%s:%d)", world->name.c_str(), ipToString(world->address), world->port); Ea::LoginRecv::mWorlds.push_back(world); } client->setState(State::WORLD_SELECT); }