diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java index 6c426d2..4a37e85 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java @@ -138,17 +138,22 @@ public class DungeonPack int maxSearchLength = config.allowDuplicatesInChain() ? maxRuleLength : MAX_HISTORY_LENGTH; ArrayList history = DungeonHelper.getDungeonChainHistory(parent, this, maxSearchLength); - ArrayList subtreeHistory; - /*if (config.getDuplicateSearchLevels() > 0) + ArrayList subtreeHistory = null; + if (config.getDuplicateSearchLevels() > 0) { - subtreeHistory = DungeonHelper.getFlatDungeonTree( - DungeonHelper.getAncestor(parent, config.getDuplicateSearchLevels()), - MAX_SUBTREE_LIST_SIZE); + // Search over (DuplicateSearchLevels - 1); zero means don't search at all, + // one means search only up to the level of the immediate parent, and so on. + // Since we start with the parent, we need to drop the max levels by one. + NewDimData ancestor = DungeonHelper.getAncestor(parent, this, config.getDuplicateSearchLevels() - 1); + if (ancestor != null) + { + subtreeHistory = DungeonHelper.listDungeonsInTree(ancestor, this, MAX_SUBTREE_LIST_SIZE); + } } - else + if (subtreeHistory == null) { subtreeHistory = new ArrayList(); - }*/ + } subtreeHistory = new ArrayList(); return getNextDungeon(history, subtreeHistory, random); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index a4cc980..2c9775e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -641,45 +641,66 @@ public class DungeonHelper } /** - * Performs a breadth-first listing of all dungeons rooted at a specified dimension. Only dungeons from the same pack as the root will be included. + * Performs a breadth-first listing of all dungeons rooted at a specified dimension. Only dungeons from the specified pack will be included. * @param root - the pocket dimension that serves as the root for the dungeon tree + * @param pack - the pack to which any dungeons must belong in order to be listed * @param maxSize - the maximum number of dungeons that can be listed * @return a list of the dungeons used in a given dungeon tree */ - public static ArrayList listDungeonsInTree(NewDimData root, int maxSize) + public static ArrayList listDungeonsInTree(NewDimData root, DungeonPack pack, int maxSize) { + int count = 0; + NewDimData current; + DungeonData dungeon; ArrayList dungeons = new ArrayList(); - Queue pendingDimensions = new LinkedList(); - - if (root.dungeon() == null) - { - return dungeons; - } + Queue pendingDimensions = new LinkedList(); pendingDimensions.add(root); + // Perform a breadth-first search through the dungeon graph while (dungeons.size() < maxSize && !pendingDimensions.isEmpty()) { - NewDimData current = pendingDimensions.remove(); - for (NewDimData child : current.children()) + current = pendingDimensions.remove(); + dungeon = current.dungeon(); + // Check that this is a dungeon, and if so, that it belongs to the pack that we want + if (dungeon != null && dungeon.dungeonType().Owner == pack) { - if (child.dungeon() != null) + dungeons.add(dungeon); + // Add all child dungeons for checking later + for (NewDimData child : current.children()) { - dungeons.add(child.dungeon()); pendingDimensions.add(child); } - if (dungeons.size() == maxSize) - { - break; - } } } return dungeons; } - public static NewDimData getAncestor(NewDimData dimension, int levels) + /** + * Gets the highest ancestor of a dimension with a dungeon that belongs to the specified pack. + * @param dimension - the first dimension to include in the search + * @param pack - the pack to which the ancestors must belong + * @param maxLevels - the maximum number of ancestors to check + * @return the highest ancestor that belongs to the specified pack within the specified levels, or null if none exists + */ + public static NewDimData getAncestor(NewDimData dimension, DungeonPack pack, int maxLevels) { // Find the ancestor of a dimension located a specified number of levels up. - // If such an ancestor does not exist, return the root dimension. - return null; + NewDimData parent = dimension; + NewDimData current = null; + + // We solve this inductively. We begin with null as the first valid ancestor, + // like a kind of virtual child dimension. Then "current" references the + // highest valid ancestor found so far and "parent" references its parent + for (int levels = 0; levels <= maxLevels; levels++) + { + if (parent == null || parent.dungeon() == null || + parent.dungeon().dungeonType().Owner != pack) + { + break; + } + current = parent; + parent = parent.parent(); + } + return current; } } \ No newline at end of file