diff --git a/core/src/main/java/com/gdx/game/quest/FetchQuestTaskHandler.java b/core/src/main/java/com/gdx/game/quest/FetchQuestTaskHandler.java new file mode 100644 index 00000000..6cc4829b --- /dev/null +++ b/core/src/main/java/com/gdx/game/quest/FetchQuestTaskHandler.java @@ -0,0 +1,63 @@ +package com.gdx.game.quest; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import com.gdx.game.entities.Entity; +import com.gdx.game.entities.EntityConfig; +import com.gdx.game.map.MapManager; +import com.gdx.game.profile.ProfileManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FetchQuestTaskHandler implements QuestTaskHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(QuestGraph.class); + + @Override + public void handleUpdate(QuestTask questTask, String questID) { + String taskConfig = questTask.getPropertyValue(QuestTask.QuestTaskPropertyType.TARGET_TYPE.toString()); + if (taskConfig == null || taskConfig.isEmpty()) + return; + EntityConfig config = Entity.getEntityConfig(taskConfig); + + Array questItemPositions = ProfileManager.getInstance().getProperty(config.getEntityID(), Array.class); + //Case where all the items have been picked up + if (questItemPositions != null && questItemPositions.size == 0) { + questTask.setTaskComplete(); + LOGGER.debug("TASK : {} is complete of Quest: {}", questTask.getId(), questID); + LOGGER.debug("INFO : {}", QuestTask.QuestTaskPropertyType.TARGET_TYPE); + } + } + + @Override + public void handleInit(MapManager mapManager, QuestTask questTask, String questID) { + + String taskConfig = questTask.getPropertyValue(QuestTask.QuestTaskPropertyType.TARGET_TYPE.toString()); + if (taskConfig == null || taskConfig.isEmpty()) + return; + + Array questEntities = new Array<>(); + Array positions = mapManager.getQuestItemSpawnPositions(questID, questTask.getId()); + EntityConfig config = Entity.getEntityConfig(taskConfig); + Array questItemPositions = ProfileManager.getInstance().getProperty(config.getEntityID(), Array.class); + + if (questItemPositions == null) { + questItemPositions = new Array<>(positions); + addQuestEntities(config, positions, questID, questEntities); + } else { + addQuestEntities(config, positions, questID, questEntities); + } + + mapManager.addMapQuestEntities(questEntities); + ProfileManager.getInstance().setProperty(config.getEntityID(), questItemPositions); + } + + private void addQuestEntities(EntityConfig config, Array positions, String questID, Array questEntities) { + for (Vector2 position : positions) { + Entity entity = Entity.initEntity(config, position); + entity.getEntityConfig().setCurrentQuestID(questID); + questEntities.add(entity); + } + } + +} \ No newline at end of file diff --git a/core/src/main/java/com/gdx/game/quest/QuestGraph.java b/core/src/main/java/com/gdx/game/quest/QuestGraph.java index 26287be7..b4a8ea9e 100644 --- a/core/src/main/java/com/gdx/game/quest/QuestGraph.java +++ b/core/src/main/java/com/gdx/game/quest/QuestGraph.java @@ -1,31 +1,31 @@ package com.gdx.game.quest; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.Json; -import com.gdx.game.entities.Entity; -import com.gdx.game.entities.EntityConfig; -import com.gdx.game.map.MapManager; -import com.gdx.game.profile.ProfileManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Collections; import java.util.Enumeration; import java.util.Hashtable; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; import java.util.Set; +import java.util.HashSet; + +import com.badlogic.gdx.utils.Json; +import com.gdx.game.map.MapFactory; +import com.gdx.game.map.MapManager; public class QuestGraph { - private static final Logger LOGGER = LoggerFactory.getLogger(QuestGraph.class); + private Hashtable questTasks = new Hashtable<>(); + + private Hashtable> questTaskDependencies = new Hashtable<>(); - private Hashtable questTasks; - private Hashtable> questTaskDependencies; private String questTitle; + private String questID; + private boolean isQuestComplete; + private int goldReward; + private int xpReward; public int getGoldReward() { @@ -79,10 +79,6 @@ public boolean areAllTasksComplete() { } public void setTasks(Hashtable questTasks) { - if (questTasks.size() < 0) { - throw new IllegalArgumentException("Can't have a negative amount of conversations"); - } - this.questTasks = questTasks; this.questTaskDependencies = new Hashtable<>(questTasks.size()); @@ -107,59 +103,35 @@ public boolean isValid(String taskID) { } public boolean isReachable(String sourceID, String sinkID) { - if (!isValid(sourceID) || !isValid(sinkID)) { - return false; - } - if (questTasks.get(sourceID) == null) { - return false; - } + Set reachableNodes = new HashSet<>(); + return isReachable(sourceID, sinkID, reachableNodes); + } - ArrayList list = questTaskDependencies.get(sourceID); - if (list == null) { - return false; - } - for(QuestTaskDependency dependency: list) { - if (dependency.getSourceId().equalsIgnoreCase(sourceID) && dependency.getDestinationId().equalsIgnoreCase(sinkID)) { + private boolean isReachable(String sourceId, String targetId, Set reachableNodes) { + if (sourceId.equals(targetId)) + return true; + + reachableNodes.add(sourceId); + List dependencies = questTaskDependencies.computeIfAbsent(sourceId, k -> new ArrayList<>()); + for (QuestTaskDependency dep : dependencies) { + String destinationId = dep.getDestinationId(); + if (!reachableNodes.contains(destinationId) && isReachable(destinationId, targetId, reachableNodes)) return true; - } } + return false; } public QuestTask getQuestTaskByID(String id) { - if (!isValid(id)) { - //System.out.println("Id " + id + " is not valid!"); - return null; - } - return questTasks.get(id); + return (isValid(id)) ? questTasks.get(id) : null; } public void addDependency(QuestTaskDependency questTaskDependency) { - ArrayList list = questTaskDependencies.get(questTaskDependency.getSourceId()); - if (list == null) { - return; - } - - //Will not add if creates cycles - if (doesCycleExist(questTaskDependency)) { - //System.out.println("Cycle exists! Not adding"); - return; - } - + String sourceId = questTaskDependency.getSourceId(); + ArrayList list = questTaskDependencies.computeIfAbsent(sourceId, k -> new ArrayList<>()); list.add(questTaskDependency); } - public boolean doesCycleExist(QuestTaskDependency questTaskDep) { - Set keys = questTasks.keySet(); - for(String id: keys) { - if (doesQuestTaskHaveDependencies(id) && questTaskDep.getDestinationId().equalsIgnoreCase(id)) { - //System.out.println("ID: " + id + " destID: " + questTaskDep.getDestinationId()); - return true; - } - } - return false; - } - public boolean doesQuestTaskHaveDependencies(String id) { QuestTask task = getQuestTaskByID(id); if (task == null) { @@ -174,7 +146,7 @@ public boolean updateQuestForReturn() { ArrayList tasks = getAllQuestTasks(); QuestTask readyTask = null; - //First, see if all tasks are available, meaning no blocking dependencies + // First, see if all tasks are available, meaning no blocking dependencies for(QuestTask task : tasks) { if (!isQuestTaskAvailable(task.getId())) { return false; @@ -199,8 +171,8 @@ public boolean isQuestTaskAvailable(String id) { if (task == null) { return false; } - ArrayList list = questTaskDependencies.get(id); + List list = questTaskDependencies.get(id); for(QuestTaskDependency dep: list) { QuestTask depTask = getQuestTaskByID(dep.getDestinationId()); if (depTask == null || depTask.isTaskComplete()) { @@ -225,53 +197,21 @@ public void update(MapManager mapMgr) { ArrayList allQuestTasks = getAllQuestTasks(); for(QuestTask questTask: allQuestTasks) { - if (questTask.isTaskComplete()) { - continue; - } + if (isInvalidQuestTask(questTask, mapMgr)) continue; - //We first want to make sure the task is available and is relevant to current location - if (!isQuestTaskAvailable(questTask.getId())) { - continue; - } - - String taskLocation = questTask.getPropertyValue(QuestTask.QuestTaskPropertyType.TARGET_LOCATION.toString()); - if (taskLocation == null || taskLocation.isEmpty() || !taskLocation.equalsIgnoreCase(mapMgr.getCurrentMapType().toString())) { - continue; - } + // Determine the handler based on quest type + QuestTaskHandler handler = getHandlerForQuestType(questTask.getQuestType()); + if (handler != null) + handler.handleUpdate(questTask, questID); + } + } - switch(questTask.getQuestType()) { - case FETCH: - String taskConfig = questTask.getPropertyValue(QuestTask.QuestTaskPropertyType.TARGET_TYPE.toString()); - if (taskConfig == null || taskConfig.isEmpty()) { - break; - } - EntityConfig config = Entity.getEntityConfig(taskConfig); - - Array questItemPositions = ProfileManager.getInstance().getProperty(config.getEntityID(), Array.class); - if (questItemPositions == null) { - break; - } - - //Case where all the items have been picked up - if (questItemPositions.size == 0) { - questTask.setTaskComplete(); - LOGGER.debug("TASK : {} is complete of Quest: {}", questTask.getId(), questID); - LOGGER.debug("INFO : {}", QuestTask.QuestTaskPropertyType.TARGET_TYPE); - } - break; - case KILL: - break; - case DELIVERY: - break; - case GUARD: - break; - case ESCORT: - break; - case RETURN: - break; - case DISCOVER: - break; - } + private QuestTaskHandler getHandlerForQuestType(QuestTask.QuestType questType) { + switch (questType) { + case FETCH: + return new FetchQuestTaskHandler(); + default: + return null; } } @@ -279,65 +219,24 @@ public void init(MapManager mapMgr) { ArrayList allQuestTasks = getAllQuestTasks(); for(QuestTask questTask: allQuestTasks) { - if (questTask.isTaskComplete()) { - continue; - } + if (isInvalidQuestTask(questTask, mapMgr)) continue; - //We first want to make sure the task is available and is relevant to current location - if (!isQuestTaskAvailable(questTask.getId())) { - continue; - } + // Determine the handler based on quest type + QuestTaskHandler handler = getHandlerForQuestType(questTask.getQuestType()); + if (handler != null) + handler.handleInit(mapMgr, questTask, questID); + } + } - String taskLocation = questTask.getPropertyValue(QuestTask.QuestTaskPropertyType.TARGET_LOCATION.toString()); - if (taskLocation == null || taskLocation.isEmpty() || !taskLocation.equalsIgnoreCase(mapMgr.getCurrentMapType().toString())) { - continue; - } + private boolean isInvalidQuestTask(QuestTask questTask, MapManager mapManager) { + if (questTask.isTaskComplete() || !isQuestTaskAvailable(questTask.getId())) + return true; - switch(questTask.getQuestType()) { - case FETCH: - Array questEntities = new Array<>(); - Array positions = mapMgr.getQuestItemSpawnPositions(questID, questTask.getId()); - String taskConfig = questTask.getPropertyValue(QuestTask.QuestTaskPropertyType.TARGET_TYPE.toString()); - if (taskConfig == null || taskConfig.isEmpty()) { - break; - } - EntityConfig config = Entity.getEntityConfig(taskConfig); - - Array questItemPositions = ProfileManager.getInstance().getProperty(config.getEntityID(), Array.class); - - if (questItemPositions == null) { - questItemPositions = new Array<>(); - for(Vector2 position: positions) { - questItemPositions.add(position); - Entity entity = Entity.initEntity(config, position); - entity.getEntityConfig().setCurrentQuestID(questID); - questEntities.add(entity); - } - } else { - for(Vector2 questItemPosition: questItemPositions) { - Entity entity = Entity.initEntity(config, questItemPosition); - entity.getEntityConfig().setCurrentQuestID(questID); - questEntities.add(entity); - } - } - - mapMgr.addMapQuestEntities(questEntities); - ProfileManager.getInstance().setProperty(config.getEntityID(), questItemPositions); - break; - case KILL: - break; - case DELIVERY: - break; - case GUARD: - break; - case ESCORT: - break; - case RETURN: - break; - case DISCOVER: - break; - } - } + QuestTask.QuestTaskPropertyType questTaskPropertyType = QuestTask.QuestTaskPropertyType.TARGET_LOCATION; + String taskLocation = questTask.getPropertyValue(questTaskPropertyType.toString()); + MapFactory.MapType mapType = mapManager.getCurrentMapType(); + + return taskLocation == null || taskLocation.isEmpty() || !taskLocation.equalsIgnoreCase(mapType.toString()); } public String toString() { diff --git a/core/src/main/java/com/gdx/game/quest/QuestTaskHandler.java b/core/src/main/java/com/gdx/game/quest/QuestTaskHandler.java new file mode 100644 index 00000000..338a710e --- /dev/null +++ b/core/src/main/java/com/gdx/game/quest/QuestTaskHandler.java @@ -0,0 +1,11 @@ +package com.gdx.game.quest; + +import com.gdx.game.map.MapManager; + +public interface QuestTaskHandler { + + void handleUpdate(QuestTask questTask, String questID); + + void handleInit(MapManager mapManager, QuestTask questTask, String questID); + +} diff --git a/core/src/test/java/com/gdx/game/quest/QuestGraphTest.java b/core/src/test/java/com/gdx/game/quest/QuestGraphTest.java index 08aec946..d78bc2c1 100644 --- a/core/src/test/java/com/gdx/game/quest/QuestGraphTest.java +++ b/core/src/test/java/com/gdx/game/quest/QuestGraphTest.java @@ -1,3 +1,4 @@ + package com.gdx.game.quest; import com.badlogic.gdx.Gdx; @@ -12,6 +13,7 @@ import com.gdx.game.profile.ProfileManager; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -22,6 +24,9 @@ import java.util.Hashtable; import java.util.stream.Stream; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockConstruction; @@ -31,8 +36,14 @@ public class QuestGraphTest { private MockedConstruction mockNPCGraphics; + private QuestGraph questGraph; + + private QuestTask questTask; + @BeforeEach void init() { + questGraph = new QuestGraph(); + questTask = new QuestTask(); Gdx.gl = mock(GL20.class); Gdx.gl20 = mock(GL20.class); mockNPCGraphics = mockConstruction(NPCGraphicsComponent.class); @@ -40,13 +51,13 @@ void init() { @AfterEach void end() { + questGraph = null; + questTask = null; mockNPCGraphics.close(); } @Test public void testIsValid_ShouldSucceed() { - QuestGraph questGraph = new QuestGraph(); - QuestTask questTask = new QuestTask(); questTask.setId("1"); questTask.setPropertyValue("1", "test"); Hashtable questTasks = new Hashtable<>(); @@ -60,7 +71,6 @@ public void testIsValid_ShouldSucceed() { @Test public void testIsValid_ShouldSucceedWithNullValue() { - QuestGraph questGraph = new QuestGraph(); Hashtable questTasks = new Hashtable<>(); questGraph.setTasks(questTasks); @@ -94,28 +104,8 @@ private static QuestGraph createQuestGraphWithTask(String taskId, String propert return questGraph; } - @Test - public void testDoesCycleExist_ShouldSucceedReturnFalse() { - QuestGraph questGraph = new QuestGraph(); - QuestTask questTask = new QuestTask(); - questTask.setId("1"); - questTask.setPropertyValue(QuestTask.QuestTaskPropertyType.IS_TASK_COMPLETE.toString(), "true"); - Hashtable questTasks = new Hashtable<>(); - questTasks.put("1", questTask); - questGraph.setTasks(questTasks); - QuestTaskDependency questTaskDependency = new QuestTaskDependency(); - questTaskDependency.setSourceId("1"); - questTaskDependency.setDestinationId("1"); - - boolean doesCycleExist = questGraph.doesCycleExist(questTaskDependency); - - assertThat(doesCycleExist).isFalse(); - } - @Test public void testDoesQuestTaskHaveDependencies_ShouldSucceedWithWrongId() { - QuestGraph questGraph = new QuestGraph(); - QuestTask questTask = new QuestTask(); questTask.setId("1"); questTask.setPropertyValue(QuestTask.QuestTaskPropertyType.IS_TASK_COMPLETE.toString(), "true"); Hashtable questTasks = new Hashtable<>(); @@ -129,8 +119,6 @@ public void testDoesQuestTaskHaveDependencies_ShouldSucceedWithWrongId() { @Test public void testDoesQuestTaskHaveDependencies_ShouldSucceedReturnFalse() { - QuestGraph questGraph = new QuestGraph(); - QuestTask questTask = new QuestTask(); questTask.setId("1"); questTask.setPropertyValue(QuestTask.QuestTaskPropertyType.IS_TASK_COMPLETE.toString(), "true"); Hashtable questTasks = new Hashtable<>(); @@ -239,8 +227,6 @@ public void testInit_ShouldSucceedForQuestTypeFETCH() { mapManager.loadMap(MapFactory.MapType.TOPPLE); ProfileManager.getInstance().setProperty("TOWN_INNKEEPER", new Array()); - QuestGraph questGraph = new QuestGraph(); - QuestTask questTask = new QuestTask(); questTask.setId("1"); questTask.setPropertyValue(QuestTask.QuestTaskPropertyType.TARGET_LOCATION.toString(), "TOPPLE"); questTask.setPropertyValue(QuestTask.QuestTaskPropertyType.TARGET_TYPE.toString(), EntityFactory.TOWN_INNKEEPER_CONFIG); @@ -264,8 +250,6 @@ public void testInit_ShouldSucceedForQuestTypeKILL() { mapManager.loadMap(MapFactory.MapType.TOPPLE); ProfileManager.getInstance().setProperty("TOWN_INNKEEPER", new Array()); - QuestGraph questGraph = new QuestGraph(); - QuestTask questTask = new QuestTask(); questTask.setId("1"); questTask.setPropertyValue(QuestTask.QuestTaskPropertyType.TARGET_LOCATION.toString(), "TOPPLE"); questTask.setPropertyValue(QuestTask.QuestTaskPropertyType.TARGET_TYPE.toString(), EntityFactory.TOWN_INNKEEPER_CONFIG); @@ -279,4 +263,48 @@ public void testInit_ShouldSucceedForQuestTypeKILL() { assertThat(ProfileManager.getInstance().getProperty("TOWN_INNKEEPER", Array.class)).isEmpty(); } -} + + @Test + public void testReachableTaskTC01() { + // Arrange + QuestTaskDependency questTaskDependency = new QuestTaskDependency(); + questTaskDependency.setSourceId("1"); + questTaskDependency.setDestinationId("2"); + questGraph.addDependency(questTaskDependency); + // Act + boolean isReachable = questGraph.isReachable("1", "2"); + // Assert + assertTrue(isReachable); + } + + @Test + public void testReachableTaskTC02() { + // Arrange + QuestTaskDependency questTaskDependency1 = new QuestTaskDependency(); + QuestTaskDependency questTaskDependency2 = new QuestTaskDependency(); + questTaskDependency1.setSourceId("1"); + questTaskDependency1.setDestinationId("2"); + questTaskDependency2.setSourceId("2"); + questTaskDependency2.setDestinationId("3"); + questGraph.addDependency(questTaskDependency1); + questGraph.addDependency(questTaskDependency2); + // Act + boolean isReachable = questGraph.isReachable("1", "3"); + // Assert + assertTrue(isReachable); + } + + @Test + public void testNotReachableTask() { + // Arrange + QuestTaskDependency questTaskDependency = new QuestTaskDependency(); + questTaskDependency.setSourceId("1"); + questTaskDependency.setDestinationId("2"); + questGraph.addDependency(questTaskDependency); + // Act + boolean isReachable = questGraph.isReachable("1", "200"); + // Assert + assertFalse(isReachable); + } + +} \ No newline at end of file