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()); }