Fix mob using attack with no diseaseSkill causing errors
This commit is contained in:
@@ -7326,7 +7326,8 @@ public class Character extends AbstractCharacterObject {
|
||||
final int skilllv = rs.getInt("mobskilllv");
|
||||
final long length = rs.getInt("length");
|
||||
|
||||
MobSkill ms = MobSkillFactory.getMobSkill(MobSkillType.from(skillid), skilllv);
|
||||
MobSkillType type = MobSkillType.from(skillid).orElseThrow();
|
||||
MobSkill ms = MobSkillFactory.getMobSkillOrThrow(type, skilllv);
|
||||
loadedDiseases.put(disease, new Pair<>(length, ms));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import server.life.MobSkillFactory;
|
||||
import server.life.MobSkillType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
public class MobSkillCommand extends Command {
|
||||
{
|
||||
@@ -22,13 +23,18 @@ public class MobSkillCommand extends Command {
|
||||
|
||||
String skillId = params[0];
|
||||
String skillLevel = params[1];
|
||||
MobSkillType type = MobSkillType.from(Integer.parseInt(skillId));
|
||||
MobSkill mobSkill = MobSkillFactory.getMobSkill(type, Integer.parseInt(skillLevel));
|
||||
if (mobSkill == null) {
|
||||
throw new IllegalArgumentException("Mob skill not found. Id: %s, level: %s".formatted(skillId, skillLevel));
|
||||
Optional<MobSkillType> possibleType = MobSkillType.from(Integer.parseInt(skillId));
|
||||
Optional<MobSkill> possibleSkill = possibleType.map(
|
||||
type -> MobSkillFactory.getMobSkillOrThrow(type, Integer.parseInt(skillLevel))
|
||||
);
|
||||
if (possibleSkill.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Character chr = client.getPlayer();
|
||||
chr.getMap().getAllMonsters().forEach(monster -> mobSkill.applyEffect(chr, monster, false, Collections.emptyList()));
|
||||
MobSkill mobSkill = possibleSkill.get();
|
||||
chr.getMap().getAllMonsters().forEach(
|
||||
monster -> mobSkill.applyEffect(chr, monster, false, Collections.emptyList())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import server.maps.MapObject;
|
||||
import server.maps.MapObjectType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
public class DebuffCommand extends Command {
|
||||
{
|
||||
@@ -49,7 +50,7 @@ public class DebuffCommand extends Command {
|
||||
}
|
||||
|
||||
Disease disease = null;
|
||||
MobSkill skill = null;
|
||||
Optional<MobSkill> skill = Optional.empty();
|
||||
|
||||
switch (params[0].toUpperCase()) {
|
||||
case "SLOW" -> {
|
||||
@@ -94,7 +95,7 @@ public class DebuffCommand extends Command {
|
||||
}
|
||||
}
|
||||
|
||||
if (disease == null) {
|
||||
if (disease == null || skill.isEmpty()) {
|
||||
player.yellowMessage("Syntax: !debuff SLOW|SEDUCE|ZOMBIFY|CONFUSE|STUN|POISON|SEAL|DARKNESS|WEAKEN|CURSE");
|
||||
return;
|
||||
}
|
||||
@@ -103,7 +104,7 @@ public class DebuffCommand extends Command {
|
||||
Character chr = (Character) mmo;
|
||||
|
||||
if (chr.getId() != player.getId()) {
|
||||
chr.giveDebuff(disease, skill);
|
||||
chr.giveDebuff(disease, skill.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +492,7 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler {
|
||||
if (monster.isBuffed(MonsterStatus.WEAPON_REFLECT) && !attack.magic) {
|
||||
for (MobSkillId msId : monster.getSkills()) {
|
||||
if (msId.type() == MobSkillType.PHYSICAL_AND_MAGIC_COUNTER) {
|
||||
MobSkill toUse = MobSkillFactory.getMobSkill(MobSkillType.PHYSICAL_AND_MAGIC_COUNTER, msId.level());
|
||||
MobSkill toUse = MobSkillFactory.getMobSkillOrThrow(MobSkillType.PHYSICAL_AND_MAGIC_COUNTER, msId.level());
|
||||
player.addHP(-toUse.getX());
|
||||
map.broadcastMessage(player, PacketCreator.damagePlayer(0, monster.getId(), player.getId(), toUse.getX(), 0, 0, false, 0, true, monster.getObjectId(), 0, 0), true);
|
||||
}
|
||||
@@ -501,7 +501,7 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler {
|
||||
if (monster.isBuffed(MonsterStatus.MAGIC_REFLECT) && attack.magic) {
|
||||
for (MobSkillId msId : monster.getSkills()) {
|
||||
if (msId.type() == MobSkillType.PHYSICAL_AND_MAGIC_COUNTER) {
|
||||
MobSkill toUse = MobSkillFactory.getMobSkill(MobSkillType.PHYSICAL_AND_MAGIC_COUNTER, msId.level());
|
||||
MobSkill toUse = MobSkillFactory.getMobSkillOrThrow(MobSkillType.PHYSICAL_AND_MAGIC_COUNTER, msId.level());
|
||||
player.addHP(-toUse.getY());
|
||||
map.broadcastMessage(player, PacketCreator.damagePlayer(0, monster.getId(), player.getId(), toUse.getY(), 0, 0, false, 0, true, monster.getObjectId(), 0, 0), true);
|
||||
}
|
||||
|
||||
@@ -79,19 +79,16 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
boolean isAttack = inRangeInclusive(rawActivity, 24, 41);
|
||||
boolean isSkill = inRangeInclusive(rawActivity, 42, 59);
|
||||
|
||||
int useSkillId = 0, useSkillLevel = 0;
|
||||
|
||||
MobSkill nextUse = null;
|
||||
int nextSkillId = 0, nextSkillLevel = 0;
|
||||
|
||||
boolean nextMovementCouldBeSkill = !(isSkill || (pNibbles != 0));
|
||||
int useSkillId = 0;
|
||||
int useSkillLevel = 0;
|
||||
|
||||
if (isSkill) {
|
||||
useSkillId = skillId;
|
||||
useSkillLevel = skillLv;
|
||||
|
||||
if (monster.hasSkill(useSkillId, useSkillLevel)) {
|
||||
MobSkill toUse = MobSkillFactory.getMobSkill(MobSkillType.from(useSkillId), useSkillLevel);
|
||||
MobSkillType mobSkillType = MobSkillType.from(useSkillId).orElseThrow();
|
||||
MobSkill toUse = MobSkillFactory.getMobSkillOrThrow(mobSkillType, useSkillLevel);
|
||||
|
||||
if (monster.canUseSkill(toUse, true)) {
|
||||
int animationTime = MonsterInformationProvider.getInstance().getMobSkillAnimationTime(toUse);
|
||||
@@ -112,12 +109,16 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
}
|
||||
}
|
||||
|
||||
boolean nextMovementCouldBeSkill = !(isSkill || (pNibbles != 0));
|
||||
MobSkill nextUse = null;
|
||||
int nextSkillId = 0;
|
||||
int nextSkillLevel = 0;
|
||||
int mobMp = monster.getMp();
|
||||
if (nextMovementCouldBeSkill && monster.hasAnySkill()) {
|
||||
MobSkillId skillToUse = monster.getRandomSkill();
|
||||
nextSkillId = skillToUse.type().getId();
|
||||
nextSkillLevel = skillToUse.level();
|
||||
nextUse = MobSkillFactory.getMobSkill(skillToUse.type(), skillToUse.level());
|
||||
nextUse = MobSkillFactory.getMobSkillOrThrow(skillToUse.type(), skillToUse.level());
|
||||
|
||||
if (!(nextUse != null && monster.canUseSkill(nextUse, false) && nextUse.getHP() >= (int) (((float) monster.getHp() / monster.getMaxHp()) * 100) && mobMp >= nextUse.getMpCon())) {
|
||||
// thanks OishiiKawaiiDesu for noticing mobs trying to cast skills they are not supposed to be able
|
||||
|
||||
@@ -49,6 +49,7 @@ import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class TakeDamageHandler extends AbstractPacketHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(TakeDamageHandler.class);
|
||||
@@ -151,9 +152,11 @@ public final class TakeDamageHandler extends AbstractPacketHandler {
|
||||
is_deadly = true;
|
||||
}
|
||||
mpattack += attackInfo.getMpBurn();
|
||||
MobSkill mobSkill = MobSkillFactory.getMobSkill(MobSkillType.from(attackInfo.getDiseaseSkill()), attackInfo.getDiseaseLevel());
|
||||
if (mobSkill != null && damage > 0) {
|
||||
mobSkill.applyEffect(chr, attacker, false, banishPlayers);
|
||||
|
||||
Optional<MobSkillType> possibleType = MobSkillType.from(attackInfo.getDiseaseSkill());
|
||||
Optional<MobSkill> possibleMobSkill = possibleType.map(type -> MobSkillFactory.getMobSkillOrThrow(type, attackInfo.getDiseaseLevel()));
|
||||
if (possibleMobSkill.isPresent() && damage > 0) {
|
||||
possibleMobSkill.get().applyEffect(chr, attacker, false, banishPlayers);
|
||||
}
|
||||
|
||||
attacker.setMp(attacker.getMp() - attackInfo.getMpCon());
|
||||
|
||||
@@ -1195,12 +1195,12 @@ public class AbstractPlayerInteraction {
|
||||
}
|
||||
|
||||
private void applySealSkill(Monster monster) {
|
||||
MobSkill sealSkill = MobSkillFactory.getMobSkill(MobSkillType.SEAL_SKILL, 1);
|
||||
MobSkill sealSkill = MobSkillFactory.getMobSkillOrThrow(MobSkillType.SEAL_SKILL, 1);
|
||||
sealSkill.applyEffect(monster);
|
||||
}
|
||||
|
||||
private void applyReduceAvoid(Monster monster) {
|
||||
MobSkill reduceAvoidSkill = MobSkillFactory.getMobSkill(MobSkillType.EVA, 2);
|
||||
MobSkill reduceAvoidSkill = MobSkillFactory.getMobSkillOrThrow(MobSkillType.EVA, 2);
|
||||
reduceAvoidSkill.applyEffect(monster);
|
||||
}
|
||||
|
||||
|
||||
@@ -1046,7 +1046,7 @@ public class StatEffect {
|
||||
if (dis == null) {
|
||||
chrApp.dispel();
|
||||
} else {
|
||||
MobSkill mobSkill = MobSkillFactory.getMobSkill(dis.getMobSkillType(), skill.level());
|
||||
MobSkill mobSkill = MobSkillFactory.getMobSkillOrThrow(dis.getMobSkillType(), skill.level());
|
||||
chrApp.giveDebuff(dis, mobSkill);
|
||||
}
|
||||
}
|
||||
@@ -1059,7 +1059,7 @@ public class StatEffect {
|
||||
if (dis == null) {
|
||||
chrApp.dispel();
|
||||
} else {
|
||||
MobSkill mobSkill = MobSkillFactory.getMobSkill(dis.getMobSkillType(), skill.level());
|
||||
MobSkill mobSkill = MobSkillFactory.getMobSkillOrThrow(dis.getMobSkillType(), skill.level());
|
||||
chrApp.giveDebuff(dis, mobSkill);
|
||||
}
|
||||
}
|
||||
@@ -1070,8 +1070,8 @@ public class StatEffect {
|
||||
applyfrom.dispelDebuff(debuff);
|
||||
}
|
||||
} else if (mobSkill > 0 && mobSkillLevel > 0) {
|
||||
var mobSkillType = MobSkillType.from(mobSkill);
|
||||
MobSkill ms = MobSkillFactory.getMobSkill(mobSkillType, mobSkillLevel);
|
||||
MobSkillType mobSkillType = MobSkillType.from(mobSkill).orElseThrow();
|
||||
MobSkill ms = MobSkillFactory.getMobSkillOrThrow(mobSkillType, mobSkillLevel);
|
||||
Disease dis = Disease.getBySkill(mobSkillType);
|
||||
|
||||
if (target > 0) {
|
||||
|
||||
@@ -192,7 +192,7 @@ public class LifeFactory {
|
||||
while (monsterSkillInfoData.getChildByPath(Integer.toString(i)) != null) {
|
||||
int skillId = DataTool.getInt(i + "/skill", monsterSkillInfoData, 0);
|
||||
int skillLv = DataTool.getInt(i + "/level", monsterSkillInfoData, 0);
|
||||
MobSkillType type = MobSkillType.from(skillId);
|
||||
MobSkillType type = MobSkillType.from(skillId).orElseThrow();
|
||||
skills.add(new MobSkillId(type, skillLv));
|
||||
|
||||
Data monsterSkillData = monsterData.getChildByPath("skill" + (i + 1));
|
||||
@@ -202,7 +202,7 @@ public class LifeFactory {
|
||||
animationTime += DataTool.getIntConvert("delay", effectEntry, 0);
|
||||
}
|
||||
|
||||
MobSkill skill = MobSkillFactory.getMobSkill(type, skillLv);
|
||||
MobSkill skill = MobSkillFactory.getMobSkillOrThrow(type, skillLv);
|
||||
mi.setMobSkillAnimationTime(skill, animationTime);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,20 +47,24 @@ public class MobSkillFactory {
|
||||
private static final Lock readLock = readWriteLock.readLock();
|
||||
private static final Lock writeLock = readWriteLock.writeLock();
|
||||
|
||||
public static MobSkill getMobSkill(final MobSkillType type, final int level) {
|
||||
public static MobSkill getMobSkillOrThrow(MobSkillType type, int level) {
|
||||
return getMobSkill(type, level).orElseThrow(
|
||||
() -> new IllegalArgumentException("No MobSkill exists for type %s, level %d".formatted(type, level))
|
||||
);
|
||||
}
|
||||
|
||||
public static Optional<MobSkill> getMobSkill(final MobSkillType type, final int level) {
|
||||
readLock.lock();
|
||||
try {
|
||||
MobSkill ms = mobSkills.get(createKey(type, level));
|
||||
if (ms != null) {
|
||||
return ms;
|
||||
return Optional.of(ms);
|
||||
}
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
return loadMobSkill(type, level).orElseThrow(
|
||||
() -> new IllegalArgumentException("No MobSkill exists for type %s, level %d".formatted(type, level))
|
||||
);
|
||||
return loadMobSkill(type, level);
|
||||
}
|
||||
|
||||
private static Optional<MobSkill> loadMobSkill(final MobSkillType type, final int level) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package server.life;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
public enum MobSkillType {
|
||||
ATTACK_UP(100),
|
||||
@@ -51,11 +52,18 @@ public enum MobSkillType {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static MobSkillType from(int id) {
|
||||
public static Optional<MobSkillType> from(int id) {
|
||||
if (isOutOfIdRange(id)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Arrays.stream(values())
|
||||
.filter(type -> type.getId() == id)
|
||||
.findFirst()
|
||||
.orElseThrow(IllegalArgumentException::new);
|
||||
.findAny();
|
||||
}
|
||||
|
||||
private static boolean isOutOfIdRange(int id) {
|
||||
return id < 100 || id > 200;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
|
||||
@@ -47,7 +47,7 @@ public class CarnivalFactory {
|
||||
int mobSkillId = DataTool.getInt("mobSkillID", z, 0);
|
||||
MobSkillType mobSkillType = null;
|
||||
if (mobSkillId != 0) {
|
||||
mobSkillType = MobSkillType.from(mobSkillId);
|
||||
mobSkillType = MobSkillType.from(mobSkillId).orElseThrow();
|
||||
}
|
||||
int level = DataTool.getInt("level", z, 0);
|
||||
boolean isMultiTarget = DataTool.getInt("target", z, 1) > 1;
|
||||
@@ -63,7 +63,7 @@ public class CarnivalFactory {
|
||||
for (Data z : dataRoot.getData("MCGuardian.img")) {
|
||||
int spendCp = DataTool.getInt("spendCP", z, 0);
|
||||
int mobSkillId = DataTool.getInt("mobSkillID", z, 0);
|
||||
MobSkillType mobSkillType = MobSkillType.from(mobSkillId);
|
||||
MobSkillType mobSkillType = MobSkillType.from(mobSkillId).orElseThrow();
|
||||
int level = DataTool.getInt("level", z, 0);
|
||||
guardians.put(Integer.parseInt(z.getName()), new MCSkill(spendCp, mobSkillType, level, true));
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public class CarnivalFactory {
|
||||
|
||||
public record MCSkill(int cpLoss, MobSkillType mobSkillType, int level, boolean targetsAll) {
|
||||
public MobSkill getSkill() {
|
||||
return MobSkillFactory.getMobSkill(mobSkillType, level);
|
||||
return MobSkillFactory.getMobSkillOrThrow(mobSkillType, level);
|
||||
}
|
||||
|
||||
public Disease getDisease() {
|
||||
|
||||
@@ -111,7 +111,7 @@ public class MonsterStatFetcher {
|
||||
Set<MobSkillId> skills = new HashSet<>();
|
||||
while (monsterSkillData.getChildByPath(Integer.toString(i)) != null) {
|
||||
int skillId = DataTool.getInt(i + "/skill", monsterSkillData, 0);
|
||||
MobSkillType type = MobSkillType.from(skillId);
|
||||
MobSkillType type = MobSkillType.from(skillId).orElseThrow();
|
||||
int skillLevel = DataTool.getInt(i + "/level", monsterSkillData, 0);
|
||||
skills.add(new MobSkillId(type, skillLevel));
|
||||
i++;
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.mockito.MockitoAnnotations;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@@ -49,9 +50,10 @@ class MobSkillFactoryTest {
|
||||
|
||||
@Test
|
||||
void shouldLoadExistingMobSkill() {
|
||||
MobSkill mobSkill = MobSkillFactory.getMobSkill(MobSkillType.ATTACK_UP, 1);
|
||||
Optional<MobSkill> possibleSkill = MobSkillFactory.getMobSkill(MobSkillType.ATTACK_UP, 1);
|
||||
|
||||
assertNotNull(mobSkill);
|
||||
assertTrue(possibleSkill.isPresent());
|
||||
MobSkill mobSkill = possibleSkill.get();
|
||||
assertAll("MobSkill",
|
||||
() -> assertEquals(115, mobSkill.getX()),
|
||||
() -> assertEquals(5, mobSkill.getMpCon()),
|
||||
@@ -62,7 +64,7 @@ class MobSkillFactoryTest {
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionOnNonExisting() {
|
||||
assertThrows(IllegalArgumentException.class, () -> MobSkillFactory.getMobSkill(MobSkillType.DEFENSE_UP, 1));
|
||||
assertThrows(IllegalArgumentException.class, () -> MobSkillFactory.getMobSkillOrThrow(MobSkillType.DEFENSE_UP, 1));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user