void ProtocolGameBase::sendCancelWalk() { NetworkMessage msg; msg.addByte(0xB5); msg.addByte(player->getDirection()); writeToOutputBuffer(msg); }
void ProtocolGameBase::sendInventory() { std::map<uint16_t, uint16_t> items = player->getAllItemsClientId(); NetworkMessage msg; msg.addByte(0xF5); msg.add<uint16_t>(items.size() + 11); for (uint16_t i = 1; i <= 11; i++) { msg.add<uint16_t>(i); msg.addByte(0); msg.add<uint16_t>(1); } for (const auto& it : items) { msg.add<uint16_t>(it.first); msg.addByte(0); msg.add<uint16_t>(it.second); } writeToOutputBuffer(msg); }
//tile void ProtocolGameBase::RemoveTileThing(NetworkMessage& msg, const Position& pos, uint32_t stackpos) { if (stackpos >= 10) { return; } msg.addByte(0x6C); msg.addPosition(pos); msg.addByte(stackpos); }
void ProtocolGameBase::AddCreatureLight(NetworkMessage& msg, const Creature* creature) { LightInfo lightInfo; creature->getCreatureLight(lightInfo); msg.addByte(0x8D); msg.add<uint32_t>(creature->getID()); msg.addByte((player->isAccessPlayer() ? 0xFF : lightInfo.level)); msg.addByte(lightInfo.color); }
void ProtocolGameBase::AddPlayerSkills(NetworkMessage& msg) { msg.addByte(0xA1); for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) { msg.add<uint16_t>(std::min<int32_t>(player->getSkillLevel(i), std::numeric_limits<uint16_t>::max())); msg.add<uint16_t>(player->getBaseSkill(i)); msg.addByte(player->getSkillPercent(i)); } }
void ProtocolGameBase::sendBasicData() { NetworkMessage msg; msg.addByte(0x9F); msg.addByte(player->isPremium() ? 0x01 : 0x00); msg.add<uint32_t>(std::numeric_limits<uint32_t>::max()); msg.addByte(player->getVocation()->getClientId()); msg.add<uint16_t>(0x00); writeToOutputBuffer(msg); }
void ProtocolGameBase::sendVIP(uint32_t guid, const std::string& name, const std::string& description, uint32_t icon, bool notify, VipStatus_t status) { NetworkMessage msg; msg.addByte(0xD2); msg.add<uint32_t>(guid); msg.addString(name); msg.addString(description); msg.add<uint32_t>(std::min<uint32_t>(10, icon)); msg.addByte(notify ? 0x01 : 0x00); msg.addByte(status); writeToOutputBuffer(msg); }
void ProtocolGameBase::sendMagicEffect(const Position& pos, uint8_t type) { if (!canSee(pos)) { return; } NetworkMessage msg; msg.addByte(0x83); msg.addPosition(pos); msg.addByte(type); writeToOutputBuffer(msg); }
void ProtocolGameBase::sendInventoryItem(slots_t slot, const Item* item) { NetworkMessage msg; if (item) { msg.addByte(0x78); msg.addByte(slot); msg.addItem(item); } else { msg.addByte(0x79); msg.addByte(slot); } writeToOutputBuffer(msg); }
void ProtocolSpectator::sendEmptyTileOnPlayerPos(const Tile* tile, const Position& playerPos) { NetworkMessage msg; msg.addByte(0x69); msg.addPosition(playerPos); msg.add<uint16_t>(0x00); msg.addItem(tile->getGround()); msg.addByte(0x00); msg.addByte(0xFF); writeToOutputBuffer(msg); }
void ProtocolGameBase::AddOutfit(NetworkMessage& msg, const Outfit_t& outfit) { msg.add<uint16_t>(outfit.lookType); if (outfit.lookType != 0) { msg.addByte(outfit.lookHead); msg.addByte(outfit.lookBody); msg.addByte(outfit.lookLegs); msg.addByte(outfit.lookFeet); msg.addByte(outfit.lookAddons); } else { msg.addItemId(outfit.lookTypeEx); } msg.add<uint16_t>(outfit.lookMount); }
void ProtocolGameBase::sendChannel(uint16_t channelId, const std::string& channelName, const UsersMap* channelUsers, const InvitedMap* invitedUsers) { NetworkMessage msg; msg.addByte(0xAC); msg.add<uint16_t>(channelId); msg.addString(channelName); if (channelUsers) { msg.add<uint16_t>(channelUsers->size()); for (const auto& it : *channelUsers) { msg.addString(it.second->getName()); } } else { msg.add<uint16_t>(0x00); } if (invitedUsers) { msg.add<uint16_t>(invitedUsers->size()); for (const auto& it : *invitedUsers) { msg.addString(it.second->getName()); } } else { msg.add<uint16_t>(0x00); } writeToOutputBuffer(msg); }
void ProtocolGameBase::sendMapDescription(const Position& pos) { NetworkMessage msg; msg.addByte(0x64); msg.addPosition(player->getPosition()); GetMapDescription(pos.x - 8, pos.y - 6, pos.z, 18, 14, msg); writeToOutputBuffer(msg); }
void ProtocolGameBase::sendUpdateTile(const Tile* tile, const Position& pos) { if (!canSee(pos)) { return; } NetworkMessage msg; msg.addByte(0x69); msg.addPosition(pos); if (tile) { GetTileDescription(tile, msg); msg.addByte(0x00); msg.addByte(0xFF); } else { msg.addByte(0x01); msg.addByte(0xFF); } writeToOutputBuffer(msg); }
void ProtocolGameBase::AddPlayerStats(NetworkMessage& msg) { msg.addByte(0xA0); msg.add<uint16_t>(std::min<int32_t>(player->getHealth(), std::numeric_limits<uint16_t>::max())); msg.add<uint16_t>(std::min<int32_t>(player->getPlayerInfo(PLAYERINFO_MAXHEALTH), std::numeric_limits<uint16_t>::max())); msg.add<uint32_t>(player->getFreeCapacity()); msg.add<uint32_t>(player->getCapacity()); msg.add<uint64_t>(player->getExperience()); msg.add<uint16_t>(player->getLevel()); msg.addByte(player->getPlayerInfo(PLAYERINFO_LEVELPERCENT)); msg.addDouble(0, 3); // experience bonus msg.add<uint16_t>(std::min<int32_t>(player->getMana(), std::numeric_limits<uint16_t>::max())); msg.add<uint16_t>(std::min<int32_t>(player->getPlayerInfo(PLAYERINFO_MAXMANA), std::numeric_limits<uint16_t>::max())); msg.addByte(std::min<uint32_t>(player->getMagicLevel(), std::numeric_limits<uint8_t>::max())); msg.addByte(std::min<uint32_t>(player->getBaseMagicLevel(), std::numeric_limits<uint8_t>::max())); msg.addByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVELPERCENT)); msg.addByte(player->getSoul()); msg.add<uint16_t>(player->getStaminaMinutes()); msg.add<uint16_t>(player->getBaseSpeed() / 2); Condition* condition = player->getCondition(CONDITION_REGENERATION); msg.add<uint16_t>(condition ? condition->getTicks() / 1000 : 0x00); msg.add<uint16_t>(player->getOfflineTrainingTime() / 60 / 1000); }
void ProtocolSpectator::syncKnownCreatureSets() { const auto& casterKnownCreatures = client->getKnownCreatures(); const auto playerPos = player->getPosition(); const auto tile = player->getTile(); if (!tile || !tile->getGround()) { disconnectSpectator("A sync error has occured."); return; } sendEmptyTileOnPlayerPos(tile, playerPos); bool known; uint32_t removedKnown; for (const auto creatureID : casterKnownCreatures) { if (knownCreatureSet.find(creatureID) != knownCreatureSet.end()) { continue; } NetworkMessage msg; const auto creature = g_game.getCreatureByID(creatureID); if (creature && !creature->isRemoved()) { msg.addByte(0x6A); msg.addPosition(playerPos); msg.addByte(1); //stackpos checkCreatureAsKnown(creature->getID(), known, removedKnown); AddCreature(msg, creature, known, removedKnown); RemoveTileThing(msg, playerPos, 1); } else if (operatingSystem <= CLIENTOS_FLASH) { // otclient freeze with huge amount of creature add, but do not debug if there are unknown creatures, best solution for now :( addDummyCreature(msg, creatureID, playerPos); RemoveTileThing(msg, playerPos, 1); } writeToOutputBuffer(msg); } sendUpdateTile(tile, playerPos); }
void ProtocolGameBase::GetFloorDescription(NetworkMessage& msg, int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, int32_t offset, int32_t& skip) { for (int32_t nx = 0; nx < width; nx++) { for (int32_t ny = 0; ny < height; ny++) { Tile* tile = g_game.map.getTile(x + nx + offset, y + ny + offset, z); if (tile) { if (skip >= 0) { msg.addByte(skip); msg.addByte(0xFF); } skip = 0; GetTileDescription(tile, msg); } else if (skip == 0xFE) { msg.addByte(0xFF); msg.addByte(0xFF); skip = -1; } else { ++skip; } } } }
void ProtocolGameBase::sendContainer(uint8_t cid, const Container* container, bool hasParent, uint16_t firstIndex) { NetworkMessage msg; msg.addByte(0x6E); msg.addByte(cid); if (container->getID() == ITEM_BROWSEFIELD) { msg.addItem(1987, 1); msg.addString("Browse Field"); } else { msg.addItem(container); msg.addString(container->getName()); } msg.addByte(container->capacity()); msg.addByte(hasParent ? 0x01 : 0x00); msg.addByte(container->isUnlocked() ? 0x01 : 0x00); // Drag and drop msg.addByte(container->hasPagination() ? 0x01 : 0x00); // Pagination uint32_t containerSize = container->size(); msg.add<uint16_t>(containerSize); msg.add<uint16_t>(firstIndex); if (firstIndex < containerSize) { uint8_t itemsToSend = std::min<uint32_t>(std::min<uint32_t>(container->capacity(), containerSize - firstIndex), std::numeric_limits<uint8_t>::max()); msg.addByte(itemsToSend); for (ItemDeque::const_iterator it = container->getItemList().begin() + firstIndex, end = it + itemsToSend; it != end; ++it) { msg.addItem(*it); } } else { msg.addByte(0x00); } writeToOutputBuffer(msg); }
void ProtocolGameBase::GetMapDescription(int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, NetworkMessage& msg) { int32_t skip = -1; int32_t startz, endz, zstep; if (z > 7) { startz = z - 2; endz = std::min<int32_t>(MAP_MAX_LAYERS - 1, z + 2); zstep = 1; } else { startz = 7; endz = 0; zstep = -1; } for (int32_t nz = startz; nz != endz + zstep; nz += zstep) { GetFloorDescription(msg, x, y, nz, width, height, z - nz, skip); } if (skip >= 0) { msg.addByte(skip); msg.addByte(0xFF); } }
void ProtocolGameBase::sendPingBack() { NetworkMessage msg; msg.addByte(0x1E); writeToOutputBuffer(msg, false); }
void ProtocolGameBase::AddWorldLight(NetworkMessage& msg, const LightInfo& lightInfo) { msg.addByte(0x82); msg.addByte((player->isAccessPlayer() ? 0xFF : lightInfo.level)); msg.addByte(lightInfo.color); }
void ProtocolGameBase::sendEnterWorld() { NetworkMessage msg; msg.addByte(0x0F); writeToOutputBuffer(msg); }
void ProtocolGameBase::sendPendingStateEntered() { NetworkMessage msg; msg.addByte(0x0A); writeToOutputBuffer(msg); }
void ProtocolGameBase::AddCreature(NetworkMessage& msg, const Creature* creature, bool known, uint32_t remove) { CreatureType_t creatureType = creature->getType(); const Player* otherPlayer = creature->getPlayer(); if (known) { msg.add<uint16_t>(0x62); msg.add<uint32_t>(creature->getID()); } else { msg.add<uint16_t>(0x61); msg.add<uint32_t>(remove); msg.add<uint32_t>(creature->getID()); msg.addByte(creatureType); msg.addString(creature->getName()); } if (creature->isHealthHidden()) { msg.addByte(0x00); } else { msg.addByte(std::ceil((static_cast<double>(creature->getHealth()) / std::max<int32_t>(creature->getMaxHealth(), 1)) * 100)); } msg.addByte(creature->getDirection()); if (!creature->isInGhostMode() && !creature->isInvisible()) { AddOutfit(msg, creature->getCurrentOutfit()); } else { static Outfit_t outfit; AddOutfit(msg, outfit); } LightInfo lightInfo; creature->getCreatureLight(lightInfo); msg.addByte(player->isAccessPlayer() ? 0xFF : lightInfo.level); msg.addByte(lightInfo.color); msg.add<uint16_t>(creature->getStepSpeed() / 2); msg.addByte(player->getSkullClient(creature)); msg.addByte(player->getPartyShield(otherPlayer)); if (!known) { msg.addByte(player->getGuildEmblem(otherPlayer)); } if (creatureType == CREATURETYPE_MONSTER) { const Creature* master = creature->getMaster(); if (master) { const Player* masterPlayer = master->getPlayer(); if (masterPlayer) { if (masterPlayer == player) { creatureType = CREATURETYPE_SUMMON_OWN; } else { creatureType = CREATURETYPE_SUMMON_OTHERS; } } } } msg.addByte(creatureType); // Type (for summons) msg.addByte(creature->getSpeechBubble()); msg.addByte(0xFF); // MARK_UNMARKED if (otherPlayer) { msg.add<uint16_t>(otherPlayer->getHelpers()); } else { msg.add<uint16_t>(0x00); } msg.addByte(player->canWalkthroughEx(creature) ? 0x00 : 0x01); }
void ProtocolSpectator::addDummyCreature(NetworkMessage& msg, const uint32_t& creatureID, const Position& playerPos) { // add dummy creature CreatureType_t creatureType = CREATURETYPE_NPC; if(creatureID <= 0x10000000) { creatureType = CREATURETYPE_PLAYER; } else if(creatureID <= 0x40000000) { creatureType = CREATURETYPE_MONSTER; } msg.addByte(0x6A); msg.addPosition(playerPos); msg.addByte(1); //stackpos msg.add<uint16_t>(0x61); // is not known msg.add<uint32_t>(0); // remove no creature msg.add<uint32_t>(creatureID); // creature id msg.addByte(creatureType); // creature type msg.addString("Dummy"); msg.addByte(0x00); // health percent msg.addByte(DIRECTION_NORTH); // direction AddOutfit(msg, player->getCurrentOutfit()); // outfit msg.addByte(0); // light level msg.addByte(0); // light color msg.add<uint16_t>(200); // speed msg.addByte(SKULL_NONE); // skull type msg.addByte(SHIELD_NONE); // party shield msg.addByte(GUILDEMBLEM_NONE); // guild emblem msg.addByte(creatureType); // creature type msg.addByte(SPEECHBUBBLE_NONE); // speechbubble msg.addByte(0xFF); // MARK_UNMARKED msg.add<uint16_t>(0x00); // helpers msg.addByte(0); // walkThrough }
void ProtocolSpectator::onRecvFirstMessage(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->close(); return; } operatingSystem = (OperatingSystem_t)msg.get<uint16_t>(); version = msg.get<uint16_t>(); msg.skipBytes(7); // U32 clientVersion, U8 clientType if (!RSA_decrypt(msg)) { getConnection()->close(); return; } uint32_t key[4]; key[0] = msg.get<uint32_t>(); key[1] = msg.get<uint32_t>(); key[2] = msg.get<uint32_t>(); key[3] = msg.get<uint32_t>(); enableXTEAEncryption(); setXTEAKey(key); if (operatingSystem >= CLIENTOS_OTCLIENT_LINUX) { NetworkMessage opcodeMessage; opcodeMessage.addByte(0x32); opcodeMessage.addByte(0x00); opcodeMessage.add<uint16_t>(0x00); writeToOutputBuffer(opcodeMessage); } msg.skipBytes(1); // gamemaster flag std::string password = msg.getString(); std::string characterName = msg.getString(); uint32_t timeStamp = msg.get<uint32_t>(); uint8_t randNumber = msg.getByte(); if (m_challengeTimestamp != timeStamp || m_challengeRandom != randNumber) { getConnection()->close(); return; } auto dispatchDisconnectClient = [this](const std::string& msg) { g_dispatcher.addTask(createTask( std::bind(&ProtocolSpectator::disconnectSpectator, this, msg))); }; if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return; } if (g_game.getGameState() == GAME_STATE_STARTUP) { dispatchDisconnectClient("Gameworld is starting up. Please wait."); return; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { dispatchDisconnectClient("Gameworld is under maintenance. Please re-connect in a while."); return; } BanInfo banInfo; if (IOBan::isIpBanned(getIP(), banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; dispatchDisconnectClient(ss.str()); return; } password.erase(password.begin()); g_dispatcher.addTask(createTask(std::bind(&ProtocolSpectator::login, this, characterName, password))); }
void ProtocolGameBase::sendAddCreature(const Creature* creature, const Position& pos, int32_t stackpos, bool isLogin) { if (!canSee(pos)) { return; } if (creature != player) { if (stackpos != -1) { NetworkMessage msg; msg.addByte(0x6A); msg.addPosition(pos); msg.addByte(stackpos); bool known; uint32_t removedKnown; checkCreatureAsKnown(creature->getID(), known, removedKnown); AddCreature(msg, creature, known, removedKnown); writeToOutputBuffer(msg); } if (isLogin) { sendMagicEffect(pos, CONST_ME_TELEPORT); } return; } NetworkMessage msg; msg.addByte(0x17); msg.add<uint32_t>(player->getID()); msg.add<uint16_t>(0x32); // beat duration (50) msg.addDouble(Creature::speedA, 3); msg.addDouble(Creature::speedB, 3); msg.addDouble(Creature::speedC, 3); // can report bugs? if (player->getAccountType() >= ACCOUNT_TYPE_TUTOR) { msg.addByte(0x01); } else { msg.addByte(0x00); } msg.addByte(0x00); // can change pvp framing option msg.addByte(0x00); // expert mode button enabled msg.addString("http://static.tibia.com/images/store/"); msg.addByte(3); writeToOutputBuffer(msg); sendPendingStateEntered(); sendEnterWorld(); sendMapDescription(pos); if (isLogin) { sendMagicEffect(pos, CONST_ME_TELEPORT); } sendInventoryItem(CONST_SLOT_HEAD, player->getInventoryItem(CONST_SLOT_HEAD)); sendInventoryItem(CONST_SLOT_NECKLACE, player->getInventoryItem(CONST_SLOT_NECKLACE)); sendInventoryItem(CONST_SLOT_BACKPACK, player->getInventoryItem(CONST_SLOT_BACKPACK)); sendInventoryItem(CONST_SLOT_ARMOR, player->getInventoryItem(CONST_SLOT_ARMOR)); sendInventoryItem(CONST_SLOT_RIGHT, player->getInventoryItem(CONST_SLOT_RIGHT)); sendInventoryItem(CONST_SLOT_LEFT, player->getInventoryItem(CONST_SLOT_LEFT)); sendInventoryItem(CONST_SLOT_LEGS, player->getInventoryItem(CONST_SLOT_LEGS)); sendInventoryItem(CONST_SLOT_FEET, player->getInventoryItem(CONST_SLOT_FEET)); sendInventoryItem(CONST_SLOT_RING, player->getInventoryItem(CONST_SLOT_RING)); sendInventoryItem(CONST_SLOT_AMMO, player->getInventoryItem(CONST_SLOT_AMMO)); sendStats(); sendSkills(); //gameworld light-settings LightInfo lightInfo; g_game.getWorldLightInfo(lightInfo); sendWorldLight(lightInfo); //player light level sendCreatureLight(creature); const std::forward_list<VIPEntry>& vipEntries = IOLoginData::getVIPEntries(player->getAccount()); if (player->isAccessPlayer()) { for (const VIPEntry& entry : vipEntries) { VipStatus_t vipStatus; Player* vipPlayer = g_game.getPlayerByGUID(entry.guid); if (!vipPlayer) { vipStatus = VIPSTATUS_OFFLINE; } else { vipStatus = VIPSTATUS_ONLINE; } sendVIP(entry.guid, entry.name, entry.description, entry.icon, entry.notify, vipStatus); } } else { for (const VIPEntry& entry : vipEntries) { VipStatus_t vipStatus; Player* vipPlayer = g_game.getPlayerByGUID(entry.guid); if (!vipPlayer || vipPlayer->isInGhostMode()) { vipStatus = VIPSTATUS_OFFLINE; } else { vipStatus = VIPSTATUS_ONLINE; } sendVIP(entry.guid, entry.name, entry.description, entry.icon, entry.notify, vipStatus); } } sendBasicData(); sendInventory(); player->sendIcons(); }