diff --git a/config.yaml b/config.yaml index f46841921b3..d758e5f0c84 100644 --- a/config.yaml +++ b/config.yaml @@ -362,6 +362,7 @@ server: #Quest Configuration USE_QUEST_RATE: false #Exp/Meso gained by quests uses fixed server exp/meso rate times quest rate as multiplier, instead of player rates. + QUEST_MOB_COUNT_MODIFIER: 1 #Multiplier for how many 1 monster kill will count toward monster kill quests #Quest Points Configuration QUEST_POINT_REPEATABLE_INTERVAL: 25 #Minimum interval between repeatable quest completions for quest points to be awarded. diff --git a/src/main/java/client/QuestStatus.java b/src/main/java/client/QuestStatus.java index 48ad279435d..a75f6dbf5a9 100644 --- a/src/main/java/client/QuestStatus.java +++ b/src/main/java/client/QuestStatus.java @@ -30,6 +30,8 @@ import java.util.List; import java.util.Map; +import config.YamlConfig; + /** * @author Matze */ @@ -60,6 +62,7 @@ public static Status getById(int id) { } private final short questID; + private final Quest quest; private Status status; //private boolean updated; //maybe this can be of use for someone? private final Map progress = new LinkedHashMap<>(); @@ -70,6 +73,7 @@ public static Status getById(int id) { private String customData; public QuestStatus(Quest quest, Status status) { + this.quest = quest; this.questID = quest.getId(); this.setStatus(status); this.completionTime = System.currentTimeMillis(); @@ -81,6 +85,7 @@ public QuestStatus(Quest quest, Status status) { } public QuestStatus(Quest quest, Status status, int npc) { + this.quest = quest; this.questID = quest.getId(); this.setStatus(status); this.setNpc(npc); @@ -93,7 +98,7 @@ public QuestStatus(Quest quest, Status status, int npc) { } public Quest getQuest() { - return Quest.getInstance(questID); + return this.quest; } public short getQuestID() { @@ -131,7 +136,7 @@ public final void setNpc(int npc) { } private void registerMobs() { - for (int i : Quest.getInstance(questID).getRelevantMobs()) { + for (int i : this.quest.getRelevantMobs()) { progress.put(i, "000"); } //this.setUpdated(); @@ -161,13 +166,19 @@ public boolean progress(int id) { } int current = Integer.parseInt(currentStr); - if (current >= this.getQuest().getMobAmountNeeded(id)) { - return false; + int maxNeeded = this.getQuest().getMobAmountNeeded(id); + + int multiplier = YamlConfig.config.server.QUEST_MOB_COUNT_MODIFIER; + + int newCount = current + multiplier; + if (newCount > maxNeeded) { + newCount = maxNeeded; + } else if (newCount < 0) { + newCount = 0; } - String str = StringUtil.getLeftPaddedStr(Integer.toString(++current), '0', 3); + String str = StringUtil.getLeftPaddedStr(Integer.toString(newCount), '0', 3); progress.put(id, str); - //this.setUpdated(); return true; } diff --git a/src/main/java/config/ServerConfig.java b/src/main/java/config/ServerConfig.java index 036dae258d7..9f4b640bb7b 100644 --- a/src/main/java/config/ServerConfig.java +++ b/src/main/java/config/ServerConfig.java @@ -210,6 +210,7 @@ public class ServerConfig { //Quest Configuration public boolean USE_QUEST_RATE; + public int QUEST_MOB_COUNT_MODIFIER; //Quest Points Configuration public int QUEST_POINT_REPEATABLE_INTERVAL; diff --git a/src/main/java/provider/wz/WZFiles.java b/src/main/java/provider/wz/WZFiles.java index f1621cab293..fe104906255 100644 --- a/src/main/java/provider/wz/WZFiles.java +++ b/src/main/java/provider/wz/WZFiles.java @@ -18,8 +18,6 @@ public enum WZFiles { SOUND("Sound"), UI("UI"); - public static final String DIRECTORY = getWzDirectory(); - private final String fileName; WZFiles(String name) { @@ -27,7 +25,7 @@ public enum WZFiles { } public Path getFile() { - return Path.of(DIRECTORY, fileName); + return Path.of(getWzDirectory(), fileName); } public String getFilePath() { diff --git a/src/test/java/client/QuestStatusTest.java b/src/test/java/client/QuestStatusTest.java new file mode 100644 index 00000000000..6d65729cca8 --- /dev/null +++ b/src/test/java/client/QuestStatusTest.java @@ -0,0 +1,106 @@ +package client; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import server.quest.Quest; +import tools.StringUtil; + +import java.lang.reflect.Field; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +public class QuestStatusTest { + private QuestStatus questStatus; + private Quest mockQuest; + private static final int MOB_ID = 100; + private static final int MAX_MOB_AMOUNT = 10; + + @BeforeEach + void setUp() throws Exception { + mockQuest = mock(Quest.class); + when(mockQuest.getId()).thenReturn((short) 1); + when(mockQuest.getMobAmountNeeded(MOB_ID)).thenReturn(MAX_MOB_AMOUNT); + + questStatus = new QuestStatus(mockQuest, QuestStatus.Status.STARTED); + questStatus.setProgress(MOB_ID, "000"); // Set all tests to 0 to start + + setQuestMobCountModifier(1); // Default multiplier + } + + private void setQuestMobCountModifier(int value) throws Exception { + Field field = Class.forName("config.YamlConfig").getDeclaredField("config"); + field.setAccessible(true); + Object config = field.get(null); + Field serverField = config.getClass().getDeclaredField("server"); + serverField.setAccessible(true); + Object server = serverField.get(config); + Field modifierField = server.getClass().getDeclaredField("QUEST_MOB_COUNT_MODIFIER"); + modifierField.setAccessible(true); + modifierField.set(server, value); + } + + private void setQuestCount(int value) { + questStatus.setProgress(MOB_ID, StringUtil.getLeftPaddedStr(Integer.toString(value), '0', 3)); + } + + @Test + void testProgressDefaultIncrementSuccessfully() { + setQuestCount(5); + boolean result = questStatus.progress(MOB_ID); + assertTrue(result); + assertEquals("006", questStatus.getProgress(MOB_ID)); + } + + @Test + void testProgressReturnsFalseForUnknownMobId() { + boolean result = questStatus.progress(999); + assertFalse(result); + assertEquals("000", questStatus.getProgress(MOB_ID)); + } + + @Test + void testProgressDoesNotExceedMax() throws Exception { + questStatus.setProgress(MOB_ID, StringUtil.getLeftPaddedStr("8", '0', 3)); + setQuestMobCountModifier(9999); + + boolean result = questStatus.progress(MOB_ID); + assertTrue(result); + + assertEquals("010", questStatus.getProgress(MOB_ID)); + } + + @Test + void testProgressWithZeroMultiplier() throws Exception { + setQuestCount(5); + setQuestMobCountModifier(0); + + boolean result = questStatus.progress(MOB_ID); + + assertTrue(result); + assertEquals("005", questStatus.getProgress(MOB_ID)); + } + + @Test + void testProgressWithNegativeMultiplier() throws Exception { + setQuestCount(0); + setQuestMobCountModifier(-1); + + boolean result = questStatus.progress(MOB_ID); + + assertTrue(result); + assertEquals("000", questStatus.getProgress(MOB_ID)); + } + + // Would be surprised if anyone ever does this but it's there + @Test + void testProgressedQuestWithNegativeMultiplier() throws Exception { + setQuestCount(5); + setQuestMobCountModifier(-1); + + boolean result = questStatus.progress(MOB_ID); + + assertTrue(result); + assertEquals("004", questStatus.getProgress(MOB_ID)); + } +} \ No newline at end of file diff --git a/src/test/java/server/life/MobSkillFactoryTest.java b/src/test/java/server/life/MobSkillFactoryTest.java index 078a9c60351..e1bb75767e1 100644 --- a/src/test/java/server/life/MobSkillFactoryTest.java +++ b/src/test/java/server/life/MobSkillFactoryTest.java @@ -1,5 +1,6 @@ package server.life; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -18,16 +19,20 @@ class MobSkillFactoryTest { @TempDir - private Path wzPath; + static Path wzPath; + + @BeforeAll + static void setWzPath() { + System.setProperty("wz-path", "%s/wz".formatted(wzPath.toString())); + writeTestFileToTempDir(); + } @BeforeEach - void setWzPath() { + void setUp() { MockitoAnnotations.openMocks(this); - writeTestFileToTempDir(); - System.setProperty("wz-path", "%s/wz".formatted(wzPath.toString())); } - private void writeTestFileToTempDir() { + private static void writeTestFileToTempDir() { try { String testFileContents = readTestFileContents(); writeTempDirFile(testFileContents); @@ -36,15 +41,15 @@ private void writeTestFileToTempDir() { } } - private String readTestFileContents() throws IOException { - return new String(getClass() + private static String readTestFileContents() throws IOException { + return new String(MobSkillFactoryTest.class .getClassLoader() .getResourceAsStream("MobSkill-test.img.xml") .readAllBytes() ); } - private void writeTempDirFile(String fileContents) throws IOException { + private static void writeTempDirFile(String fileContents) throws IOException { Path tempDirDirectory = wzPath.resolve("wz/Skill.wz"); Files.createDirectories(tempDirDirectory); Path tempDirFile = Files.createFile(tempDirDirectory.resolve("MobSkill.img.xml"));