Fix mob using attack with no diseaseSkill causing errors

This commit is contained in:
P0nk
2022-09-12 20:31:38 +02:00
parent 0c6548a36d
commit d31f4806fc
14 changed files with 71 additions and 45 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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

View File

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

View File

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

View File

@@ -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) {

View File

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

View File

@@ -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) {

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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++;

View File

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