Example #1
0
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());
}