summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/tlIItools/Affix.java431
-rw-r--r--src/main/java/tlIItools/AffixGroup.java130
-rw-r--r--src/main/java/tlIItools/AffixLister.java428
-rw-r--r--src/main/java/tlIItools/AffixSet.java47
-rw-r--r--src/main/java/tlIItools/Effect.java453
-rw-r--r--src/main/java/tlIItools/EffectGroup.java120
-rw-r--r--src/main/java/tlIItools/EffectRepo.java85
-rw-r--r--src/main/java/tlIItools/LevelRange.java135
-rw-r--r--src/main/java/tlIItools/Main.java6
-rw-r--r--src/main/java/tlIItools/NameFileReader.java124
-rw-r--r--src/main/java/tlIItools/ReplPair.java173
11 files changed, 1074 insertions, 1058 deletions
diff --git a/src/main/java/tlIItools/Affix.java b/src/main/java/tlIItools/Affix.java
index d90c0108..c49e6e2a 100644
--- a/src/main/java/tlIItools/Affix.java
+++ b/src/main/java/tlIItools/Affix.java
@@ -1,112 +1,79 @@
package tlIItools;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Scanner;
-
-/**
- * Represents a Torchlight II affix.
- */
+import java.util.*;
+
+/** Represents a Torchlight II affix.
+ *
+ * @author Ben Culkin */
public class Affix {
- /**
- * Whether or not to record timing info.
- */
+ /** Details which sort of affix this is.
+ *
+ * @author Ben Culkin */
+ public enum AffixType {
+ /** An affix that applies to a normal item. */
+ ITEM,
+ /** An affix that applies to a socketable. */
+ SOCKETABLE,
+ /** An affix that applies to a monster/person. */
+ PERSONAL,
+ /** An affix that applies as an item enchantment. */
+ ENCHANTMENT
+ }
+
+ /** Whether or not to record timing info. */
public static boolean doTiming;
- /**
- * Internal name of the affix.
- */
+
+ /** Internal name of the affix. */
public String intName;
- /*
- * The prefix/suffix attached to the affix.
+ /* The prefix/suffix attached to the affix.
*
* In general, only one of these is set for a given affix.
*
* NOTE: Some affixes have a mis-set suffix/prefix ordering, and may need to be
- * changed in their files.
- */
- /**
- * The 'suffix name' attached to this affix.
+ * changed in their files. */
+
+ /** The 'suffix name' attached to this affix.
*
* Include the word [ITEM] to indicate where the item name should go.
*
* Note that it is not guaranteed that this is actually a suffix; it could be a
- * prefix.
- */
+ * prefix. */
public String affixSuffix;
- /**
- * The 'prefix name' attached to this affix.
+ /** The 'prefix name' attached to this affix.
*
* Include the word [ITEM] to indicate where the item name should go.
*
* Note that it is not guaranteed that this is actually a prefix; it could be a
- * suffix.
- */
+ * suffix. */
public String affixPrefix;
- /*
- * The min/max levels the affix can spawn at.
- */
- /**
- * The minimum level of an item this affix can spawn on.
- */
- public int minLevel;
- /**
- * The maximum level of an item this affix can spawn on.
- */
- public int maxLevel;
-
- /**
- * The spawn weight for the affix.
- */
+ /** The min/max levels the affix can spawn at. */
+ public LevelRange spawnRange = new LevelRange();
+
+ /** The spawn weight for the affix. */
public int weight;
- /**
- * The number of affix slots taken up.
- */
+ /** The number of affix slots taken up. */
public int slots;
- /**
- * Whether this is a socketable affix.
- */
- public boolean isSocketable;
- /**
- * Whether this is an enchantment, instead of a standard affix.
- */
- public boolean isEnchantment;
- /**
- * Whether this is a mob/player affix.
- */
- public boolean isPerson;
-
- /**
- * The types of equipment this can spawn on.
- */
+ /** The type of thing this affix applies to. */
+ public AffixType type = AffixType.ITEM;
+
+ /** The types of equipment this can spawn on. */
public List<String> equipTypes;
- /**
- * The types of equipment this can't spawn on.
- */
+ /** The types of equipment this can spawn on. */
public List<String> nonequipTypes;
-
- /**
- * Places to get this enchantment from;
- */
+ /** The types of equipment this can spawn on. */
public List<String> enchantSources;
-
- /**
- * The socketable types this spawns on.
- */
+ /** The types of equipment this can spawn on. */
public List<String> socketableTypes;
- /**
- * The effects attached to this affix.
- */
+ /** The effects attached to this affix. */
public List<Effect> effects;
- /**
- * Is this affix in an 'affix group' with another affix?
+ /** Determine whether this affix is in an 'affix group' with another affix.
*
* By 'affix group', what we mean is that it is essentially the same affix, with
* generally just differing levels/values.
@@ -115,50 +82,51 @@ public class Affix {
* strength would be considered to be in the same affix group (assuming that
* both of those strength bonuses had the same effect name).
*
- * @param afx
- * The affix to check if we are in an affix group with.
+ * @param afx The affix to check if we are in an affix group with.
*
- * @return Whether or now we are in an affix group with the specified affix.
- */
+ * @return Whether or now we are in an affix group with the specified affix. */
public boolean isInAffixGroup(Affix afx) {
if (effects == null) {
- if (afx.effects != null)
- return false;
- } else if (!effects.equals(afx.effects)) // TODO this isn't actually an equals;
- // maybe make this a 'isEquivalent' or
- // 'isSimilarEffect'?
- return false;
+ if (afx.effects != null) return false;
+ } else if (!effects.equals(afx.effects)) {
+ Iterator<Effect> leftIter = effects.iterator();
+ Iterator<Effect> rightIter = afx.effects.iterator();
+
+ while (leftIter.hasNext() && rightIter.hasNext()) {
+ Effect left = leftIter.next();
+ Effect right = rightIter.next();
+
+ if (!left.group.equals(right.group)) return false;
+ }
+ }
+
if (enchantSources == null) {
- if (afx.enchantSources != null)
- return false;
- } else if (!enchantSources.equals(afx.enchantSources))
- return false;
- if (equipTypes == null) {
- if (afx.equipTypes != null)
- return false;
- } else if (!equipTypes.equals(afx.equipTypes))
+ if (afx.enchantSources != null) return false;
+ } else if (!enchantSources.equals(afx.enchantSources)) {
return false;
- if (isEnchantment != afx.isEnchantment)
+ } else if (equipTypes == null) {
+ if (afx.equipTypes != null) return false;
+ } else if (!equipTypes.equals(afx.equipTypes)) {
return false;
- if (isPerson != afx.isPerson)
+ } else if (type == null) {
+ if (afx.type != null) return false;
+ } else if (type != afx.type) {
return false;
- if (isSocketable != afx.isSocketable)
+ } else if (nonequipTypes == null) {
+ if (afx.nonequipTypes != null) return false;
+ } else if (!nonequipTypes.equals(afx.nonequipTypes)) {
return false;
- if (nonequipTypes == null) {
- if (afx.nonequipTypes != null)
- return false;
- } else if (!nonequipTypes.equals(afx.nonequipTypes))
- return false;
- if (socketableTypes == null) {
- if (afx.socketableTypes != null)
- return false;
- } else if (!socketableTypes.equals(afx.socketableTypes))
+ } else if (socketableTypes == null) {
+ if (afx.socketableTypes != null) return false;
+ } else if (!socketableTypes.equals(afx.socketableTypes)) {
return false;
+ } else {
+ return true;
+ }
return true;
}
-
- /**
- * Gets the name of the 'affix group' that this affix is in.
+
+ /** Gets the 'affix group' that this affix is in.
*
* By 'affix group', what we mean is that it is essentially the same affix, with
* generally just differing levels/values.
@@ -168,85 +136,62 @@ public class Affix {
* both of those strength bonuses had the same effect name, and applied to the
* same sorts of items).
*
- * @return The name of the affix group
- */
- public String getAffixGroupName() {
- StringBuilder sb = new StringBuilder();
-
- for (Effect eft : effects) {
- sb.append(eft.getEffectGroup());
- }
-
- for (String enchantSource : enchantSources) {
- sb.append(enchantSource);
- }
-
- for (String equipType : equipTypes) {
- sb.append(equipType);
- }
-
- for (String nonEquipType : nonequipTypes) {
- sb.append(nonEquipType);
- }
-
- for (String socketableType : socketableTypes) {
- sb.append(socketableType);
- }
-
- return sb.toString();
+ * @return The affix group */
+ public AffixGroup toAffixGroup() {
+ AffixGroup group = new AffixGroup();
+
+ group.type = type;
+ group.enchantSources = enchantSources;
+ group.equipTypes = equipTypes;
+ group.nonequipTypes = nonequipTypes;
+ group.socketableTypes = socketableTypes;
+
+ for (Effect eff : effects) group.effects.add(eff.group);
+
+ return group;
}
- /*
- * Are invalid equip types being added?
+ /* Are invalid equip types being added?
*
* NOTE: This is kinda bad practice. It should really be handled via two
* separate affix methods, one to add a valid affix, one to add an invalid, w/
- * the caller keeping tracking/calling the right one.
- */
+ * the caller keeping tracking/calling the right one. */
private boolean inNonEquip;
- /**
- * Create a new blank affix.
- */
+ /** Create a new blank affix. */
public Affix() {
- equipTypes = new ArrayList<>();
- nonequipTypes = new ArrayList<>();
- enchantSources = new ArrayList<>();
+ equipTypes = new ArrayList<>();
+ nonequipTypes = new ArrayList<>();
+ enchantSources = new ArrayList<>();
socketableTypes = new ArrayList<>();
- effects = new ArrayList<>();
+ effects = new ArrayList<>();
}
- /**
- * Sets the set of equip types that is added to.
+ /** Sets the set of equip types that is added to.
*
- * @param nonequip
- * True if the equip types being added are prohibited, or false
- * if they are allowed.
- */
+ * @param nonequip True if the equip types being added are prohibited, or false
+ * if they are allowed. */
public void setEquipType(boolean nonequip) {
inNonEquip = nonequip;
}
- /**
- * Add an equip type to the right set of equip types.
+ /** Add an equip type to the right set of equip types.
*
- * @param type
- * The equip type to add.
- */
- public void addEquipType(String type) {
+ * @param equipType The equip type to add. */
+ public void addEquipType(String equipType) {
if (inNonEquip) {
- nonequipTypes.add(type);
+ nonequipTypes.add(equipType);
} else {
- if (type.equals("SOCKETABLE") || type.contains(" EMBER")) {
- isSocketable = true;
- socketableTypes.add(type);
- } else if (type.startsWith("ENCHANTER")) {
- isEnchantment = true;
- enchantSources.add(type.substring(10));
- } else if (type.equals("MONSTER") || type.equals("PLAYER")) {
- isPerson = true;
+ if (equipType.equals("SOCKETABLE") || equipType.contains(" EMBER")) {
+ type = AffixType.SOCKETABLE;
+ socketableTypes.add(equipType);
+ } else if (equipType.startsWith("ENCHANTER")) {
+ type = AffixType.ENCHANTMENT;
+ enchantSources.add(equipType.substring(10));
+ } else if (equipType.equals("MONSTER") || equipType.equals("PLAYER")) {
+ type = AffixType.PERSONAL;
} else {
- equipTypes.add(type);
+ equipTypes.add(equipType);
}
}
}
@@ -256,22 +201,71 @@ public class Affix {
return intName;
}
- /**
- * Print out the full details of this affix.
+ /** Print out a 'short-form' of this affix.
+ *
+ * @return The short form of this affix. */
+ public String toShortString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(intName);
+ sb.append("\n");
+
+ if (affixSuffix != null) {
+ sb.append("\tSuffix: ");
+ sb.append(affixSuffix);
+ sb.append("\n");
+ }
+
+ if (affixPrefix != null) {
+ sb.append("\tPrefix: ");
+ sb.append(affixPrefix);
+ sb.append("\n");
+
+ }
+
+ sb.append("\t");
+ sb.append(spawnRange.toString());
+ sb.append("\n");
+
+ sb.append("\tSpawn Weight: ");
+ sb.append(weight);
+ sb.append("\t");
+
+ if (slots == 0) {
+ sb.append("\tOccupies no slots\n");
+ } else {
+ sb.append("\tSlots: ");
+ sb.append(slots);
+ sb.append("\n");
+ }
+
+ if (effects.size() != 0) {
+ sb.append("\tEffects: ");
+ for (Effect eft : effects) {
+ if (effects.size() > 1) sb.append("\n\t\t");
+ sb.append(eft.toString());
+ }
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ }
+
+ /** Print out the full details of this affix.
*
- * @return The full details of the affix.
- */
+ * @return The full details of the affix. */
public String toLongString() {
StringBuilder sb = new StringBuilder();
- if (isSocketable) {
+
+ if (type == AffixType.SOCKETABLE) {
sb.append("Socketable ");
- } else if (isPerson || (intName != null && intName.startsWith("HERO_"))) {
+ } else if (type == AffixType.PERSONAL || (intName != null && intName.startsWith("HERO_"))) {
sb.append("Personal ");
} else if (intName != null & intName.startsWith("MAP_")) {
sb.append("Area ");
}
- if (isEnchantment) {
+ if (type == AffixType.ENCHANTMENT) {
sb.append("Enchantment: ");
} else {
sb.append("Affix: ");
@@ -294,21 +288,7 @@ public class Affix {
}
sb.append("\t");
- if (minLevel <= 1 && maxLevel == 999) {
- sb.append("No Level Range");
- } else if (minLevel != 1 && maxLevel != 999) {
- sb.append("Level Range: ");
- sb.append(minLevel);
- sb.append("-");
- sb.append(maxLevel);
- } else if (minLevel <= 1) {
- sb.append("Max Level: ");
- sb.append(maxLevel);
- } else if (maxLevel == 999) {
- sb.append("Minimum Level: ");
- sb.append(minLevel);
- }
-
+ sb.append(spawnRange);
sb.append("\n");
sb.append("\tSpawn Weight: ");
@@ -324,18 +304,20 @@ public class Affix {
}
if (equipTypes.size() != 0) {
- if (isSocketable)
+ if (type == AffixType.SOCKETABLE) {
sb.append("\tSocketable Into: ");
- else if (isEnchantment)
+ } else if (type == AffixType.ENCHANTMENT) {
sb.append("\tEnchants Onto: ");
- else
+ } else {
sb.append("\tSpawns On: ");
+ }
+
sb.append(equipTypes);
sb.append("\n");
}
// Socketables & enchantments use this as a duplicate.
- if (!isSocketable && !isEnchantment && nonequipTypes.size() != 0) {
+ if (type != AffixType.SOCKETABLE && type != AffixType.ENCHANTMENT && nonequipTypes.size() != 0) {
sb.append("\tCan't Spawn On: ");
sb.append(nonequipTypes);
sb.append("\n");
@@ -362,6 +344,7 @@ public class Affix {
sb.append("\n");
}
+ /*
sb.append("Affix Group: ");
String afxGroupName = getAffixGroupName();
sb.append(afxGroupName);
@@ -369,36 +352,29 @@ public class Affix {
sb.append(afxGroupName.hashCode());
sb.append(")");
sb.append("\n");
+ */
return sb.toString();
}
- /**
- * Load an affix from an input source.
+ /** Load an affix from an input source.
*
- * @param scn
- * The input source to load from.
+ * @param scn The input source to load from.
*
- * @param fName
- * The name of the input source in question.
+ * @param fName The name of the input source in question.
*
- * @return The loaded affix.
- */
+ * @return The loaded affix. */
public static Affix loadAffix(Scanner scn, String fName) {
return loadAffix(scn, fName, new ArrayList<>());
}
- /**
- * Load an affix from an input source.
+ /** Load an affix from an input source.
*
- * @param scn
- * The input source to read from.
- * @param scnName
- * The name of the input source.
- * @param errors
- * A list to stick errors encountered during loading the affix.
- * @return The affix, loaded from the file.
- */
+ * @param scn The input source to read from.
+ * @param scnName The name of the input source.
+ * @param errors A list to stick errors encountered during loading the affix.
+ *
+ * @return The affix, loaded from the file. */
public static Affix loadAffix(Scanner scn, String scnName, List<String> errors) {
Affix afx = new Affix();
@@ -428,27 +404,32 @@ public class Affix {
afx.affixPrefix = splits[1];
break;
default:
- errors.add(
- String.format("Misformed affix translation: (%s) (%s) (%s)\n",
- splits[0], splits[1], scnName));
+ String msg = String.format(
+ "Misformed affix translation: (%s) (%s) (%s)\n",
+ splits[0], splits[1], scnName);
+ errors.add(msg);
}
} else if (ln.contains("MIN_SPAWN_RANGE")) {
- afx.minLevel = Integer.parseInt(splits[1]);
+ afx.spawnRange.minLevel = Integer.parseInt(splits[1]);
} else if (ln.contains("MAX_SPAWN_RANGE")) {
- afx.maxLevel = Integer.parseInt(splits[1]);
+ afx.spawnRange.maxLevel = Integer.parseInt(splits[1]);
} else if (ln.contains("WEIGHT:")) {
afx.weight = Integer.parseInt(splits[1]);
} else if (ln.contains("SLOTS_OCCUPY")) {
afx.weight = Integer.parseInt(splits[1]);
} else if (ln.contains("UNITTYPE") && !ln.contains("/")) {
if (splits.length == 1)
- errors.add(String.format("Malformed equip type: (%s) (%s)\n",
+ errors.add(String.format(
+ "Malformed equip type: (%s) (%s)\n",
splits[0], scnName));
+
afx.addEquipType(splits[1]);
} else if (splits[0].equals("<STRING>NAME")) {
if (splits.length == 1)
- errors.add(String.format("Malformed name: (%s) (%s)\n", splits[0],
- scnName));
+ errors.add(String.format(
+ "Malformed name: (%s) (%s)\n",
+ splits[0], scnName));
+
afx.intName = splits[1];
} else if (ln.contains("[EFFECT]")) {
List<String> eftErrs = new ArrayList<>();
@@ -459,21 +440,21 @@ public class Affix {
afx.effects.add(eft);
}
}
+
// Sort effects, so that they are in a stable order, even if specified out of
// order
afx.effects.sort(Comparator.comparingInt((val) -> val.hashCode()));
long endTime = System.nanoTime();
if (doTiming) {
- String fmt
- = "\tProcessed affix %s from %s in %d nanoseconds (%.2f seconds)\n\n";
+ String fmt = "\tProcessed affix %s from %s in %d nanoseconds (%.2f seconds)\n\n";
double seconds = ((double) (endTime - startTime) / 1000000000);
- errors.add(String.format(fmt, afx.intName, scnName, endTime - startTime,
- seconds));
+ errors.add(String.format(
+ fmt,
+ afx.intName, scnName, endTime - startTime, seconds));
}
return afx;
}
-
}
diff --git a/src/main/java/tlIItools/AffixGroup.java b/src/main/java/tlIItools/AffixGroup.java
new file mode 100644
index 00000000..5835614d
--- /dev/null
+++ b/src/main/java/tlIItools/AffixGroup.java
@@ -0,0 +1,130 @@
+package tlIItools;
+
+import java.util.*;
+
+import tlIItools.Affix.*;
+
+/**
+ * Represents a 'group' of related affixes.
+ *
+ * These are affixes that are do the same thing, but could be of varying levels;
+ * or have effects of differing intensity.
+ *
+ * @author Ben Culkin */
+public class AffixGroup implements Comparable<AffixGroup> {
+ public List<EffectGroup> effects;
+ /** The types of enchanters who can add this. */
+ public List<String> enchantSources;
+ /** The types of equipment this can spawn on. */
+ public List<String> equipTypes;
+ /** The types of equipment this cannot spawn on. */
+ public List<String> nonequipTypes;
+ /** The types of equipment this can be socketed into on. */
+ public List<String> socketableTypes;
+
+ /** The type of thing this affix applies to. */
+ public AffixType type = AffixType.ITEM;
+
+ /** Create a new affix group. */
+ public AffixGroup() {
+ effects = new ArrayList<>();
+ enchantSources = new ArrayList<>();
+ equipTypes = new ArrayList<>();
+ nonequipTypes = new ArrayList<>();
+ socketableTypes = new ArrayList<>();
+ }
+
+ /** Determine whether this affix group contains a particular affix.
+ *
+ * By 'affix group', what we mean is that it is essentially the same affix, with
+ * generally just differing levels/values.
+ *
+ * For instance, an affix that granted +2 strength, and one that granted +4
+ * strength would be considered to be in the same affix group (assuming that
+ * both of those strength bonuses had the same effect name).
+ *
+ * @param afx The affix to check if it is in the affix group with.
+ *
+ * @return Whether or the specified affix is in this affix group. */
+ public boolean contains(Affix afx) {
+ return afx.toAffixGroup().equals(this);
+ }
+
+ public String groupSummary() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("Affix Type: ");
+ sb.append(type);
+ sb.append("\n");
+ sb.append("Effects: ");
+ if (effects.size() > 1) sb.append("\n");
+ for (EffectGroup group : effects) {
+ if (effects.size() > 1) sb.append("\t");
+ sb.append(group.summary());
+ sb.append("\n");
+ }
+
+ if (type == AffixType.SOCKETABLE) {
+ sb.append("Affix can be socketed into: ");
+ sb.append(String.join(", ", equipTypes));
+ sb.append("\nAffix can spawn on: ");
+ sb.append(String.join(", ", socketableTypes));
+ sb.append("\n");
+ } else {
+ sb.append("Affix can spawn on: ");
+ sb.append(String.join(", ", equipTypes));
+ sb.append("\nAffix can't spawn on: ");
+ sb.append(String.join(", ", nonequipTypes));
+ sb.append("\n");
+ }
+
+ if (type == AffixType.ENCHANTMENT) {
+ sb.append("Affix can be enchanted by: ");
+ sb.append(String.join(", ", socketableTypes));
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public int compareTo(AffixGroup other) {
+ return toString().compareTo(other.toString());
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ for (EffectGroup group: effects) sb.append(group);
+ for (String enchantSource: enchantSources) sb.append(enchantSource);
+ for (String equipType: equipTypes) sb.append(equipType);
+ for (String nonEquipType: nonequipTypes) sb.append(nonEquipType);
+ for (String socketableType: socketableTypes) sb.append(socketableType);
+
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(effects, enchantSources, equipTypes, nonequipTypes,
+ socketableTypes, type);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ AffixGroup other = (AffixGroup) obj;
+ return Objects.equals(effects, other.effects)
+ && Objects.equals(enchantSources, other.enchantSources)
+ && Objects.equals(equipTypes, other.equipTypes)
+ && Objects.equals(nonequipTypes, other.nonequipTypes)
+ && Objects.equals(socketableTypes, other.socketableTypes)
+ && type == other.type;
+ }
+}
diff --git a/src/main/java/tlIItools/AffixLister.java b/src/main/java/tlIItools/AffixLister.java
index 3a096bd2..c9cce52a 100644
--- a/src/main/java/tlIItools/AffixLister.java
+++ b/src/main/java/tlIItools/AffixLister.java
@@ -5,79 +5,56 @@ import java.io.*;
import java.util.*;
import java.util.Map.Entry;
-/**
- * Lists randomly generated affixes for Torchlight II gear.
+/** Lists randomly generated affixes for Torchlight II gear.
*
- * @author Ben Culkin
- */
+ * @author Ben Culkin */
public class AffixLister {
- /*
- * Count of effects this class has loaded.
- */
+ /* Count of effects this class has loaded. */
private static int effectCount = 0;
- /**
- * Should the class record timing data?
- */
+ /** Should the class record timing data? */
public static boolean doTiming = false;
- /**
- * Should the file name be attached to things?
- */
+ /** Should the file name be attached to things? */
public static boolean addFileName = false;
- /*
- * Output streams to use.
- */
- /**
- * The normal output to use.
- */
+ /* Output streams to use. */
+
+ /** The normal output to use. */
public static PrintStream normOut = System.out;
- /**
- * The error output to use.
- */
+ /** The error output to use. */
public static PrintStream errOut = System.err;
+ /** The output to write affix groups to. */
+ public static PrintStream affixGroupDest = null;
- /**
- * Indicates how to treat affixes with regards to their names.
- */
+ /** Indicates how to treat affixes with regards to their names. */
public static enum NameMode {
- /**
- * Show all affixes.
- */
+ /** Show all affixes. */
ALL,
- /**
- * Show only unnamed affixes.
- */
+ /** Show only unnamed affixes. */
UNNAMED,
- /**
- * Show only named affixes.
- */
+ /** Show only named affixes. */
NAMED;
}
- /**
- * Main method.
+ /** Main method.
*
- * @param args The names of the files to read affix data from.
- */
+ * @param args The names of the files to read affix data from. */
public static void main(String[] args) {
listAffixes(args);
}
- /**
- * Main method that actually does stuff.
+ /** Main method that actually does stuff.
*
- * @param args
- * The names of the files to read affix data from.
- */
+ * @param args The names of the files to read affix data from.
+ *
+ * @return The listed affix set. */
+ @SuppressWarnings("unused")
public static AffixSet listAffixes(String[] args) {
- AffixSet affixSetByName = new AffixSet();
+ boolean doingArgs = true;
- boolean doingArgs = true;
-
- boolean omitZeros = false;
- boolean listZeros = false;
+ boolean omitZeros = false;
+ boolean listZeros = false;
NameMode nameMode = NameMode.ALL;
@@ -86,193 +63,164 @@ public class AffixLister {
int zeroCount = 0;
int groupCount = 0;
- boolean outputAffixGroups = false;
- OutputStream affixGroupDest = null;
-
- Map<String, Set<Affix>> groupContents = affixSetByName.affixGroups;
+ boolean outputAffixGroups = false;
- Set<Affix> nonGroupContents = affixSetByName.ungroupedAffixes;
+ Map<String, Set<Affix>> groupContents = new HashMap<>();
+ Set<Affix> nonGroupContents = new HashSet<>();
NameFileReader nfr = new NameFileReader(false);
nfr.groupRx = ".*/mods/([^/]+)/*";
long startTime = System.nanoTime();
- for(int i = 0; i < args.length; i++) {
+ for (int i = 0; i < args.length; i++) {
String fName = args[i];
if (doingArgs && fName.startsWith("-")) {
boolean isArg = true;
switch (fName) {
- case "--":
- doingArgs = false;
- break;
-
- case "--omit-zero":
- case "-z":
- omitZeros = true;
- break;
-
- case "--no-omit-zero":
- case "-Z":
- omitZeros = false;
- break;
-
- case "--list-zero":
- case "-l":
- listZeros = true;
- break;
-
- case "--no-list-zero":
- case "-L":
- listZeros = false;
- break;
-
- case "--timing":
- case "-t":
- doTiming = true;
- Effect.doTiming = true;
+ case "--":
+ doingArgs = false;
+ break;
+ case "--omit-zero":
+ case "-z":
+ omitZeros = true;
+ break;
+ case "--no-omit-zero":
+ case "-Z":
+ omitZeros = false;
+ break;
+ case "--list-zero":
+ case "-l":
+ listZeros = true;
+ break;
+ case "--no-list-zero":
+ case "-L":
+ listZeros = false;
+ break;
+ case "--timing":
+ case "-t":
+ doTiming = true;
+ Effect.doTiming = true;
+ break;
+ case "--no-timing":
+ case "-T":
+ doTiming = false;
+ Effect.doTiming = false;
+ break;
+ case "--file-names":
+ case "-f":
+ addFileName = true;
+ break;
+ case "--no-file-names":
+ case "-F":
+ addFileName = true;
+ break;
+ case "--name-mode":
+ case "-n":
+ if (i + 1 >= args.length) {
+ errOut.printf("ERROR: name mode argument requires the mode to use be specified (all, unnamed or named)\n");
break;
+ }
- case "--no-timing":
- case "-T":
- doTiming = false;
- Effect.doTiming = false;
- break;
-
- case "--file-names":
- case "-f":
- addFileName = true;
- break;
-
- case "--no-file-names":
- case "-F":
- addFileName = true;
- break;
-
- case "--name-mode":
- case "-n":
- if (i + 1 >= args.length) {
- errOut.printf("ERROR: name mode argument requires the mode to use be specified (all, unnamed or named)\n");
- break;
- }
-
- nameMode = NameMode.valueOf(args[++i].toUpperCase());
-
- break;
-
- case "--file-group":
- case "-g":
- if (i + 1 >= args.length) {
- errOut.printf("ERROR: file group argument requires the group name to use be specified\n");
- break;
- }
-
- nfr.swapGroup(args[++i]);
-
- break;
-
- case "--guess-groups":
- nfr.guessGroups = true;
-
- break;
-
- case "--no-guess-groups":
- nfr.guessGroups = false;
-
+ nameMode = NameMode.valueOf(args[++i].toUpperCase());
+ break;
+ case "--file-group":
+ case "-g":
+ if (i + 1 >= args.length) {
+ errOut.printf("ERROR: file group argument requires the group name to use be specified\n");
break;
+ }
- case "--read-names-from-file":
- case "-r":
- if (i + 1 >= args.length) {
- errOut.printf("ERROR: read name file argument requires the file to use be specified\n");
- break;
- }
-
- nfr.readFrom(args[++i]);
-
+ nfr.swapGroup(args[++i]);
+ break;
+ case "--guess-groups":
+ nfr.guessGroups = true;
+ break;
+ case "--no-guess-groups":
+ nfr.guessGroups = false;
+ break;
+ case "--read-names-from-file":
+ case "-r":
+ if (i + 1 >= args.length) {
+ errOut.printf("ERROR: read name file argument requires the file to use be specified\n");
break;
+ }
- case "--output":
- case "-o":
- if (i + 1 >= args.length) {
- errOut.printf("ERROR: output file argument requires the file to use be specified\n");
- break;
- }
-
- try {
- normOut = new PrintStream(args[++i]);
-
- nfr.normOut = normOut;
- } catch (IOException ioex) {
- errOut.printf("Could not open output file %s\n", args[i]);
-
- ioex.printStackTrace(errOut);
- }
-
+ nfr.readFrom(args[++i]);
+ break;
+ case "--output":
+ case "-o":
+ if (i + 1 >= args.length) {
+ errOut.printf("ERROR: output file argument requires the file to use be specified\n");
break;
+ }
- case "--output-errors":
- case "-e":
- if (i + 1 >= args.length) {
- errOut.printf("ERROR: error output file argument requires the file to use be specified\n");
- break;
- }
-
- try {
- errOut = new PrintStream(args[++i]);
-
- nfr.errOut = errOut;
- } catch (IOException ioex) {
- errOut.printf("Could not open error output file %s\n", args[i]);
-
- ioex.printStackTrace(errOut);
- }
+ try {
+ normOut = new PrintStream(args[++i]);
+ nfr.normOut = normOut;
+ } catch (IOException ioex) {
+ errOut.printf("Could not open output file %s\n", args[i]);
+ ioex.printStackTrace(errOut);
+ }
+ break;
+ case "--output-errors":
+ case "-e":
+ if (i + 1 >= args.length) {
+ errOut.printf("ERROR: error output file argument requires the file to use be specified\n");
break;
+ }
- case "--guess-regex":
- if (i + 1 >= args.length) {
- errOut.printf("ERROR: group regex argument requires the regex to use be specified\n");
- break;
- }
-
- nfr.groupRx = args[++i];
+ try {
+ errOut = new PrintStream(args[++i]);
+ nfr.errOut = errOut;
+ } catch (IOException ioex) {
+ errOut.printf("Could not open error output file %s\n", args[i]);
+ ioex.printStackTrace(errOut);
+ }
+ break;
+ case "--guess-regex":
+ if (i + 1 >= args.length) {
+ errOut.printf("ERROR: group regex argument requires the regex to use be specified\n");
break;
- case "--output-affix-groups":
- if (i + 1 >= args.length) {
- errOut.printf("ERROR: to output affix-groups, must specify a file to output them to");
- break;
- }
-
- try {
- affixGroupDest = new PrintStream(args[++i]);
-
- outputAffixGroups = true;
- } catch (IOException ioex) {
- errOut.printf("ERROR: Couldn't open file %s to write affix groups to\n", affixGroupDest);
- }
+ }
+ nfr.groupRx = args[++i];
+ break;
+ case "--output-affix-groups":
+ if (i + 1 >= args.length) {
+ errOut.printf(
+ "ERROR: to output affix-groups, must specify a file to output them to");
break;
- default:
- isArg = false;
- }
+ }
- if (isArg) {
- continue;
+ try {
+ affixGroupDest = new PrintStream(args[++i]);
+ outputAffixGroups = true;
+ } catch (IOException ioex) {
+ errOut.printf(
+ "ERROR: Couldn't open file %s to write affix groups to\n",
+ affixGroupDest);
+ }
+ break;
+ default:
+ isArg = false;
}
- nfr.addFile(fName);
+ if (isArg) continue;
+ else nfr.addFile(fName);
} else {
nfr.addFile(fName);
}
}
AffixSet affixSetByContents = new AffixSet();
-
+
for (Entry<String, List<String>> fGroup : nfr.fNames.entrySet()) {
if (fGroup.getValue().size() == 0) continue;
+
normOut.printf("\nFile Group '%s' starting\n", fGroup.getKey());
for (String fName : fGroup.getValue()) {
try (FileReader fr = new FileReader(fName)) {
@@ -280,7 +228,7 @@ public class AffixLister {
Affix afx = Affix.loadAffix(sc, fName);
affixSetByContents.addAffixByContents(afx);
-
+
effectCount += afx.effects.size();
if (afx.intName != null && afx.weight != 0) {
@@ -290,10 +238,12 @@ public class AffixLister {
if (!groupContents.containsKey(groupName)) {
groupCount += 1;
- // errOut.printf("\tTRACE: Counted distinct group %s from %s\n", groupName, afx.intName);
+ // errOut.printf("\tTRACE: Counted distinct group %s from
+ // %s\n", groupName, afx.intName);
if (hasGroup) {
- // errOut.printf("\tTRACE: Counted actual group %s from %s\n", groupName, afx.intName);
+ // errOut.printf("\tTRACE: Counted actual group %s from
+ // %s\n", groupName, afx.intName);
groupContents.put(groupName, new HashSet<>());
} else {
@@ -309,58 +259,88 @@ public class AffixLister {
if (afx.weight == 0) zeroCount += 1;
if (afx.weight == 0 && !listZeros) {
- if (!omitZeros)
- normOut.printf("\nAffix %s has zero spawn weight\n", afx.intName);
+ if (!omitZeros) normOut.printf(
+ "\nAffix %s has zero spawn weight\n",
+ afx.intName);
} else {
- boolean isNamed = (afx.affixSuffix != null) || (afx.affixPrefix != null);
+ boolean isNamed =
+ (afx.affixSuffix != null) || (afx.affixPrefix != null);
- if (isNamed) namedCount += 1;
+ if (isNamed) namedCount += 1;
else unnamedCount += 1;
- if (nameMode == NameMode.UNNAMED && isNamed) continue;
+ if (nameMode == NameMode.UNNAMED && isNamed) continue;
if (nameMode == NameMode.NAMED && !isNamed) continue;
normOut.printf("\n%s\n", afx.toLongString());
}
} catch (Exception ex) {
- errOut.printf("Something bad happened for file %s:%s\n", fName, ex.getMessage());
+ errOut.printf(
+ "Something bad happened for file %s:%s\n",
+ fName, ex.getMessage());
ex.printStackTrace(errOut);
-
errOut.println();
}
}
+
normOut.printf("\nFile Group '%s' ending\n", fGroup.getKey());
}
errOut.println("\nGroup Contents: ");
- for (Entry<String, Set<Affix>> ent: groupContents.entrySet()) {
+
+ for (Entry<String, Set<Affix>> ent : groupContents.entrySet()) {
errOut.printf("\t%s: %s\n", ent.getKey(), ent.getValue());
}
+
errOut.println();
errOut.println();
if (outputAffixGroups) {
- for (Entry<String, Set<Affix>> ent : affixSetByContents.affixGroups.entrySet()) {
- String groupName = ent.getKey();
- Set<Affix> affixes = ent.getValue();
-
- boolean isFirstAfx = true;
- for (Affix afx : affixes) {
- if (isFirstAfx) {
- // Print the header for this
- // group
- isFirstAfx = false;
- }
- // print this affix in the group format
+ for (Entry<AffixGroup, Set<Affix>> entry
+ : affixSetByContents.affixGroups.entrySet())
+ {
+ AffixGroup group = entry.getKey();
+ Set<Affix> affixes = entry.getValue();
+
+ // Skip one-affix groups
+ if (affixes.size() == 1) continue;
+
+ List<Affix> affixList = new ArrayList<>(affixes);
+ Collections.sort(affixList, (lhs, rhs) -> lhs.spawnRange.compareTo(rhs.spawnRange));
+
+ boolean isFirstAfx = true;
+ for (Affix afx : affixList) {
+ // @TODO actually implement this -bculkin, 12/29/2020
+
+ // Print the header for this group
+ if (isFirstAfx) {
+ isFirstAfx = false;
+ affixGroupDest.printf("Group ID %s (%d affixes)\t",
+ group.hashCode(), affixes.size());
+ affixGroupDest.print(group.groupSummary());
}
+
+ affixGroupDest.print("\t");
+ affixGroupDest.print(afx.toShortString().replaceAll("\n(?=.)", "\n\t"));
+ // print this affix in the group format
}
+ affixGroupDest.println();
+ }
}
long endTime = System.nanoTime();
- errOut.printf("\nProcessed %,d affixes (%,d named, %,d unnamed, %,d zero-weight) (%,d effects) (%,d distinct groups, %,d actual groups, %,d nongrouped affixes) out of %,d files (%,d groups) in %,d nanoseconds (%.2f seconds)\n", nfr.fCount, namedCount, unnamedCount, zeroCount, effectCount, groupCount, groupContents.size(), nonGroupContents.size(), nfr.fCount, nfr.fNames.size(), endTime - startTime, ((double)(endTime - startTime) / 1000000000));
- errOut.printf("\tOptions: Name Mode: %s, Special-case zero weight: %s, Noting zero-weight in special case: %s\n", nameMode, !listZeros, !omitZeros);
-
- return affixSetByName;
+ errOut.printf(
+ "\nProcessed %,d affixes (%,d named, %,d unnamed, %,d zero-weight) (%,d effects) (%,d distinct groups, %,d actual groups, %,d nongrouped affixes) out of %,d files (%,d groups) in %,d nanoseconds (%.2f seconds)\n",
+ nfr.fCount, namedCount, unnamedCount, zeroCount, effectCount, groupCount,
+ groupContents.size(), nonGroupContents.size(), nfr.fCount,
+ nfr.fNames.size(), endTime - startTime,
+ ((double) (endTime - startTime) / 1000000000));
+
+ errOut.printf(
+ "\tOptions: Name Mode: %s, Special-case zero weight: %s, Noting zero-weight in special case: %s\n",
+ nameMode, !listZeros, !omitZeros);
+
+ return affixSetByContents;
}
}
diff --git a/src/main/java/tlIItools/AffixSet.java b/src/main/java/tlIItools/AffixSet.java
index d7f14211..fa5c8d19 100644
--- a/src/main/java/tlIItools/AffixSet.java
+++ b/src/main/java/tlIItools/AffixSet.java
@@ -2,65 +2,50 @@ package tlIItools;
import java.util.*;
-/**
- * Container of a set of affixes.
+/** Container of a set of affixes.
*
- * @author Ben Culkin
- */
+ * @author Ben Culkin */
public class AffixSet {
private static class AffixComparator implements Comparator<Affix> {
+ @Override
public int compare(Affix a1, Affix a2) {
- if (a1.minLevel == a2.minLevel) {
- return a1.maxLevel - a2.maxLevel;
- }
-
- return a1.minLevel - a2.minLevel;
+ return a1.spawnRange.compareTo(a2.spawnRange);
}
}
- /**
- * All of the affix groups contained in this set.
+ /** All of the affix groups contained in this set.
*
* An affix group is a set of affixes that generally have the same or
- * similar effects, but have different intensities or spawn levels.
- */
- public Map<String, Set<Affix>> affixGroups;
+ * similar effects, but have different intensities or spawn levels. */
+ public Map<AffixGroup, Set<Affix>> affixGroups;
- /**
- * All of the ungrouped affixes contained in this set.
- */
+ /** All of the ungrouped affixes contained in this set. */
public Set<Affix> ungroupedAffixes;
- /**
- * Create a new blank affix set.
- */
+ /** Create a new blank affix set. */
public AffixSet() {
affixGroups = new TreeMap<>();
ungroupedAffixes = new TreeSet<>(new AffixComparator());
}
-
- /**
- * Add an affix to this set.
+
+ /** Add an affix to this set.
*
- * @param afx The affix to add.
- */
+ * @param afx The affix to add. */
public void addAffixByContents(Affix afx) {
- String afxGroup = afx.getAffixGroupName();
-
+ AffixGroup group = afx.toAffixGroup();
+ String afxGroup = group.toString();
+
if (afxGroup.equals("")) {
ungroupedAffixes.add(afx);
} else {
- affixGroups.compute(afxGroup, (key, val) -> {
+ affixGroups.compute(group, (key, val) -> {
if (val == null) {
Set<Affix> afxSet = new HashSet<>();
-
afxSet.add(afx);
-
return afxSet;
} else {
val.add(afx);
-
return val;
}
});
diff --git a/src/main/java/tlIItools/Effect.java b/src/main/java/tlIItools/Effect.java
index d641b112..fd7867d0 100644
--- a/src/main/java/tlIItools/Effect.java
+++ b/src/main/java/tlIItools/Effect.java
@@ -1,255 +1,139 @@
package tlIItools;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Scanner;
+import java.util.*;
-/**
- * Represents an effect attached to an affix.
+/** Represents an effect attached to an affix.
*
- * @author Ben Culkin
- */
+ * @author Ben Culkin */
public class Effect {
- /**
- * Count of all loaded effects.
- */
+ /** Count of all loaded effects. */
public static int effectCount = 0;
- /**
- * Do timing analysis when loading effects.
- */
+ /** Do timing analysis when loading effects. */
public static boolean doTiming;
- /**
- * The file name this effect came from.
- */
+ /** The file name this effect came from. */
public String fName;
-
- /**
- * The name of the effect.
- */
- public String name;
-
- /**
- * The specific effect that happens.
- */
- public String type;
-
- /**
- * Damage type for the effect, if applicable.
- */
- public String damageType = "physical";
-
- /**
- * Duration of the effect.
- */
+ /** Duration of the effect. */
public double duration;
- /**
- * Whether or not we have a duration or not.
- */
- public boolean hasDuration;
-
- /**
- * Minimum value for the effect.
- */
+ /** Minimum value for the effect. */
public double minValue;
- /**
- * Maximum value for the effect.
- */
+ /** Maximum value for the effect. */
public double maxValue;
- /**
- * The name of the stat that applies to this affect.
- */
- public String statName;
- /**
- * The percent of the stat value to apply.
- */
+ /** The percent of the stat value to apply. */
public double statPercent;
- /**
- * Whether or not this stat is a bonus value.
- */
- public boolean isStatBonus;
-
- /**
- * Whether or not this uses the owners level to modify
- * any applicable graph.
- */
- public boolean ownerLevel;
-
- /**
- * The graph to use instead of the default graph.
- */
- public String graphOverride;
-
- /**
- * Whether or not a graph is used for this effect.
- */
- public boolean useGraph = true;
-
- /**
- * Whether this effect can stack with itself.
- */
- public boolean exclusive;
-
- /**
- * The amount the targets armor is reduced by for this
- * effect.
- */
+ /** The amount the targets armor is reduced by for this effect. */
public double soakScale = 1.0;
- /**
- * Level of the effect.
- */
+ /** Level of the effect. */
public int level = -1;
- /**
- * Whether or not this effect is a 'transfer'
- * effect (Applied to the enemy on a hit).
- */
- public boolean isTransfer;
-
- /**
- * The amount to resist/do knockback by.
- */
+ /** The 'effect group' this effect belongs to.
+ *
+ * An 'effect group is essentially any other effect that is the same general sort of effect, just with different details.
+ *
+ * For instance, an effect that grants +4 strength would group with one granting +8 strength,
+ * assuming that most other details were equal. */
+ public EffectGroup group = new EffectGroup();
+
+ /** The amount to resist/do knockback by. */
public double resist;
- /**
- * Minimum value per monster.
- */
+ /** Minimum value per monster. */
public double minPer;
- /**
- * Maximum value per monster.
- */
+ /** Maximum value per monster. */
public double maxPer;
- /**
- * Range for effect.
- */
+ /** Range for effect. */
public double range;
- /**
- * Maximum count of monsters.
- */
+ /** Maximum count of monsters. */
public double maxCount;
- /**
- * The rate at which the effect fires.
- */
+ /** The rate at which the effect fires. */
public double pulse;
- /**
- * Create a new blank effect.
- */
+ /** Create a new blank effect. */
public Effect() {
}
-
- /**
- * Gets the 'effect group' this effect belongs to.
- *
- * An 'effect group is essentially any other effect that is the same general sort of effect, just with different details.
- *
- * For instance, an effect that grants +4 strength would group with one granting +8 strength,
- * assuming that most other details were equal.
- *
- * @return The 'effect group' this effect belongs to.
- */
- public String getEffectGroup() {
- StringBuilder sb = new StringBuilder();
-
- sb.append(name);
- sb.append(type);
- sb.append(damageType);
- sb.append(hasDuration);
- sb.append(statName);
- sb.append(isStatBonus);
- sb.append(ownerLevel);
- sb.append(graphOverride);
- sb.append(useGraph);
- sb.append(exclusive);
- sb.append(isTransfer);
-
- return sb.toString();
- }
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- if (isTransfer) {
+ if (group.isTransfer) {
sb.append("Inflict on Hit: ");
}
- Map<String, String> detMap = hasDuration ? EffectRepo.timeDetals : EffectRepo.detals;
+ Map<String, String> detMap = group.hasDuration ? EffectRepo.timeDetals : EffectRepo.detals;
- if (detMap.containsKey(type) || (hasDuration && !EffectRepo.timeDetals.containsKey(type) && EffectRepo.detals.containsKey(type))) {
+ if (detMap.containsKey(group.type) ||
+ (group.hasDuration
+ && !EffectRepo.timeDetals.containsKey(group.type)
+ && EffectRepo.detals.containsKey(group.type)))
+ {
String fmt;
- if (hasDuration && !EffectRepo.timeDetals.containsKey(type) && EffectRepo.detals.containsKey(type)) {
- AffixLister.errOut.printf("Improvised details for timed %s\n", type);
- fmt = EffectRepo.detals.get(type) + "for <DUR> seconds";
+ if (group.hasDuration
+ && !EffectRepo.timeDetals.containsKey(group.type)
+ && EffectRepo.detals.containsKey(group.type))
+ {
+ AffixLister.errOut.printf("Improvised details for timed %s\n", group.type);
+ fmt = EffectRepo.detals.get(group.type) + "for <DUR> seconds";
} else {
- fmt = detMap.get(type);
+ fmt = detMap.get(group.type);
}
// Expand aliases first.
- for (ReplPair repl : EffectRepo.replList) {
- fmt = fmt.replaceAll(repl.find, repl.replace);
- }
+ for (ReplPair repl : EffectRepo.replList) fmt = fmt.replaceAll(repl.find, repl.replace);
- if (minValue <= 0 && maxValue <= 0) {
- fmt = fmt.replaceAll("<C\\|([^|>]+)\\|([^|>]+)>", "$1");
- }
-
- if (minValue >= 0 && maxValue >= 0) {
- fmt = fmt.replaceAll("<C\\|([^|>]+)\\|([^|>]+)>", "$2");
- }
-
- if (minPer <= 0 && maxPer <= 0) {
- fmt = fmt.replaceAll("<MC\\|(\\w+)\\|(\\w+)>", "$1");
- }
-
- if (minPer >= 0 && maxPer >= 0) {
- fmt = fmt.replaceAll("<MC\\|([^|>]+)\\|([^|>]+)>", "$2");
- }
+ if (minValue <= 0 && maxValue <= 0) { fmt = fmt.replaceAll("<C\\|([^|>]+)\\|([^|>]+)>", "$1"); }
+ if (minValue >= 0 && maxValue >= 0) { fmt = fmt.replaceAll("<C\\|([^|>]+)\\|([^|>]+)>", "$2"); }
+ if (minPer <= 0 && maxPer <= 0) { fmt = fmt.replaceAll("<MC\\|(\\w+)\\|(\\w+)>", "$1"); }
+ if (minPer >= 0 && maxPer >= 0) { fmt = fmt.replaceAll("<MC\\|([^|>]+)\\|([^|>]+)>", "$2"); }
if (fmt.contains("<") || fmt.contains(">")) {
- AffixLister.errOut.printf("WARN: Details for effect %s are malformatted (contains < or >):\n\t%s\n", type, fmt);
+ AffixLister.errOut.printf("WARN: Details for effect %s are malformatted (contains < or >):\n\t%s\n", group.type, fmt);
}
- sb.append(String.format(fmt, Math.abs(minValue), Math.abs(maxValue), duration, damageType.toLowerCase(), level, resist, name, Math.abs(minPer), Math.abs(maxPer), range, maxCount, pulse));
+ sb.append(String.format(fmt,
+ Math.abs(minValue), Math.abs(maxValue),
+ duration, group.damageType.toLowerCase(), level, resist, group.name,
+ Math.abs(minPer), Math.abs(maxPer), range, maxCount, pulse));
} else {
sb.append("No effect details for effect ");
- sb.append(type);
- sb.append(String.format(" with parameters (min %.2f, max %.2f, dur %.2f, type %s, level %d)", minValue, maxValue, duration, damageType.toLowerCase(), level, name));
+ sb.append(group.type);
+ sb.append(String.format(
+ " with parameters (min %.2f, max %.2f, dur %.2f, type %s, level %d)",
+ minValue, maxValue, duration, group.damageType.toLowerCase(), level, group.name));
if (AffixLister.addFileName) {
sb.append(" from file ");
sb.append(fName);
}
- if (hasDuration) AffixLister.errOut.print("TIMED: ");
+ if (group.hasDuration) AffixLister.errOut.print("TIMED: ");
AffixLister.errOut.println(sb.toString());
}
- if (name != null) {
+ if (group.name != null) {
sb.append(" (named ");
- sb.append(name);
+ sb.append(group.name);
sb.append(")");
}
- if (exclusive) sb.append(" (Exclusive)");
+ if (group.exclusive) sb.append(" (Exclusive)");
- if (graphOverride != null) {
+ if (group.graphOverride != null) {
sb.append(" (Uses ");
- sb.append(graphOverride);
+ sb.append(group.graphOverride);
sb.append(" graph)");
}
- if (ownerLevel) {
+ if (group.ownerLevel) {
sb.append(" (Uses owner level for graph)");
}
@@ -265,154 +149,77 @@ public class Effect {
sb.append(")");
}
- if (statName != null) {
- sb.append(String.format(" (%.2f of stat %s", statPercent, statName));
- if (isStatBonus) sb.append(" as bonus)");
+ if (group.statName != null) {
+ sb.append(String.format(" (%.2f of stat %s", statPercent, group.statName));
+
+ if (group.isStatBonus) sb.append(" as bonus)");
else sb.append(")");
}
- if (!useGraph) sb.append(" (Ignoring graph)");
+ if (!group.useGraph) sb.append(" (Ignoring graph)");
return sb.toString();
}
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((damageType == null) ? 0 : damageType.hashCode());
- long temp;
- temp = Double.doubleToLongBits(duration);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- result = prime * result + (exclusive ? 1231 : 1237);
- result = prime * result
- + ((graphOverride == null) ? 0 : graphOverride.hashCode());
- result = prime * result + (hasDuration ? 1231 : 1237);
- result = prime * result + (isStatBonus ? 1231 : 1237);
- result = prime * result + (isTransfer ? 1231 : 1237);
- result = prime * result + level;
- temp = Double.doubleToLongBits(maxCount);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- temp = Double.doubleToLongBits(maxPer);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- temp = Double.doubleToLongBits(maxValue);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- temp = Double.doubleToLongBits(minPer);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- temp = Double.doubleToLongBits(minValue);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- result = prime * result + (ownerLevel ? 1231 : 1237);
- temp = Double.doubleToLongBits(pulse);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- temp = Double.doubleToLongBits(range);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- temp = Double.doubleToLongBits(resist);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- temp = Double.doubleToLongBits(soakScale);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- result = prime * result + ((statName == null) ? 0 : statName.hashCode());
- temp = Double.doubleToLongBits(statPercent);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- result = prime * result + ((type == null) ? 0 : type.hashCode());
- result = prime * result + (useGraph ? 1231 : 1237);
- return result;
- }
@Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Effect other = (Effect) obj;
- if (damageType == null) {
- if (other.damageType != null)
- return false;
- } else if (!damageType.equals(other.damageType))
- return false;
- if (Double.doubleToLongBits(duration) != Double.doubleToLongBits(other.duration))
- return false;
- if (exclusive != other.exclusive)
- return false;
- if (graphOverride == null) {
- if (other.graphOverride != null)
- return false;
- } else if (!graphOverride.equals(other.graphOverride))
- return false;
- if (hasDuration != other.hasDuration)
- return false;
- if (isStatBonus != other.isStatBonus)
- return false;
- if (isTransfer != other.isTransfer)
- return false;
- if (level != other.level)
- return false;
- if (Double.doubleToLongBits(maxCount) != Double.doubleToLongBits(other.maxCount))
- return false;
- if (Double.doubleToLongBits(maxPer) != Double.doubleToLongBits(other.maxPer))
- return false;
- if (Double.doubleToLongBits(maxValue) != Double.doubleToLongBits(other.maxValue))
- return false;
- if (Double.doubleToLongBits(minPer) != Double.doubleToLongBits(other.minPer))
- return false;
- if (Double.doubleToLongBits(minValue) != Double.doubleToLongBits(other.minValue))
- return false;
- if (name == null) {
- if (other.name != null)
- return false;
- } else if (!name.equals(other.name))
- return false;
- if (ownerLevel != other.ownerLevel)
- return false;
- if (Double.doubleToLongBits(pulse) != Double.doubleToLongBits(other.pulse))
- return false;
- if (Double.doubleToLongBits(range) != Double.doubleToLongBits(other.range))
- return false;
- if (Double.doubleToLongBits(resist) != Double.doubleToLongBits(other.resist))
- return false;
- if (Double.doubleToLongBits(soakScale)
- != Double.doubleToLongBits(other.soakScale))
- return false;
- if (statName == null) {
- if (other.statName != null)
- return false;
- } else if (!statName.equals(other.statName))
- return false;
- if (Double.doubleToLongBits(statPercent)
- != Double.doubleToLongBits(other.statPercent))
- return false;
- if (type == null) {
- if (other.type != null)
- return false;
- } else if (!type.equals(other.type))
- return false;
- if (useGraph != other.useGraph)
- return false;
- return true;
- }
-
- /**
- * Parse an effect.
+ public int hashCode() {
+ return Objects.hash(duration, fName, group, level, maxCount, maxPer, maxValue,
+ minPer, minValue, pulse, range, resist, soakScale, statPercent);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Effect other = (Effect) obj;
+ return Double.doubleToLongBits(duration)
+ == Double.doubleToLongBits(other.duration)
+ && Objects.equals(fName, other.fName)
+ && Objects.equals(group, other.group) && level == other.level
+ && Double.doubleToLongBits(maxCount)
+ == Double.doubleToLongBits(other.maxCount)
+ && Double.doubleToLongBits(maxPer)
+ == Double.doubleToLongBits(other.maxPer)
+ && Double.doubleToLongBits(maxValue)
+ == Double.doubleToLongBits(other.maxValue)
+ && Double.doubleToLongBits(minPer)
+ == Double.doubleToLongBits(other.minPer)
+ && Double.doubleToLongBits(minValue)
+ == Double.doubleToLongBits(other.minValue)
+ && Double.doubleToLongBits(pulse) == Double.doubleToLongBits(other.pulse)
+ && Double.doubleToLongBits(range) == Double.doubleToLongBits(other.range)
+ && Double.doubleToLongBits(resist)
+ == Double.doubleToLongBits(other.resist)
+ && Double.doubleToLongBits(soakScale)
+ == Double.doubleToLongBits(other.soakScale)
+ && Double.doubleToLongBits(statPercent)
+ == Double.doubleToLongBits(other.statPercent);
+ }
+
+ /** Parse an effect.
+ *
* @param afx The affix the effect belongs to.
* @param scn The scanner to read from.
* @param scnSource The name of the scanner.
+ *
* @return An effect, read from the scanner.
*/
public static Effect parseEffect(Affix afx, Scanner scn, String scnSource) {
return parseEffect(afx, scn, scnSource, new ArrayList<>());
}
- /**
- * Parse an effect.
+ /** Parse an effect.
+ *
* @param afx The affix the effect belongs to.
* @param scn The scanner to read from.
* @param scnSource The name of the scanner.
* @param errs Repository for errors found while parsing.
- * @return An effect, read from the scanner.
- */
+ *
+ * @return An effect, read from the scanner. */
public static Effect parseEffect(Affix afx, Scanner scn, String scnSource, List<String> errs) {
Effect efct = new Effect();
@@ -432,11 +239,11 @@ public class Effect {
if (splits.length == 1) continue;
if (ln.contains("NAME")) {
- efct.name = splits[1];
+ efct.group.name = splits[1];
} else if (ln.contains("DAMAGE_TYPE")) {
- efct.damageType = splits[1];
+ efct.group.damageType = splits[1];
} else if (ln.contains("TYPE")) {
- efct.type = splits[1];
+ efct.group.type = splits[1];
} else if (ln.contains("ACTIVATION")) {
switch (splits[1]) {
case "DYNAMIC":
@@ -446,31 +253,31 @@ public class Effect {
// actual difference.
break;
case "TRANSFER":
- efct.isTransfer = true;
+ efct.group.isTransfer = true;
break;
default:
- errs.add(String.format("Malformed activation type: (%s) (%s) (%s)\n", splits[1], efct.name, afx.intName));
+ errs.add(String.format("Malformed activation type: (%s) (%s) (%s)\n", splits[1], efct.group.name, afx.intName));
}
} else if (ln.contains("DURATION")) {
if (splits[1].equals("ALWAYS")) {
- efct.hasDuration = false;
+ efct.group.hasDuration = false;
efct.duration = Double.POSITIVE_INFINITY;
} else if (splits[1].equals("INSTANT")) {
- efct.hasDuration = false;
+ efct.group.hasDuration = false;
efct.duration = Double.NaN;
} else if (splits[1].equals("PERCENT")) {
- efct.hasDuration = false;
+ efct.group.hasDuration = false;
efct.duration = Double.NaN;
errs.add(String.format("WARN: Punting on DURATION:PERCENT for %s\n", scnSource));
} else if (splits[1].equals("0")) {
- efct.hasDuration = false;
+ efct.group.hasDuration = false;
efct.duration = 0.0;
} else {
- efct.hasDuration = true;
+ efct.group.hasDuration = true;
if (splits[1].equalsIgnoreCase("instant")) {
efct.duration = -1;
@@ -487,19 +294,19 @@ public class Effect {
} else if (ln.contains("LEVEL:")) {
efct.level = Integer.parseInt(splits[1]);
} else if (ln.contains("EXCLUSIVE")) {
- efct.exclusive = Boolean.parseBoolean(splits[1]);
+ efct.group.exclusive = Boolean.parseBoolean(splits[1]);
} else if (ln.contains("GRAPHOVERRIDE")) {
- efct.graphOverride = splits[1];
+ efct.group.graphOverride = splits[1];
} else if (ln.contains("USEOWNERLEVEL")) {
- efct.ownerLevel = Boolean.parseBoolean(splits[1]);
+ efct.group.ownerLevel = Boolean.parseBoolean(splits[1]);
} else if (ln.contains("NOGRAPH")) {
- efct.useGraph = Boolean.parseBoolean(splits[1]);
+ efct.group.useGraph = Boolean.parseBoolean(splits[1]);
} else if (ln.contains("STATNAME")) {
- efct.statName = splits[1];
+ efct.group.statName = splits[1];
} else if (ln.contains("STATPERCENT")) {
efct.statPercent = Double.parseDouble(splits[1]);
} else if (ln.contains("STATMODIFIERISBONUS")) {
- efct.isStatBonus = Boolean.parseBoolean(splits[1]);
+ efct.group.isStatBonus = Boolean.parseBoolean(splits[1]);
} else if (ln.contains("RESISTANCE:")) {
efct.resist = Double.parseDouble(splits[1]);
} else if (ln.contains("FORCE:")) {
@@ -525,13 +332,11 @@ public class Effect {
String fmt = "\t\tProcessed effect %s from %s in %d nanoseconds (%.2f seconds)\n";
double seconds = (((endTime - startTime) / 1000000000));
- errs.add(String.format(fmt, efct.name, scnSource, endTime - startTime, seconds));
+ errs.add(String.format(fmt, efct.group.name, scnSource, endTime - startTime, seconds));
}
effectCount += 1;
return efct;
}
-
-
}
diff --git a/src/main/java/tlIItools/EffectGroup.java b/src/main/java/tlIItools/EffectGroup.java
new file mode 100644
index 00000000..9f4ad49b
--- /dev/null
+++ b/src/main/java/tlIItools/EffectGroup.java
@@ -0,0 +1,120 @@
+package tlIItools;
+
+import java.util.*;
+
+/** An 'effect group'.
+ *
+ * This groups similar effects together, the same way affix groups group affixs
+ * together.
+ *
+ * @author Ben Culkin */
+public class EffectGroup {
+ /** The name of the effect. */
+ public String name;
+ /** The specific effect that happens. */
+ public String type;
+ /** Damage type for the effect, if applicable. */
+ public String damageType = "physical";
+ /** Whether or not we have a duration or not. */
+ public boolean hasDuration;
+ /** The name of the stat that applies to this affect. */
+ public String statName;
+ /** Whether or not this stat is a bonus value. */
+ public boolean isStatBonus;
+ /** Whether or not this uses the owners level to modify any applicable graph. */
+ public boolean ownerLevel;
+ /** Whether or not a graph is used for this effect. */
+ public boolean useGraph = true;
+ /** The graph to use instead of the default graph. */
+ public String graphOverride;
+ /** Whether this effect can stack with itself. */
+ public boolean exclusive;
+ /** Whether or not this effect is a 'transfer' effect (Applied to the enemy on a hit). */
+ public boolean isTransfer;
+
+ public String summary() {
+ StringBuilder sb = new StringBuilder();
+
+ if (isTransfer) sb.append("Transfer: ");
+ sb.append(type);
+ if (name != null && !name.equals("")) {
+ sb.append(" (named ");
+ sb.append(name);
+ sb.append(")");
+ }
+
+ if (hasDuration) sb.append(" (timed)");
+ if (statName != null && !name.equals("")) {
+ sb.append(" (uses stat ");
+ sb.append(statName);
+ if (isStatBonus) sb.append(" as a bonus");
+ sb.append(")");
+ }
+
+ if (ownerLevel) sb.append(" (uses owner level)");
+ if (useGraph) {
+ sb.append(" (uses ");
+ if (graphOverride != null && !graphOverride.equals("")) sb.append(graphOverride);
+ else sb.append("default");
+ sb.append(" graph)");
+ }
+
+ if (exclusive) sb.append(" (exclusive)");
+
+ // @TODO Ben Culkin 12/31/2020 :FancyEffectSummary
+ //
+ // EffectGroups should probably use something from EffectRepo to better
+ // output the summary for a particular group type
+ // String fmt = "%s (name %s, damageType %s, hasDuration %s, stat %s, isBonus %s, ownerLevel %s, useGraph %s, graphOverride %s, exclusive %s, isTransfer %s)";
+
+ // sb.append(String.format(fmt, type, name, damageType, hasDuration, statName, isStatBonus, ownerLevel, useGraph, graphOverride, exclusive, isTransfer));
+
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(name);
+ sb.append(type);
+ sb.append(damageType);
+ sb.append(hasDuration);
+ sb.append(statName);
+ sb.append(isStatBonus);
+ sb.append(ownerLevel);
+ sb.append(graphOverride);
+ sb.append(useGraph);
+ sb.append(exclusive);
+ sb.append(isTransfer);
+
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(damageType, exclusive, graphOverride, hasDuration,
+ isStatBonus, isTransfer, name, ownerLevel, statName, type, useGraph);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+
+ EffectGroup other = (EffectGroup) obj;
+
+ return Objects.equals(damageType, other.damageType)
+ && Objects.equals(graphOverride, other.graphOverride)
+ && Objects.equals(name, other.name)
+ && Objects.equals(statName, other.statName)
+ && Objects.equals(type, other.type)
+ && exclusive == other.exclusive
+ && hasDuration == other.hasDuration
+ && isStatBonus == other.isStatBonus
+ && isTransfer == other.isTransfer
+ && ownerLevel == other.ownerLevel
+ && useGraph == other.useGraph;
+ }
+}
diff --git a/src/main/java/tlIItools/EffectRepo.java b/src/main/java/tlIItools/EffectRepo.java
index f2f0d076..05151a48 100644
--- a/src/main/java/tlIItools/EffectRepo.java
+++ b/src/main/java/tlIItools/EffectRepo.java
@@ -1,40 +1,26 @@
package tlIItools;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Scanner;
+import java.io.*;
+import java.util.*;
import java.util.Map.Entry;
-/**
- * Repository class for storing information needed for parsing/outputing
+/** Repository class for storing information needed for parsing/outputing
* effects.
*
- * @author Ben Culkin
- *
- */
+ * @author Ben Culkin */
public class EffectRepo {
// NOTE: consider making these use function accessors in the future?
// --bculkin, 6/24/20
- /**
- * The list of detail strings for skills.
- */
+
+ /** The list of detail strings for skills. */
public static Map<String, String> detals;
- /**
- * The list of detail strings for timed skills.
- */
+ /** The list of detail strings for timed skills. */
public static Map<String, String> timeDetals;
- /**
- * The list of replacements for detail strings.
- */
+ /** The list of replacements for detail strings. */
public static List<ReplPair> replList;
- /*
- * Init. lists from files.
- */
+ /* Init. lists from files. */
static {
try (FileReader detalReader = new FileReader("data/affix-detals.txt")) {
detals = readDetails(new Scanner(detalReader));
@@ -42,8 +28,7 @@ public class EffectRepo {
AffixLister.errOut.println("Error loading affix detail text");
}
- try (FileReader timedDetalReader
- = new FileReader("data/timed-affix-detals.txt")) {
+ try (FileReader timedDetalReader = new FileReader("data/timed-affix-detals.txt")) {
timeDetals = readDetails(new Scanner(timedDetalReader));
} catch (IOException ioex) {
AffixLister.errOut.println("Error loading timed affix detail text");
@@ -56,36 +41,31 @@ public class EffectRepo {
}
}
- /**
- * Read effect detail strings from an input source.
+ /** Read effect detail strings from an input source.
+ *
+ * @param scn The source to read from.
*
- * @param scn
- * The source to read from.
- * @return The map of effect details to use.
- */
+ * @return The map of effect details to use. */
public static Map<String, String> readDetails(Scanner scn) {
Map<String, String> detalMap = new HashMap<>();
return readDetails(detalMap, scn);
}
- /**
- * Read effect detail strings from an input source, adding to an existing set.
+ /** Read effect detail strings from an input source, adding to an existing set.
+ *
+ * @param detalMap The details to add to.
+ * @param scn The source to read from.
*
- * @param detalMap
- * The details to add to.
- * @param scn
- * The source to read from.
- * @return The map of effect details to use.
- */
- public static Map<String, String> readDetails(Map<String, String> detalMap,
- Scanner scn) {
+ * @return The map of effect details to use. */
+ public static Map<String, String> readDetails(
+ Map<String, String> detalMap, Scanner scn)
+ {
while (scn.hasNextLine()) {
String name = scn.nextLine().trim();
- if (name.equals(""))
- continue;
- if (name.startsWith("#"))
- continue;
+
+ if (name.equals("")) continue;
+ if (name.startsWith("#")) continue;
String body;
do {
@@ -98,18 +78,17 @@ public class EffectRepo {
return detalMap;
}
- /**
- * Sanity check the loaded format strings.
- */
+ /** Sanity check the loaded format strings. */
public static void sanityCheckFormats() {
for (Entry<String, String> detal : detals.entrySet()) {
String fmt = detal.getValue();
- AffixLister.errOut.printf("\tTRACE: Applying replacements for %s\n",
- detal.getKey());
+ AffixLister.errOut.printf("\tTRACE: Applying replacements for %s\n", detal.getKey());
+
for (ReplPair repl : replList) {
String tmp = fmt;
fmt = fmt.replaceAll(repl.find, repl.replace);
+
if (!fmt.equals(tmp)) {
String outFmt = "\t\tTRACE: Replaced %s with %s: \n\t\t%s\n\t\t%s\n";
@@ -118,8 +97,7 @@ public class EffectRepo {
}
if (fmt.contains("<") || fmt.contains(">")) {
- String warnFmt
- = "WARN: Details for effect %s are malformated (contains < or >):\n\t%s\n";
+ String warnFmt = "WARN: Details for effect %s are malformated (contains < or >):\n\t%s\n";
AffixLister.errOut.printf(warnFmt, detal.getKey(), fmt);
}
@@ -133,8 +111,7 @@ public class EffectRepo {
}
if (fmt.contains("<") || fmt.contains(">")) {
- String warnFmt
- = "WARN: Details for timed effect %s are malformatted (contains < or >):\n\t%s\n";
+ String warnFmt = "WARN: Details for timed effect %s are malformatted (contains < or >):\n\t%s\n";
AffixLister.errOut.printf(warnFmt, detal.getKey(), fmt);
}
}
diff --git a/src/main/java/tlIItools/LevelRange.java b/src/main/java/tlIItools/LevelRange.java
new file mode 100644
index 00000000..b0d620bf
--- /dev/null
+++ b/src/main/java/tlIItools/LevelRange.java
@@ -0,0 +1,135 @@
+package tlIItools;
+
+import java.util.*;
+
+public class LevelRange implements Comparable<LevelRange> {
+ /*
+ * if (minLevel <= 1 && maxLevel == 999) {
+ * sb.append("No Level Range");
+ * } else if (minLevel != 1 && maxLevel != 999) {
+ * sb.append("Level Range: ");
+ * sb.append(minLevel);
+ * sb.append("-");
+ * sb.append(maxLevel);
+ * } else if (minLevel <= 1) {
+ * sb.append("Max Level: ");
+ * sb.append(maxLevel);
+ * } else if (maxLevel == 999) {
+ * sb.append("Minimum Level: ");
+ * sb.append(minLevel);
+ * } */
+
+ public int minLevel;
+ public int maxLevel;
+
+ public LevelRange() {
+ minLevel = 1;
+ maxLevel = 999;
+ }
+
+ public LevelRange(int minLevel, int maxLevel) {
+ this.minLevel = minLevel;
+ this.maxLevel = maxLevel;
+ }
+
+ private void clamp() {
+ minLevel = Math.max(1, minLevel);
+ maxLevel = Math.min(999, maxLevel);
+ }
+
+ public boolean isUnrestricted() {
+ return minLevel <= 1 && maxLevel >= 999;
+ }
+
+ public boolean noLowerBound() {
+ return minLevel <= 1;
+ }
+
+ public boolean noUpperBound() {
+ return maxLevel >= 999;
+ }
+
+ @Override
+ public String toString() {
+ clamp();
+
+ StringBuilder sb = new StringBuilder();
+
+ if (minLevel <= 1 && maxLevel >= 999) {
+ sb.append("No Level Range");
+ } else if (minLevel > 1 && maxLevel < 999) {
+ sb.append("Level Range: ");
+ sb.append(minLevel);
+ sb.append("-");
+ sb.append(maxLevel);
+ } else if (minLevel <= 1) {
+ sb.append("Max Level: ");
+ sb.append(maxLevel);
+ } else if (maxLevel >= 999) {
+ sb.append("Minimum Level: ");
+ sb.append(minLevel);
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ clamp();
+
+ return Objects.hash(maxLevel, minLevel);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+
+ LevelRange other = (LevelRange) obj;
+
+ clamp();
+ other.clamp();
+
+ if (isUnrestricted() && other.isUnrestricted()) {
+ return true;
+ } else if (noLowerBound()) {
+ if (other.noLowerBound()) return maxLevel == other.maxLevel;
+ else return false;
+ } else if (noUpperBound()) {
+ if (other.noUpperBound()) return minLevel == other.minLevel;
+ else return false;
+ } else {
+ return maxLevel == other.maxLevel && minLevel == other.minLevel;
+ }
+ }
+
+ @Override
+ public int compareTo(LevelRange other) {
+ clamp();
+ other.clamp();
+
+ if (this.equals(other)) return 0;
+
+ // Unrestricted ranges sort above all others
+ if (isUnrestricted()) return 1;
+ if (other.isUnrestricted()) return -1;
+
+ if (noLowerBound()) {
+ if (other.noLowerBound()) {
+ return maxLevel - other.maxLevel;
+ } else {
+ return -1;
+ }
+ } else if (noUpperBound()) {
+ if (other.noUpperBound()) {
+ return minLevel - other.minLevel;
+ } else {
+ return 1;
+ }
+ } else {
+ if (minLevel == other.minLevel) return maxLevel - other.maxLevel;
+ else return minLevel - other.minLevel;
+ }
+ }
+}
diff --git a/src/main/java/tlIItools/Main.java b/src/main/java/tlIItools/Main.java
index 234f0bd3..a4d09bff 100644
--- a/src/main/java/tlIItools/Main.java
+++ b/src/main/java/tlIItools/Main.java
@@ -1,6 +1,12 @@
package tlIItools;
+/** Main method for TLIITools
+ *
+ * @author Ben Culkin */
public class Main {
+ /** Main method.
+ *
+ * @param args Unused CLI args. */
public static void main(String[] args) {
// TODO implement this
}
diff --git a/src/main/java/tlIItools/NameFileReader.java b/src/main/java/tlIItools/NameFileReader.java
index 87407162..a9646942 100644
--- a/src/main/java/tlIItools/NameFileReader.java
+++ b/src/main/java/tlIItools/NameFileReader.java
@@ -1,113 +1,71 @@
package tlIItools;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.io.Reader;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Scanner;
-
-/**
- * Reads in a list of file names to process.
+import java.io.*;
+
+import java.util.*;
+
+/** Reads in a list of file names to process.
*
- * @author Ben Culkin
- */
+ * @author Ben Culkin */
public class NameFileReader {
- /**
- * Are we attempting to guess group names?
- */
+ /** Are we attempting to guess group names? */
public boolean guessGroups;
-
- /**
- * Regex to use for guessing group names.
- */
+ /** Regex to use for guessing group names. */
public String groupRx;
-
- /**
- * The default group to put files into.
- */
+ /** The default group to put files into. */
public String defGroup;
-
- /**
- * The map of file groups.
- */
+ /** The map of file groups. */
public Map<String, List<String>> fNames;
- /*
- * The current group.
- */
+ /* The current group. */
private String curGroup;
- /*
- * The list of files for the current group.
- */
+ /* The list of files for the current group. */
private List<String> curList;
- /**
- * Counts the files read in.
- */
+ /** Counts the files read in. */
public int fCount;
+ /** Stream to write normal output to. */
public PrintStream normOut = System.out;
+ /** Stream to write error output to. */
public PrintStream errOut = System.err;
- /**
- * Create a new name reader using the default settings.
+ /** Create a new name reader using the default settings.
*
- * Guessing groups is disabled by default.
- */
+ * Guessing groups is disabled by default. */
public NameFileReader() {
this(false);
}
- /**
- * Create a new name reader using the default settings.
+ /** Create a new name reader using the default settings.
*
- * @param guessGroups
- * Controls whether or not to try to guess file groups from file
- * names.
- */
+ * @param guessGroups Controls whether or not to try to guess file groups from file names. */
public NameFileReader(boolean guessGroups) {
this(new HashMap<>(), "default", guessGroups);
}
- /**
- * Create a new name reader using the specified settings.
- *
- * @param fNames
- * The set of groups to add files to.
+ /** Create a new name reader using the specified settings.
*
- * @param defGroup
- * The name of the default file group.
- *
- * @param guessGroups
- * Whether or not to attempt to guess group names.
- */
+ * @param fNames The set of groups to add files to.
+ * @param defGroup The name of the default file group.
+ * @param guessGroups Whether or not to attempt to guess group names. */
public NameFileReader(Map<String, List<String>> fNames, String defGroup, boolean guessGroups) {
- if (!fNames.containsKey(defGroup))
- fNames.put(defGroup, new ArrayList<>());
+ if (!fNames.containsKey(defGroup)) fNames.put(defGroup, new ArrayList<>());
this.fNames = fNames;
- this.defGroup = defGroup;
-
+ this.defGroup = defGroup;
this.guessGroups = guessGroups;
+ this.curGroup = defGroup;
- this.curGroup = defGroup;
- this.curList = fNames.get(curGroup);
+ this.curList = fNames.get(curGroup);
this.fCount = 0;
}
- /**
- * Read in file names from a file.
+ /** Read in file names from a file.
*
- * @param from
- * The name of the file to read from.
- */
+ * @param from The name of the file to read from. */
public void readFrom(String from) {
try (FileReader fr = new FileReader(from)) {
readFrom(fr);
@@ -118,13 +76,9 @@ public class NameFileReader {
}
}
- /**
- * Read in file names from an input source.
- *
- * @param r
- * The input source to read from.
+ /** Read in file names from an input source.
*
- */
+ * @param r The input source to read from. */
public void readFrom(Reader r) {
Scanner scn = new Scanner(r);
@@ -153,12 +107,9 @@ public class NameFileReader {
scn.close();
}
- /**
- * Swap to a new file group.
+ /** Swap to a new file group.
*
- * @param groupName
- * The name of the group to swap to.
- */
+ * @param groupName The name of the group to swap to. */
public void swapGroup(String groupName) {
curGroup = groupName;
@@ -171,12 +122,19 @@ public class NameFileReader {
}
}
+ /** Add a file to this file reader.
+ *
+ * @param fName The file to add. */
public void addFile(String fName) {
curList.add(fName);
fCount += 1;
}
-
+
+ /** Add a file to this file reader.
+ *
+ * @param groupName The group to add the file to.
+ * @param fName The file to add. */
public void addFile(String groupName, String fName) {
fNames.computeIfAbsent(groupName, (key) -> new ArrayList<>()).add(fName);
diff --git a/src/main/java/tlIItools/ReplPair.java b/src/main/java/tlIItools/ReplPair.java
index 74012716..90717a0a 100644
--- a/src/main/java/tlIItools/ReplPair.java
+++ b/src/main/java/tlIItools/ReplPair.java
@@ -1,51 +1,31 @@
package tlIItools;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Scanner;
+import java.util.*;
-/**
- * String pairs for replacements.
+/** String pairs for replacements.
*
- * @author Ben Culkin
- */
+ * @author Ben Culkin */
public class ReplPair implements Comparable<ReplPair> {
- /**
- * Represents an error encountered parsing ReplPairs
+ /** Represents an error encountered parsing ReplPairs
*
- * @author Ben Culkin
- */
+ * @author Ben Culkin */
public static class ReplError {
- /**
- * The line the error occured on.
- */
+ /** The line the error occured on. */
public int line;
- /**
- * The number of pairs we have processed so far.
- */
+ /** The number of pairs we have processed so far. */
public int numPairs;
- /**
- * The text of the line we errored on.
- */
+ /** The text of the line we errored on. */
public String txt;
- /**
- * The message of the error.
- */
+ /** The message of the error. */
public String msg;
- /**
- * Create a new ReplPair parse error.
+ /** Create a new ReplPair parse error.
*
- * @param lne
- * The line the error occured on.
- * @param nPairs
- * The number of pairs processed up to this point.
- * @param msg
- * The message detailing the error.
- * @param txt
- * The text that caused the error.
- */
+ * @param lne The line the error occured on.
+ * @param nPairs The number of pairs processed up to this point.
+ * @param msg The message detailing the error.
+ * @param txt The text that caused the error. */
public ReplError(int lne, int nPairs, String msg, String txt) {
line = lne;
numPairs = nPairs;
@@ -65,86 +45,56 @@ public class ReplPair implements Comparable<ReplPair> {
}
}
- /**
- * The priority for this replacement.
- */
+ /** The priority for this replacement. */
public int priority;
-
- /**
- * The name of this replacement.
+ /** The name of this replacement.
*
- * Defaults to the 'find' string.
- */
+ * Defaults to the 'find' string. */
public String name;
- /**
- * The string to look for.
- */
+ /** The string to look for. */
public String find;
-
- /**
- * The string to replace it with.
- */
+ /** The string to replace it with. */
public String replace;
- /**
- * Create a new blank replacement pair.
- */
+ /** Create a new blank replacement pair. */
public ReplPair() {
this("", "", 1, null);
}
- /**
- * Create a new replacement pair with a priority of 1.
+ /** Create a new replacement pair with a priority of 1.
*
- * @param f
- * The string to find.
- * @param r
- * The string to replace.
+ * @param f The string to find.
+ * @param r The string to replace.
*/
public ReplPair(String f, String r) {
this(f, r, 1);
}
- /**
- * Create a new named replacement pair with a priority of 1.
+ /** Create a new named replacement pair with a priority of 1.
*
- * @param f
- * The string to find.
- * @param r
- * The string to replace.
- * @param n
- * The name of the replacement pair.
+ * @param f The string to find.
+ * @param r The string to replace.
+ * @param n The name of the replacement pair.
*/
public ReplPair(String f, String r, String n) {
this(f, r, 1, n);
}
- /**
- * Create a new replacement pair with a set priority.
+ /** Create a new replacement pair with a set priority.
*
- * @param f
- * The string to find.
- * @param r
- * The string to replace.
- * @param p
- * The priority for the replacement.
- */
+ * @param f The string to find.
+ * @param r The string to replace.
+ * @param p The priority for the replacement. */
public ReplPair(String f, String r, int p) {
this(f, r, p, f);
}
- /**
- * Create a new replacement pair with a set priority and name.
+ /** Create a new replacement pair with a set priority and name.
*
- * @param f
- * The string to find.
- * @param r
- * The string to replace.
- * @param n
- * The name of the replacement pair.
- * @param p
- * The priority for the replacement.
- */
+ * @param f The string to find.
+ * @param r The string to replace.
+ * @param n The name of the replacement pair.
+ * @param p The priority for the replacement. */
public ReplPair(String f, String r, int p, String n) {
find = f;
replace = r;
@@ -153,29 +103,23 @@ public class ReplPair implements Comparable<ReplPair> {
priority = p;
}
- /**
- * Read a list of replacement pairs from an input source.
+
+ /** Read a list of replacement pairs from an input source.
*
- * @param scn
- * The source to read the replacements from.
- * @return
- * The list of replacements.
- */
+ * @param scn The source to read the replacements from.
+ *
+ * @return The list of replacements. */
public static List<ReplPair> readList(Scanner scn) {
return ReplPair.readList(new ArrayList<>(), scn);
}
- /**
- * Read a list of replacement pairs from an input source, adding them to
+ /** Read a list of replacement pairs from an input source, adding them to
* an existing list.
*
- * @param detals
- * The list to add the replacements to.
- * @param scn
- * The source to read the replacements from.
- * @return
- * The list of replacements.
- */
+ * @param detals The list to add the replacements to.
+ * @param scn The source to read the replacements from.
+ *
+ * @return The list of replacements. */
public static List<ReplPair> readList(List<ReplPair> detals, Scanner scn) {
List<ReplError> errList = new ArrayList<>();
@@ -186,25 +130,22 @@ public class ReplPair implements Comparable<ReplPair> {
if (errList.size() == 0) errString = "An error";
else errString = "Errors";
- throw new IllegalArgumentException(String.format("%s occured parsing replacement pairs:\n%s", errString, errList));
+ throw new IllegalArgumentException(String.format(
+ "%s occured parsing replacement pairs:\n%s",
+ errString, errList));
}
return rplPar;
}
- /**
- * Read a list of replacement pairs from an input source, adding them to
+ /** Read a list of replacement pairs from an input source, adding them to
* an existing list.
*
- * @param detals
- * The list to add the replacements to.
- * @param scn
- * The source to read the replacements from.
- * @param errs
- * The list to stick errors in.
- * @return
- * The list of replacements.
- */
+ * @param detals The list to add the replacements to.
+ * @param scn The source to read the replacements from.
+ * @param errs The list to stick errors in.
+ *
+ * @return The list of replacements. */
public static List<ReplPair> readList(List<ReplPair> detals, Scanner scn, List<ReplError> errs) {
int lno = 0;
int pno = 0;
@@ -236,8 +177,7 @@ public class ReplPair implements Comparable<ReplPair> {
// Read in the next uncommented line
do {
if (!scn.hasNextLine()) {
- String msg =
- "Ran out of input looking for replacement body for raw name " + name;
+ String msg = "Ran out of input looking for replacement body for raw name " + name;
errs.add(new ReplError(lno, pno, msg, null));
break;
@@ -247,7 +187,6 @@ public class ReplPair implements Comparable<ReplPair> {
lno += 1;
} while (body.startsWith("#"));
-
rp.replace = body;
resList.add(rp);