void Maps::usePortal(Player *player, PacketReader &packet) { packet.skipBytes(1); int32_t opcode = packet.get<int32_t>(); switch (opcode) { case 0: // Dead if (player->getStats()->getHp() == 0) { packet.getString(); // Useless packet.skipBytes(1); // Useless bool wheel = packet.getBool(); if (wheel && player->getInventory()->getItemAmount(Items::WheelOfDestiny) <= 0) { player->acceptDeath(false); return; } Inventory::takeItem(player, Items::WheelOfDestiny, 1); player->acceptDeath(wheel); } break; case -1: { string portalname = packet.getString(); Map *tomap = getMap(player->getMap()); if (tomap == nullptr) return; PortalInfo *portal = tomap->getPortal(portalname); if (portal == nullptr) // Exit the function if portal is not found return; usePortal(player, portal); break; } default: { // GM Map change (command "/m") if (player->isGm() && getMap(opcode)) { player->setMap(opcode); } } } }
void Skills::addSkill(Player *player, PacketReader &packet) { packet.skipBytes(4); int32_t skillid = packet.get<int32_t>(); if (!GameLogicUtilities::isBeginnerSkill(skillid)) { if (player->getStats()->getSp() == 0) { // Hacking return; } if (!player->isGm() && !GameLogicUtilities::skillMatchesJob(skillid, player->getStats()->getJob())) { // Hacking return; } } if (player->getSkills()->addSkillLevel(skillid, 1) && !GameLogicUtilities::isBeginnerSkill(skillid)) { player->getStats()->setSp(player->getStats()->getSp() - 1); } }
void MobHandler::monsterControl(Player *player, PacketReader &packet) { int32_t mobid = packet.get<int32_t>(); Mob *mob = Maps::getMap(player->getMap())->getMob(mobid); if (mob == nullptr || mob->getControlStatus() == Mobs::ControlStatus::ControlNone) { return; } int16_t moveid = packet.get<int16_t>(); bool useskill = packet.getBool(); int8_t skill = packet.get<int8_t>(); uint8_t realskill = 0; uint8_t level = 0; Pos projectiletarget = packet.getPos(); packet.skipBytes(5); // 1 byte of always 0?, 4 bytes of always 1 or always 0? Pos spot = packet.getPos(); MovementHandler::parseMovement(mob, packet); if (useskill && (skill == -1 || skill == 0)) { if (!(mob->hasStatus(StatusEffects::Mob::Freeze) || mob->hasStatus(StatusEffects::Mob::Stun) || mob->hasStatus(StatusEffects::Mob::ShadowWeb))) { uint8_t size = mob->getSkillCount(); bool used = false; if (size) { bool stop = false; uint8_t rand = Randomizer::Instance()->randChar(size - 1); MobSkillInfo *info = MobDataProvider::Instance()->getMobSkill(mob->getMobId(), rand); realskill = info->skillId; level = info->level; MobSkillLevelInfo *mobskill = SkillDataProvider::Instance()->getMobSkill(realskill, level); switch (realskill) { case MobSkills::WeaponAttackUp: case MobSkills::WeaponAttackUpAoe: stop = mob->hasStatus(StatusEffects::Mob::Watk); break; case MobSkills::MagicAttackUp: case MobSkills::MagicAttackUpAoe: stop = mob->hasStatus(StatusEffects::Mob::Matk); break; case MobSkills::WeaponDefenseUp: case MobSkills::WeaponDefenseUpAoe: stop = mob->hasStatus(StatusEffects::Mob::Wdef); break; case MobSkills::MagicDefenseUp: case MobSkills::MagicDefenseUpAoe: stop = mob->hasStatus(StatusEffects::Mob::Mdef); break; case MobSkills::WeaponImmunity: case MobSkills::MagicImmunity: case MobSkills::WeaponDamageReflect: case MobSkills::MagicDamageReflect: stop = mob->hasImmunity(); break; case MobSkills::McSpeedUp: stop = mob->hasStatus(StatusEffects::Mob::Speed); break; case MobSkills::Summon: { int16_t limit = mobskill->limit; if (limit == 5000) // Custom limit based on number of players on map limit = 30 + Maps::getMap(mob->getMapId())->getNumPlayers() * 2; if (mob->getSpawnCount() >= limit) stop = true; break; } } if (!stop) { time_t now = time(0); time_t ls = mob->getLastSkillUse(realskill); if (ls == 0 || ((int32_t)(now - ls) > mobskill->interval)) { mob->setLastSkillUse(realskill, now); int64_t reqhp = mob->getHp() * 100; reqhp /= mob->getMaxHp(); if ((uint8_t)(reqhp) <= mobskill->hp) { if (info->effectAfter == 0) { handleMobSkill(mob, realskill, level, mobskill); } else { new Timer::Timer(bind(&MobHandler::handleMobSkill, mob, realskill, level, mobskill), Timer::Id(Timer::Types::MobSkillTimer, mob->getMobId(), mob->getCounter()), mob->getTimers(), Timer::Time::fromNow(info->effectAfter)); } used = true; } } } } if (!used) { realskill = 0; level = 0; } } } MobsPacket::moveMobResponse(player, mobid, moveid, useskill, mob->getMp(), realskill, level); packet.reset(19); MobsPacket::moveMob(player, mobid, useskill, skill, projectiletarget, packet.getBuffer(), packet.getBufferLength()); }
bool InventoryHandler::handleRockTeleport(Player *player, int32_t itemid, PacketReader &packet) { if (itemid == Items::SpecialTeleportRock) { packet.skipBytes(5); } int8_t type = InventoryPacket::RockTypes::Regular; switch (itemid) { case Items::VipRock: type = InventoryPacket::RockTypes::Vip; break; case Items::SpecialTeleportRock: type = packet.get<int8_t>(); break; } bool used = false; int8_t mode = packet.get<int8_t>(); int32_t targetmapid = -1; enum Modes { PresetMap = 0x00, Ign = 0x01 }; if (mode == PresetMap) { targetmapid = packet.get<int32_t>(); if (!player->getInventory()->ensureRockDestination(targetmapid)) { // Hacking return false; } } else if (mode == Ign) { string tname = packet.getString(); Player *target = PlayerDataProvider::Instance()->getPlayer(tname); if (target != nullptr && target != player) { targetmapid = target->getMap(); } else if (target == nullptr) { InventoryPacket::sendRockError(player, InventoryPacket::RockErrors::DifficultToLocate, type); } else if (target == player) { // Hacking return false; } } if (targetmapid != -1) { Map *destination = Maps::getMap(targetmapid); Map *origin = Maps::getMap(player->getMap()); if (!destination->canVip()) { InventoryPacket::sendRockError(player, InventoryPacket::RockErrors::CannotGo, type); } else if (!origin->canVip()) { InventoryPacket::sendRockError(player, InventoryPacket::RockErrors::CannotGo, type); } else if (player->getMap() == targetmapid) { InventoryPacket::sendRockError(player, InventoryPacket::RockErrors::AlreadyThere, type); } else if (type == InventoryPacket::RockTypes::Regular && destination->getContinent() != origin->getContinent()) { InventoryPacket::sendRockError(player, InventoryPacket::RockErrors::CannotGo, type); } else if (player->getStats()->getLevel() < 7 && origin->getContinent() == 0 && destination->getContinent() != 0) { InventoryPacket::sendRockError(player, InventoryPacket::RockErrors::NoobsCannotLeaveMapleIsland, type); } else { player->setMap(targetmapid); used = true; } } if (itemid == Items::SpecialTeleportRock) { if (used) { Inventory::takeItem(player, itemid, 1); } else { InventoryPacket::blankUpdate(player); } } return used; }
void InventoryHandler::useCashItem(Player *player, PacketReader &packet) { packet.get<int8_t>(); // Type packet.skipBytes(1); int32_t itemid = packet.get<int32_t>(); if (!player->getInventory()->getItemAmount(itemid)) { // Hacking return; } bool used = false; if (GameLogicUtilities::getItemType(itemid) == Items::Types::WeatherCash) { string message = packet.getString(); if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } if (message.length() <= 35) { Map *map = Maps::getMap(player->getMap()); message = player->getName() + " 's message : " + message; used = map->createWeather(player, false, Items::WeatherTime, itemid, message); } } else if (GameLogicUtilities::getItemType(itemid) == Items::Types::CashPetFood) { // Pet food. Pet *pet = player->getPets()->getSummoned(0); if (pet != nullptr) { if (pet->getFullness() < Stats::MaxFullness) { PetsPacket::showAnimation(player, pet, 1); pet->modifyFullness(Stats::MaxFullness, false); pet->addCloseness(100); // All cash pet food gives 100 closeness. used = true; } } } else { switch (itemid) { case Items::TeleportRock: case Items::TeleportCoke: case Items::VipRock: // Only occurs when you actually try to move somewhere used = handleRockTeleport(player, itemid, packet); break; case Items::FirstJobSpReset: case Items::SecondJobSpReset: case Items::ThirdJobSpReset: case Items::FourthJobSpReset: { int32_t toskill = packet.get<int32_t>(); int32_t fromskill = packet.get<int32_t>(); if (!player->getSkills()->addSkillLevel(fromskill, -1, true)) { // Hacking return; } if (!player->getSkills()->addSkillLevel(toskill, 1, true)) { // Hacking return; } used = true; break; } case Items::ApReset: { int32_t tostat = packet.get<int32_t>(); int32_t fromstat = packet.get<int32_t>(); player->getStats()->addStat(tostat, 1, true); player->getStats()->addStat(fromstat, -1, true); used = true; break; } case Items::Megaphone: { string msg = player->getMedalName() + " : " + packet.getString(); InventoryPacket::showMegaphone(player, msg); used = true; break; } case Items::SuperMegaphone: { string msg = player->getMedalName() + " : " + packet.getString(); bool whisper = packet.getBool(); InventoryPacket::showSuperMegaphone(player, msg, whisper); used = true; break; } case Items::DiabloMessenger: case Items::Cloud9Messenger: case Items::LoveholicMessenger: { string msg = packet.getString(); string msg2 = packet.getString(); string msg3 = packet.getString(); string msg4 = packet.getString(); InventoryPacket::showMessenger(player, msg, msg2, msg3, msg4, packet.getBuffer(), packet.getBufferLength(), itemid); used = true; break; } case Items::ItemMegaphone: { string msg = player->getMedalName() + " : " + packet.getString(); bool whisper = packet.getBool(); Item *item = nullptr; if (packet.getBool()) { int8_t inv = (int8_t) packet.get<int32_t>(); int16_t slot = (int16_t) packet.get<int32_t>(); item = player->getInventory()->getItem(inv, slot); if (item == nullptr) { // Hacking return; } } InventoryPacket::showItemMegaphone(player, msg, whisper, item); used = true; break; } case Items::ArtMegaphone: { int8_t lines = packet.get<int8_t>(); if (lines < 1 || lines > 3) { // Hacking return; } string text[3]; for (int8_t i = 0; i < lines; i++) { text[i] = player->getMedalName() + " : " + packet.getString(); } bool whisper = packet.getBool(); InventoryPacket::showTripleMegaphone(player, lines, text[0], text[1], text[2], whisper); used = true; break; } case Items::PetNameTag: { string name = packet.getString(); PetHandler::changeName(player, name); used = true; break; } case Items::ItemNameTag: { int16_t slot = packet.get<int16_t>(); if (slot != 0) { Item *item = player->getInventory()->getItem(Inventories::EquipInventory, slot); if (item == nullptr) { // Hacking or failure, dunno return; } item->setName(player->getName()); InventoryPacket::addNewItem(player, Inventories::EquipInventory, slot, item, true); used = true; } break; } case Items::ItemLock: case Items::ScissorsOfKarma: { int8_t inventory = (int8_t) packet.get<int32_t>(); int16_t slot = (int16_t) packet.get<int32_t>(); if (slot != 0) { Item *item = player->getInventory()->getItem(inventory, slot); if (item == nullptr || (itemid == Items::ItemLock && item->hasLock()) || item->hasTradeBlock() || (itemid == Items::ScissorsOfKarma && item->hasKarma())) { // Hacking or failure, dunno return; } ItemInfo *info = ItemDataProvider::Instance()->getItemInfo(item->getId()); if (itemid == Items::ScissorsOfKarma && info->karmascissors) { // Hacking return; } switch (itemid) { case Items::ItemLock: item->setLock(true); break; case Items::ScissorsOfKarma: item->setKarma(true); break; } InventoryPacket::addNewItem(player, inventory, slot, item, true); used = true; } break; } case Items::MapleTvMessenger: case Items::Megassenger: { bool hasreceiver = (packet.get<int8_t>() == 3); bool show_whisper = (itemid == Items::Megassenger ? packet.getBool() : false); Player *receiver = PlayerDataProvider::Instance()->getPlayer(packet.getString()); int32_t time = 15; if ((hasreceiver && receiver != nullptr) || (!hasreceiver && receiver == nullptr)) { string msg = packet.getString(); string msg2 = packet.getString(); string msg3 = packet.getString(); string msg4 = packet.getString(); string msg5 = packet.getString(); if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } MapleTvs::Instance()->addMessage(player, receiver, msg, msg2, msg3, msg4, msg5, itemid - (itemid == Items::Megassenger ? 3 : 0), time); if (itemid == Items::Megassenger) { InventoryPacket::showSuperMegaphone(player, player->getMedalName() + " : " + msg + msg2 + msg3 + msg4 + msg5, show_whisper); } used = true; } break; } case Items::MapleTvStarMessenger: case Items::StarMegassenger: { int32_t time = 30; bool show_whisper = (itemid == Items::StarMegassenger ? packet.getBool() : false); string msg = packet.getString(); string msg2 = packet.getString(); string msg3 = packet.getString(); string msg4 = packet.getString(); string msg5 = packet.getString(); if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } MapleTvs::Instance()->addMessage(player, nullptr, msg, msg2, msg3, msg4, msg5, itemid - (itemid == Items::StarMegassenger ? 3 : 0), time); if (itemid == Items::StarMegassenger) { InventoryPacket::showSuperMegaphone(player, player->getMedalName() + " : " + msg + msg2 + msg3 + msg4 + msg5, show_whisper); } used = true; break; } case Items::MapleTvHeartMessenger: case Items::HeartMegassenger: { bool show_whisper = (itemid == Items::HeartMegassenger ? packet.getBool() : false); string name = packet.getString(); Player *receiver = PlayerDataProvider::Instance()->getPlayer(name); int32_t time = 60; if (receiver != nullptr) { string msg = packet.getString(); string msg2 = packet.getString(); string msg3 = packet.getString(); string msg4 = packet.getString(); string msg5 = packet.getString(); if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } MapleTvs::Instance()->addMessage(player, receiver, msg, msg2, msg3, msg4, msg5, itemid - (itemid == Items::HeartMegassenger ? 3 : 0), time); if (itemid == Items::HeartMegassenger) { InventoryPacket::showSuperMegaphone(player, player->getMedalName() + " : " + msg + msg2 + msg3 + msg4 + msg5, show_whisper); } used = true; } break; } case Items::BronzeSackOfMesos: case Items::SilverSackOfMesos: case Items::GoldSackOfMesos: { int32_t mesos = ItemDataProvider::Instance()->getMesoBonus(itemid); if (!player->getInventory()->modifyMesos(mesos)) { InventoryPacket::sendMesobagFailed(player); } else { InventoryPacket::sendMesobagSucceed(player, mesos); used = true; } break; } case Items::Chalkboard: case Items::Chalkboard2: { string msg = packet.getString(); player->setChalkboard(msg); InventoryPacket::sendChalkboardUpdate(player, msg); break; } case Items::FungusScroll: case Items::OinkerDelight: case Items::ZetaNightmare: Inventory::useItem(player, itemid); used = true; break; case Items::ViciousHammer: { int8_t inventory = (int8_t) packet.get<int32_t>(); // How pointless... int16_t slot = (int16_t) packet.get<int32_t>(); Item *f = player->getInventory()->getItem(inventory, slot); if (f == nullptr || f->getHammers() == Items::MaxHammers) { // Hacking, probably return; } f->incHammers(); f->incSlots(); InventoryPacket::sendHammerSlots(player, f->getHammers()); player->getInventory()->setHammerSlot(slot); used = true; break; } case Items::CongratulatorySong: if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } used = Maps::getMap(player->getMap())->playJukebox(player, itemid, 60 * 5); // 5 minutes is enough! break; case Items::KoreanKite: case Items::HeartBalloon: case Items::GraduationBanner: case Items::AdmissionBanner: { string message = packet.getString(); if (!player->updateTickCount(packet.get<int32_t>())) { // Tickcount was the same or less than 100 of the difference. return; } used = Maps::getMap(player->getMap())->createKite(player, itemid, message); if (!used) { InventoryPacket::sendCannotFlyHere(player); } break; } default: { packet.reset(); std::stringstream x; x << "Unknown cash item! ItemID: " << itemid << "; Player ID: " << player->getId() << "; Packet: " << packet; ChannelServer::Instance()->log(LogTypes::Info, x.str()); break; } } } if (used) { Inventory::takeItem(player, itemid, 1); } else { InventoryPacket::blankUpdate(player); } }
Pos MovementHandler::parseMovement(MovableLife *life, PacketReader &packet) { int16_t foothold = 0; int8_t stance = 0; int16_t x = 0; int16_t y = 0; uint8_t n = packet.get<uint8_t>(); for (uint8_t i = 0; i < n; i++) { int8_t type = packet.get<int8_t>(); switch (type) { case 10: // Falling of some kind packet.skipBytes(1); break; case 16: // Wings packet.skipBytes(7); break; case 17: // Part of Wings, the falling, I believe x = packet.get<int16_t>(); y = packet.get<int16_t>(); foothold = packet.get<int16_t>(); stance = packet.get<int8_t>(); packet.skipBytes(6); break; case 12: // Horntail knockback packet.skipBytes(7); break; case 14: packet.skipBytes(9); break; case 0: // Normal up/down/left/right movement case 5: x = packet.get<int16_t>(); y = packet.get<int16_t>(); packet.skipBytes(4); foothold = packet.get<int16_t>(); stance = packet.get<int8_t>(); packet.skipBytes(2); break; case 1: // Jumping case 2: // Jumping/knockback? case 6: // Flash Jump case 13: // Recoil Shot x = packet.get<int16_t>(); y = packet.get<int16_t>(); stance = packet.get<int8_t>(); foothold = packet.get<int16_t>(); break; case 15: // Jump down x = packet.get<int16_t>(); y = packet.get<int16_t>(); packet.skipBytes(6); foothold = packet.get<int16_t>(); stance = packet.get<int8_t>(); packet.skipBytes(2); break; case 11: // Chair x = packet.get<int16_t>(); y = packet.get<int16_t>(); foothold = packet.get<int16_t>(); stance = packet.get<int8_t>(); packet.skipBytes(2); break; case 3: case 4: // Teleport case 7: // Assaulter case 8: // Assassinate case 9: // Rush x = packet.get<int16_t>(); y = packet.get<int16_t>(); packet.skipBytes(4); stance = packet.get<int8_t>(); break; default: std::cout << "New type of movement: 0x" << std::hex << (int16_t) type << std::endl; break; } } Pos pos(x, y); life->setPos(pos); life->setFh(foothold); life->setStance(stance); return pos; }