diff options
Diffstat (limited to 'src/net/eathena/charserverrecv.cpp')
-rw-r--r-- | src/net/eathena/charserverrecv.cpp | 515 |
1 files changed, 515 insertions, 0 deletions
diff --git a/src/net/eathena/charserverrecv.cpp b/src/net/eathena/charserverrecv.cpp new file mode 100644 index 000000000..62be4a694 --- /dev/null +++ b/src/net/eathena/charserverrecv.cpp @@ -0,0 +1,515 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2015 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "net/eathena/charserverrecv.h" + +#include "client.h" +#include "configuration.h" +#include "settings.h" + +#include "gui/windows/charcreatedialog.h" +#include "gui/windows/charselectdialog.h" +#include "gui/windows/okdialog.h" + +#include "gui/widgets/createwidget.h" + +#include "net/character.h" +#include "net/playerhandler.h" +#include "net/serverfeatures.h" + +#include "net/ea/token.h" + +#include "net/eathena/gamehandler.h" +#include "net/eathena/loginhandler.h" +#include "net/eathena/messageout.h" +#include "net/eathena/network.h" +#include "net/eathena/protocol.h" +#include "net/eathena/sprite.h" + +#include "resources/iteminfo.h" + +#include "resources/db/itemdb.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" + +#include "debug.h" + +extern Net::CharServerHandler *charServerHandler; + +namespace EAthena +{ + +extern ServerInfo charServer; +extern ServerInfo mapServer; + +namespace CharServerRecv +{ + std::string mNewName; + uint32_t mPinSeed = 0; + BeingId mPinAccountId = BeingId_zero; + BeingId mRenameId = BeingId_zero; + bool mNeedCreatePin = false; +} + +void CharServerRecv::readPlayerData(Net::MessageIn &msg, + Net::Character *const character) +{ + if (!character) + return; + + const Token &token = + static_cast<LoginHandler*>(loginHandler)->getToken(); + + LocalPlayer *const tempPlayer = new LocalPlayer( + msg.readBeingId("player id"), BeingTypeId_zero); + tempPlayer->setGender(token.sex); + + PlayerInfoBackend &data = character->data; + data.mAttributes[Attributes::EXP] = msg.readInt32("exp"); + data.mAttributes[Attributes::MONEY] = msg.readInt32("money"); + Stat &jobStat = data.mStats[Attributes::JOB]; + jobStat.exp = msg.readInt32("job"); + + const int temp = msg.readInt32("job level"); + jobStat.base = temp; + jobStat.mod = temp; + + msg.readInt16("shoes?"); + const int gloves = msg.readInt16("gloves"); + const int cape = msg.readInt16("cape"); + const int misc1 = msg.readInt16("misc1"); + + msg.readInt32("option"); + tempPlayer->setKarma(msg.readInt32("karma")); + tempPlayer->setManner(msg.readInt32("manner")); + msg.readInt16("left points"); + + data.mAttributes[Attributes::HP] = msg.readInt32("hp"); + data.mAttributes[Attributes::MAX_HP] = msg.readInt32("max hp"); + data.mAttributes[Attributes::MP] = msg.readInt16("mp/sp"); + data.mAttributes[Attributes::MAX_MP] = msg.readInt16("max mp/sp"); + + msg.readInt16("speed"); + const uint16_t race = msg.readInt16("class"); +// tempPlayer->setSubtype(race, 0); + const int hairStyle = msg.readInt32("hair style"); + const int option A_UNUSED = (msg.readInt16("weapon") | 1) ^ 1; + const int weapon = 0; + + tempPlayer->setSprite(SPRITE_BODY, weapon, "", ItemColor_one, true); + + data.mAttributes[Attributes::LEVEL] = msg.readInt16("level"); + + msg.readInt16("skill points"); + const int bottomClothes = msg.readInt16("head bottom"); + const int shield = msg.readInt16("shild"); + const int hat = msg.readInt16("head top"); + const int topClothes = msg.readInt16("head mid"); + + const ItemColor color = fromInt(msg.readInt16("hair color"), ItemColor); + tempPlayer->setHairColor(color); + tempPlayer->setSprite(SPRITE_HAIR_COLOR, hairStyle * -1, + ItemDB::get(-hairStyle).getDyeColorsString( + color)); + + const uint16_t look = msg.readInt16("clothes color"); + tempPlayer->setSubtype(fromInt(race, BeingTypeId), look); + tempPlayer->setName(msg.readString(24, "name")); + + character->dummy = tempPlayer; + + character->data.mStats[Attributes::STR].base = msg.readUInt8("str"); + character->data.mStats[Attributes::AGI].base = msg.readUInt8("agi"); + character->data.mStats[Attributes::VIT].base = msg.readUInt8("vit"); + character->data.mStats[Attributes::INT].base = msg.readUInt8("int"); + character->data.mStats[Attributes::DEX].base = msg.readUInt8("dex"); + character->data.mStats[Attributes::LUK].base = msg.readUInt8("luk"); + + character->slot = msg.readInt16("character slot id"); + msg.readInt16("rename"); + msg.readString(16, "map name"); + msg.readInt32("delete date"); + const int shoes = msg.readInt32("robe"); + if (!serverFeatures->haveAdvancedSprites()) + { + tempPlayer->setSprite(SPRITE_HAIR, shoes); + tempPlayer->setSprite(SPRITE_SHOES, gloves); + tempPlayer->setSprite(SPRITE_SHIELD, cape); + tempPlayer->setSprite(SPRITE_HEAD_TOP, misc1); + tempPlayer->setSprite(SPRITE_WEAPON, bottomClothes); + tempPlayer->setSprite(SPRITE_FLOOR, shield); + tempPlayer->setSprite(SPRITE_CLOTHES_COLOR, hat); + tempPlayer->setSprite(SPRITE_HEAD_BOTTOM, topClothes); +// tempPlayer->setSprite(SPRITE_HEAD_MID, misc2); + } + msg.readInt32("slot change"); + tempPlayer->setRename(msg.readInt32("rename (inverse)")); + + const uint8_t gender = static_cast<uint8_t>(msg.readUInt8("gender")); + if (gender != 99) + tempPlayer->setGender(Being::intToGender(gender)); +} + +void CharServerRecv::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(charServerHandler->mCharacters); + charServerHandler->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); + charServerHandler->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 CharServerRecv::processCharLogin2(Net::MessageIn &msg) +{ + // ignored + msg.readInt16("len"); + msg.readUInt8("char slots"); + msg.readUInt8("left slots"); + msg.readUInt8("left slots"); + msg.readUInt8("char slots"); + msg.readUInt8("char slots"); + msg.skip(20, "unused"); +} + +void CharServerRecv::processCharMapInfo(Net::MessageIn &restrict msg) +{ + Network *const network = Network::mInstance; + ServerInfo &server = mapServer; + BLOCK_START("CharServerRecv::processCharMapInfo") + PlayerInfo::setCharId(msg.readInt32("char id")); + GameHandler *const gh = static_cast<GameHandler*>(gameHandler); + gh->setMap(msg.readString(16, "map name")); + if (config.getBoolValue("usePersistentIP") || settings.persistentIp) + { + msg.readInt32("map ip address"); + server.hostname = settings.serverName; + } + else + { + server.hostname = ipToString(msg.readInt32("map ip address")); + } + server.port = msg.readInt16("map ip port"); + + // Prevent the selected local player from being deleted + localPlayer = charServerHandler->mSelectedCharacter->dummy; + PlayerInfo::setBackend(charServerHandler->mSelectedCharacter->data); + PlayerInfo::setStatBase(Attributes::WALK_SPEED, + playerHandler->getDefaultWalkSpeed().x); + + charServerHandler->mSelectedCharacter->dummy = nullptr; + + charServerHandler->clear(); + charServerHandler->updateCharSelectDialog(); + + if (network) + network->disconnect(); + client->setState(STATE_CONNECT_GAME); + BLOCK_END("CharServerRecv::processCharMapInfo") +} + +void CharServerRecv::processChangeMapServer(Net::MessageIn &msg) +{ + Network *const network = Network::mInstance; + ServerInfo &server = mapServer; + BLOCK_START("CharServerRecv::processChangeMapServer") + GameHandler *const gh = static_cast<GameHandler*>(gameHandler); + if (!gh || !network) + { + BLOCK_END("CharServerRecv::processChangeMapServer") + return; + } + gh->setMap(msg.readString(16, "map name")); + const int x = msg.readInt16("x"); + const int y = msg.readInt16("y"); + if (config.getBoolValue("usePersistentIP") || settings.persistentIp) + { + msg.readInt32("host"); + server.hostname = settings.serverName; + } + else + { + server.hostname = ipToString(msg.readInt32("host")); + } + server.port = msg.readInt16("port"); + + network->disconnect(); + client->setState(STATE_CHANGE_MAP); + if (localPlayer) + { + localPlayer->setTileCoords(x, y); + localPlayer->setMap(nullptr); + } + BLOCK_END("CharServerRecv::processChangeMapServer") +} + +void CharServerRecv::processPincodeStatus(Net::MessageIn &msg) +{ + mPinSeed = msg.readInt32("pincode seed"); + mPinAccountId = msg.readBeingId("account id"); + const uint16_t state = static_cast<uint16_t>(msg.readInt16("state")); + switch (state) + { + case 0: // pin ok + break; + case 1: // ask for pin + break; + case 2: // create new pin + case 4: // create new pin? + { + mNeedCreatePin = true; + break; + } + case 3: // pin must be changed + break; + case 5: // client show error? + break; + case 6: // Unable to use your KSSN number + break; + case 7: // char select window shows a button + break; + case 8: // pincode was incorrect + break; + default: + UNIMPLIMENTEDPACKET; + break; + } +} + +void CharServerRecv::processCharCreate(Net::MessageIn &msg) +{ + BLOCK_START("CharServerRecv::processCharCreate") + Net::Character *const character = new Net::Character; + readPlayerData(msg, character); + charServerHandler->mCharacters.push_back(character); + + charServerHandler->updateCharSelectDialog(); + + // Close the character create dialog + if (charServerHandler->mCharCreateDialog) + { + charServerHandler->mCharCreateDialog->scheduleDelete(); + charServerHandler->mCharCreateDialog = nullptr; + } + BLOCK_END("CharServerRecv::processCharCreate") +} + +void CharServerRecv::processCharCheckRename(Net::MessageIn &msg) +{ + if (msg.readInt16("flag")) + { + createOutPacket(CMSG_CHAR_RENAME); + outMsg.writeBeingId(mRenameId, "char id"); + } + else + { + CREATEWIDGET(OkDialog, + // TRANSLATORS: error header + _("Error"), + // TRANSLATORS: error message + _("Character rename error."), + // TRANSLATORS: ok dialog button + _("Error"), + DialogType::ERROR, + Modal_true, + ShowCenter_true, + nullptr, + 260); + } +} + +void CharServerRecv::processCharRename(Net::MessageIn &msg) +{ + const int flag = msg.readInt16("flag"); + if (!flag) + { + charServerHandler->mCharSelectDialog->setName( + mRenameId, + mNewName); + CREATEWIDGET(OkDialog, + // TRANSLATORS: info header + _("Info"), + // TRANSLATORS: info message + _("Character renamed."), + // TRANSLATORS: ok dialog button + _("OK"), + DialogType::OK, + Modal_true, + ShowCenter_true, + nullptr, + 260); + } + else + { + std::string message; + switch (flag) + { + case 1: + // TRANSLATORS: char rename error + message = _("Rename not allowed."); + break; + case 2: + // TRANSLATORS: char rename error + message = _("New name is not set."); + break; + case 3: + default: + // TRANSLATORS: char rename error + message = _("Character rename error."); + break; + case 4: + // TRANSLATORS: char rename error + message = _("Character not found."); + break; + } + CREATEWIDGET(OkDialog, + // TRANSLATORS: info message + _("Info"), + message, + // TRANSLATORS: ok dialog button + _("OK"), + DialogType::OK, + Modal_true, + ShowCenter_true, + nullptr, + 260); + } +} + +void CharServerRecv::processCharChangeSlot(Net::MessageIn &msg) +{ + UNIMPLIMENTEDPACKET; + msg.readInt16("len"); + msg.readInt16("flag"); // 0 - ok, 1 - error + msg.readInt16("unused"); +} + +void CharServerRecv::processCharDeleteFailed(Net::MessageIn &msg) +{ + BLOCK_START("CharServerRecv::processCharDeleteFailed") + charServerHandler->unlockCharSelectDialog(); + msg.readUInt8("error"); + CREATEWIDGET(OkDialog, + // TRANSLATORS: error header + _("Error"), + // TRANSLATORS: error message + _("Failed to delete character."), + // TRANSLATORS: ok dialog button + _("OK"), + DialogType::ERROR, + Modal_true, + ShowCenter_true, + nullptr, + 260); + BLOCK_END("CharServerRecv::processCharDeleteFailed") +} + +void CharServerRecv::processCharCaptchaNotSupported(Net::MessageIn &msg) +{ + UNIMPLIMENTEDPACKET; + msg.readInt16("5"); + msg.readUInt8("1"); +} + +void CharServerRecv::processCharDelete2Ack(Net::MessageIn &msg) +{ + UNIMPLIMENTEDPACKET; + msg.readInt32("char id"); + msg.readInt32("result"); + msg.readInt32("time"); +} + +void CharServerRecv::processCharDelete2AcceptActual(Net::MessageIn &msg) +{ + UNIMPLIMENTEDPACKET; + msg.readInt32("char id"); + msg.readInt32("result"); +} + +void CharServerRecv::processCharDelete2CancelAck(Net::MessageIn &msg) +{ + UNIMPLIMENTEDPACKET; + msg.readInt32("char id"); + msg.readInt32("result"); +} + +void CharServerRecv::processCharCharacters(Net::MessageIn &msg) +{ + msg.skip(2, "packet len"); + + delete_all(charServerHandler->mCharacters); + charServerHandler->mCharacters.clear(); + + // Derive number of characters from message length + const int count = (msg.getLength() - 4) + / (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); + charServerHandler->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 CharServerRecv::processCharBanCharList(Net::MessageIn &msg) +{ + UNIMPLIMENTEDPACKET; + const int count = (msg.readInt16("len") - 4) / 24; + for (int f = 0; f < count; f ++) + { + msg.readInt32("char id"); + msg.readString(20, "unbun time"); + } +} + +} // namespace EAthena |