summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin J. Culkin <bjculkin@mix.wvu.edu>2019-01-17 18:33:14 -0400
committerBenjamin J. Culkin <bjculkin@mix.wvu.edu>2019-01-17 18:33:14 -0400
commit8c613819790ae737150a9ad8bb82332a1aaab690 (patch)
tree03fd2180f3685ddfe6265568b542e18dae8b9280
parent45e6547632957bfa5b806825eaebd6c0f8bdb736 (diff)
Refactor AffixLister
AffixLister got refactored some more, in preparation for adding the ability to load things that aren't affixes.
-rwxr-xr-xgenafx-test.sh2
-rw-r--r--pom.xml2
-rw-r--r--src/main/java/tlIItools/Affix.java98
-rw-r--r--src/main/java/tlIItools/AffixLister.java314
-rw-r--r--src/main/java/tlIItools/AffixSet.java34
-rw-r--r--src/main/java/tlIItools/Effect.java129
-rw-r--r--src/main/java/tlIItools/Main.java7
-rw-r--r--src/main/java/tlIItools/NameFileReader.java190
8 files changed, 526 insertions, 250 deletions
diff --git a/genafx-test.sh b/genafx-test.sh
index 4f9726f9..06ee634f 100755
--- a/genafx-test.sh
+++ b/genafx-test.sh
@@ -5,7 +5,7 @@ set -e
baseout="$1"
shift 1
fileset="$@"
-listopts="-z -n named"
+listopts="-l -z -n named"
outputfle=output/"$baseout".txt
errfle=output/"$baseout".err
outputopts="-o $outputfle -e $errfle"
diff --git a/pom.xml b/pom.xml
index 19eeb12d..8d680350 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,7 +43,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <main.class>AffixLister</main.class>
+ <main.class>tlIItools.AffixLister</main.class>
</properties>
<dependencies>
diff --git a/src/main/java/tlIItools/Affix.java b/src/main/java/tlIItools/Affix.java
index 424b2dad..8b1c2b03 100644
--- a/src/main/java/tlIItools/Affix.java
+++ b/src/main/java/tlIItools/Affix.java
@@ -2,12 +2,17 @@ package tlIItools;
import java.util.ArrayList;
import java.util.List;
+import java.util.Scanner;
/**
* Represents a Torchlight II affix.
*/
public class Affix {
/**
+ * Whether or not to record timing info.
+ */
+ public static boolean doTiming;
+ /**
* Internal name of the affix.
*/
public String intName;
@@ -18,7 +23,7 @@ public class 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.
+ * may need to be changed in their files.
*/
public String affixSuffix;
public String affixPrefix;
@@ -129,6 +134,10 @@ public class Affix {
@Override
public String toString() {
+ return intName;
+ }
+
+ public String toLongString() {
StringBuilder sb = new StringBuilder();
if (isSocketable) sb.append("Socketable ");
else if (isPerson || (intName != null && intName.startsWith("HERO_"))) sb.append("Personal ");
@@ -165,8 +174,7 @@ public class Affix {
sb.append("Max Level: ");
sb.append(maxLevel);
} else if (maxLevel == 999) {
- sb.append("Minimum Level: ");
- sb.append(minLevel);
+ sb.append("Minimum Level: "); sb.append(minLevel);
}
sb.append("\n");
@@ -221,4 +229,88 @@ public class Affix {
return sb.toString();
}
+
+ /**
+ * Load an affix from an input source.
+ *
+ * @param scn
+ * The input source to load from.
+ *
+ * @param fName
+ * The name of the input source in question.
+ *
+ * @return
+ * The loaded affix.
+ */
+ public static Affix loadAffix(Scanner scn, String fName) {
+ return loadAffix(scn, fName, new ArrayList<>());
+ }
+
+ public static Affix loadAffix(Scanner scn, String scnName, List<String> errors) {
+ Affix afx = new Affix();
+
+ long startTime = System.nanoTime();
+
+ while (scn.hasNextLine()) {
+ String ln = scn.nextLine();
+ ln = ln.replaceAll("\\p{Cntrl}", "");
+
+ if (ln.contains("[NOT_UNITTYPES]")) {
+ afx.setEquipType(true);
+ continue;
+ } else if (ln.contains("[UNITTYPES]")) {
+ afx.setEquipType(false);
+ continue;
+ }
+
+ String[] splits = ln.split(":");
+ if (ln.contains("<TRANSLATE>")) {
+ splits[0] = splits[0].substring(11);
+
+ switch (splits[0]) {
+ case "SUFFIX":
+ afx.affixSuffix = splits[1];
+ break;
+ case "PREFIX":
+ afx.affixPrefix = splits[1];
+ break;
+ default:
+ errors.add(String.format("Misformed affix translation: (%s) (%s) (%s)\n", splits[0], splits[1], scnName));
+ }
+ } else if (ln.contains("MIN_SPAWN_RANGE")) {
+ afx.minLevel = Integer.parseInt(splits[1]);
+ } else if (ln.contains("MAX_SPAWN_RANGE")) {
+ afx.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", 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));
+ afx.intName = splits[1];
+ } else if (ln.contains("[EFFECT]")) {
+ List<String> eftErrs = new ArrayList<>();
+
+ Effect eft = Effect.parseEffect(afx, scn, scnName, errors);
+ errors.addAll(eftErrs);
+
+ afx.effects.add(eft);
+ }
+ }
+
+ long endTime = System.nanoTime();
+ if (doTiming) {
+ 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));
+ }
+
+ return afx;
+ }
}
diff --git a/src/main/java/tlIItools/AffixLister.java b/src/main/java/tlIItools/AffixLister.java
index 27ea0c70..76e93996 100644
--- a/src/main/java/tlIItools/AffixLister.java
+++ b/src/main/java/tlIItools/AffixLister.java
@@ -19,15 +19,24 @@ import java.util.Set;
* @author Ben Culkin
*/
public class AffixLister {
+ /**
+ * Count of effects this class has loaded.
+ */
private static int effectCount = 0;
- private static boolean doTiming = false;
+ /**
+ * Should the class record timing data?
+ */
+ public static boolean doTiming = false;
/**
* Should the file name be attached to things?
*/
public static boolean addFileName = false;
+ /**
+ * Output streams to use.
+ */
public static PrintStream normOut = System.out;
public static PrintStream errOut = System.err;
@@ -49,55 +58,24 @@ public class AffixLister {
NAMED;
}
- private static int readNamesFromFile(Map<String, List<String>> fNames, String from, String defGroup, boolean guessGroups) {
- int numFiles = 0;
- try (FileReader fr = new FileReader(from)) {
- Scanner scn = new Scanner(fr);
-
- String curGroup = defGroup;
- List<String> curList = fNames.get(curGroup);
-
- while (scn.hasNextLine()) {
- String ln = scn.nextLine();
-
- if (ln.startsWith("#")) {
- curGroup = ln.substring(1);
-
- if (!fNames.containsKey(curGroup)) {
- curList = new ArrayList<>();
- fNames.put(curGroup, curList);
- } else {
- curList = fNames.get(curGroup);
- }
- } else if (guessGroups && ln.contains("/mods/")) {
- curGroup = ln.replaceAll(".*/mods/([^/]+)/*", "$1");
-
- if (!fNames.containsKey(curGroup)) {
- curList = new ArrayList<>();
- fNames.put(curGroup, curList);
- } else {
- curList = fNames.get(curGroup);
- }
- } else {
- numFiles += 1;
- curList.add(ln);
- }
- }
- } catch (IOException ioex) {
- errOut.printf("Error reading names from file %s\n", from);
- ioex.printStackTrace(errOut);
- errOut.println();
- }
-
- return numFiles;
- }
-
/**
* Main method.
*
* @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.
+ *
+ * @param args
+ * The names of the files to read affix data from.
+ */
+ public static AffixSet listAffixes(String[] args) {
+ AffixSet afst = new AffixSet();
+
boolean doingArgs = true;
boolean omitZeros = false;
@@ -106,26 +84,22 @@ public class AffixLister {
NameMode nameMode = NameMode.ALL;
- long startTime = System.nanoTime();
-
- int fCount = 0;
-
int namedCount = 0;
int unnamedCount = 0;
int zeroCount = 0;
int groupCount = 0;
- Map<String, List<String>> groupContents = new HashMap<>();
+ Map<String, List<Affix>> groupContents = afst.affixGroups;
- List<String> nonGroupContents = new ArrayList<>();
+ List<Affix> nonGroupContents = afst.ungroupedAffixes;
int argCount = 0;
- Map<String, List<String>> fGroups = new HashMap<>();
- List<String> fNames = new ArrayList<>();
+ NameFileReader nfr = new NameFileReader(false);
+ nfr.groupRx = ".*/mods/([^/]+)/*";
+
+ long startTime = System.nanoTime();
- String curGroup = "default";
- fGroups.put(curGroup, fNames);
for(int i = 0; i < args.length; i++) {
String fName = args[i];
@@ -154,10 +128,12 @@ public class AffixLister {
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":
@@ -175,6 +151,7 @@ public class AffixLister {
}
nameMode = NameMode.valueOf(args[++i].toUpperCase());
+
break;
case "--file-group":
case "-g":
@@ -183,19 +160,16 @@ public class AffixLister {
break;
}
- curGroup = args[++i];
- if (fGroups.containsKey(curGroup)) {
- fNames = fGroups.get(curGroup);
- } else {
- fNames = new ArrayList<>();
- fGroups.put(curGroup, fNames);
- }
+ nfr.swapGroup(args[++i]);
+
break;
case "--guess-groups":
- guessGroups = true;
+ nfr.guessGroups = true;
+
break;
case "--no-guess-groups":
- guessGroups = false;
+ nfr.guessGroups = false;
+
break;
case "--read-names-from-file":
case "-r":
@@ -204,7 +178,8 @@ public class AffixLister {
break;
}
- fCount += readNamesFromFile(fGroups, args[++i], curGroup, guessGroups);
+ nfr.readFrom(args[++i]);
+
break;
case "--output":
case "-o":
@@ -212,13 +187,17 @@ public class AffixLister {
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);
}
+
break;
case "--output-errors":
case "-e":
@@ -226,13 +205,26 @@ public class AffixLister {
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);
}
+
+ 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];
+
break;
default:
isArg = false;
@@ -240,25 +232,25 @@ public class AffixLister {
if (isArg) {
argCount += 1;
+
continue;
}
- fCount += 1;
- fNames.add(fName);
+ nfr.addFile(fName);
} else {
- fCount += 1;
- fNames.add(fName);
+ nfr.addFile(fName);
}
}
- for (Entry<String, List<String>> fGroup : fGroups.entrySet()) {
+ 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)) {
Scanner sc = new Scanner(fr);
- Affix afx = processFile(sc, fName);
+ Affix afx = Affix.loadAffix(sc, fName);
+ effectCount += afx.effects.size();
if (afx.intName != null && afx.weight != 0) {
String groupRx = "(.*_?)\\d+\\Z";
@@ -274,12 +266,12 @@ public class AffixLister {
groupContents.put(groupName, new ArrayList<>());
} else {
- nonGroupContents.add(afx.intName);
+ nonGroupContents.add(afx);
}
} else if (hasGroup) {
- groupContents.get(groupName).add(afx.intName);
+ groupContents.get(groupName).add(afx);
} else {
- nonGroupContents.add(afx.intName);
+ nonGroupContents.add(afx);
}
}
@@ -297,7 +289,7 @@ public class AffixLister {
if (nameMode == NameMode.UNNAMED && isNamed) continue;
if (nameMode == NameMode.NAMED && !isNamed) continue;
- normOut.printf("\n%s\n", afx.toString());
+ normOut.printf("\n%s\n", afx.toLongString());
}
} catch (Exception ex) {
errOut.printf("Something bad happened for file %s:%s\n", fName, ex.getMessage());
@@ -311,184 +303,16 @@ public class AffixLister {
}
errOut.println("\nGroup Contents: ");
- for (Entry<String, List<String>> ent: groupContents.entrySet()) {
+ for (Entry<String, List<Affix>> ent: groupContents.entrySet()) {
errOut.printf("\t%s: %s\n", ent.getKey(), ent.getValue());
}
errOut.println();
errOut.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", fCount, namedCount, unnamedCount, zeroCount, effectCount, groupCount, groupContents.size(), nonGroupContents.size(), fCount, fGroups.size(), endTime - startTime, ((double)(endTime - startTime) / 1000000000));
+ 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);
- }
-
- // Process an affix file
- private static Affix processFile(Scanner scn, String fName) {
- Affix afx = new Affix();
-
- long startTime = System.nanoTime();
-
- while (scn.hasNextLine()) {
- String ln = scn.nextLine();
- ln = ln.replaceAll("\\p{Cntrl}", "");
-
- if (ln.contains("[NOT_UNITTYPES]")) {
- afx.setEquipType(true);
- continue;
- } else if (ln.contains("[UNITTYPES]")) {
- afx.setEquipType(false);
- continue;
- }
-
- String[] splits = ln.split(":");
- if (ln.contains("<TRANSLATE>")) {
- splits[0] = splits[0].substring(11);
-
- switch (splits[0]) {
- case "SUFFIX":
- afx.affixSuffix = splits[1];
- break;
- case "PREFIX":
- afx.affixPrefix = splits[1];
- break;
- default:
- errOut.printf("Misformed affix translation: (%s) (%s) (%s)\n", splits[0], splits[1], fName);
- }
- } else if (ln.contains("MIN_SPAWN_RANGE")) {
- afx.minLevel = Integer.parseInt(splits[1]);
- } else if (ln.contains("MAX_SPAWN_RANGE")) {
- afx.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)
- errOut.printf("Malformed equip type: (%s) (%s)\n", splits[0], fName);
- afx.addEquipType(splits[1]);
- } else if (splits[0].equals("<STRING>NAME")) {
- if (splits.length == 1)
- errOut.printf("Malformed name: (%s) (%s)\n", splits[0], fName);
- afx.intName = splits[1];
- } else if (ln.contains("[EFFECT]")) {
- afx.effects.add(parseEffect(afx, scn, fName));
- }
- }
-
- long endTime = System.nanoTime();
- if (doTiming) errOut.printf("\tProcessed affix %s from %s in %d nanoseconds (%.2f seconds)\n\n", afx.intName, fName, endTime - startTime, ((double)(endTime - startTime) / 1000000000));
-
- return afx;
- }
-
- private static Effect parseEffect(Affix afx, Scanner scn, String fName) {
- Effect efct = new Effect();
-
- long startTime = System.nanoTime();
-
- efct.fName = fName;
-
- while (scn.hasNextLine()) {
- String ln = scn.nextLine();
- ln = ln.replaceAll("\\p{Cntrl}", "");
-
- if (ln.contains("[/EFFECT]")) break;
-
- String[] splits = ln.split(":");
-
- // Empty field
- if (splits.length == 1) continue;
-
- if (ln.contains("NAME")) {
- efct.name = splits[1];
- } else if (ln.contains("DAMAGE_TYPE")) {
- efct.damageType = splits[1];
- } else if (ln.contains("TYPE")) {
- efct.type = splits[1];
- } else if (ln.contains("ACTIVATION")) {
- switch (splits[1]) {
- case "DYNAMIC":
- case "PASSIVE":
- // Passive is the default, and
- // dynamic doesn't have much
- // actual difference.
- break;
- case "TRANSFER":
- efct.isTransfer = true;
- break;
- default:
- errOut.printf("Malformed activation type: (%s) (%s) (%s)\n", splits[1], efct.name, afx.intName);
- }
- } else if (ln.contains("DURATION")) {
- if (splits[1].equals("ALWAYS")) {
- efct.hasDuration = false;
-
- efct.duration = Double.POSITIVE_INFINITY;
- } else if (splits[1].equals("INSTANT")) {
- efct.hasDuration = false;
-
- efct.duration = Double.NaN;
- } else if (splits[1].equals("PERCENT")) {
- efct.hasDuration = false;
-
- efct.duration = Double.NaN;
-
- errOut.printf("WARN: Punting on DURATION:PERCENT for %s\n", fName);
- } else if (splits[1].equals("0")) {
- efct.hasDuration = false;
- efct.duration = 0.0;
- } else {
- efct.hasDuration = true;
-
- efct.duration = Double.parseDouble(splits[1]);
- }
- } else if (ln.contains("<FLOAT>MIN:")) {
- efct.minValue = Double.parseDouble(splits[1]);
- } else if (ln.contains("<FLOAT>MAX:")) {
- efct.maxValue = Double.parseDouble(splits[1]);
- } else if (ln.contains("USEOWNERLEVEL")) {
- // We don't care about this, for now
- } else if (ln.contains("LEVEL:")) {
- efct.level = Integer.parseInt(splits[1]);
- } else if (ln.contains("EXCLUSIVE")) {
- efct.exclusive = Boolean.parseBoolean(splits[1]);
- } else if (ln.contains("GRAPHOVERRIDE")) {
- efct.graphOverride = splits[1];
- } else if (ln.contains("USEOWNERLEVEL")) {
- efct.ownerLevel = Boolean.parseBoolean(splits[1]);
- } else if (ln.contains("NOGRAPH")) {
- efct.useGraph = Boolean.parseBoolean(splits[1]);
- } else if (ln.contains("STATNAME")) {
- efct.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]);
- } else if (ln.contains("RESISTANCE:")) {
- efct.resist = Double.parseDouble(splits[1]);
- } else if (ln.contains("FORCE:")) {
- efct.resist = Double.parseDouble(splits[1]);
- } else if (ln.contains("MIN_PER")) {
- efct.minPer = Double.parseDouble(splits[1]);
- } else if (ln.contains("MAX_PER")) {
- efct.maxPer = Double.parseDouble(splits[1]);
- } else if (ln.contains("RANGE:") || ln.contains("RADIUS")) {
- efct.range = Double.parseDouble(splits[1]);
- } else if (ln.contains("MAX_COUNT:") || ln.contains("MAX_TARGETS")) {
- efct.maxCount = Double.parseDouble(splits[1]);
- } else if (ln.contains("PULSE_RATE")) {
- efct.pulse = Double.parseDouble(splits[1]);
- } else if (ln.contains("CHANCE:")) {
- // NOTE: Should really use its own field
- efct.resist = Double.parseDouble(splits[1]);
- }
- }
-
- long endTime = System.nanoTime();
- if (doTiming) errOut.printf("\t\tProcessed effect %s from %s in %d nanoseconds (%.2f seconds)\n", efct.name, fName, endTime - startTime, ((double)((endTime - startTime) / 1000000000)));
-
- effectCount += 1;
- return efct;
+ return afst;
}
}
diff --git a/src/main/java/tlIItools/AffixSet.java b/src/main/java/tlIItools/AffixSet.java
new file mode 100644
index 00000000..8f59d7b4
--- /dev/null
+++ b/src/main/java/tlIItools/AffixSet.java
@@ -0,0 +1,34 @@
+package tlIItools;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+/**
+ * Container of a set of affixes.
+ *
+ * @author Ben Culkin
+ */
+public class AffixSet {
+ /**
+ * All of the affix groups contained in this set.
+ *
+ * An affix group is a set of affixs that generally have the same or
+ * similiar effects, but have different intensities or spawn levels.
+ */
+ public Map<String, List<Affix>> affixGroups;
+
+ /**
+ * All of the ungrouped affixes contained in this set.
+ */
+ public List<Affix> ungroupedAffixes;
+
+ /**
+ * Create a new blank affix set.
+ */
+ public AffixSet() {
+ affixGroups = new HashMap<>();
+
+ ungroupedAffixes = new ArrayList<>();
+ }
+}
diff --git a/src/main/java/tlIItools/Effect.java b/src/main/java/tlIItools/Effect.java
index 1c0af9af..3efec6de 100644
--- a/src/main/java/tlIItools/Effect.java
+++ b/src/main/java/tlIItools/Effect.java
@@ -17,6 +17,15 @@ import java.util.Scanner;
*/
public class Effect {
/**
+ * Count of all loaded effects.
+ */
+ public static int effectCount = 0;
+ /**
+ * Do timing analysis when loading effects.
+ */
+ public static boolean doTiming;
+
+ /**
* The list of detail strings for skills.
*/
private static Map<String, String> detals;
@@ -361,4 +370,124 @@ public class Effect {
return sb.toString();
}
+
+ public static Effect parseEffect(Affix afx, Scanner scn, String scnSource) {
+ return parseEffect(afx, scn, scnSource, new ArrayList<>());
+ }
+
+ public static Effect parseEffect(Affix afx, Scanner scn, String scnSource, List<String> errs) {
+ Effect efct = new Effect();
+
+ long startTime = System.nanoTime();
+
+ efct.fName = scnSource;
+
+ while (scn.hasNextLine()) {
+ String ln = scn.nextLine();
+ ln = ln.replaceAll("\\p{Cntrl}", "");
+
+ if (ln.contains("[/EFFECT]")) break;
+
+ String[] splits = ln.split(":");
+
+ // Empty field
+ if (splits.length == 1) continue;
+
+ if (ln.contains("NAME")) {
+ efct.name = splits[1];
+ } else if (ln.contains("DAMAGE_TYPE")) {
+ efct.damageType = splits[1];
+ } else if (ln.contains("TYPE")) {
+ efct.type = splits[1];
+ } else if (ln.contains("ACTIVATION")) {
+ switch (splits[1]) {
+ case "DYNAMIC":
+ case "PASSIVE":
+ // Passive is the default, and
+ // dynamic doesn't have much
+ // actual difference.
+ break;
+ case "TRANSFER":
+ efct.isTransfer = true;
+ break;
+ default:
+ errs.add(String.format("Malformed activation type: (%s) (%s) (%s)\n", splits[1], efct.name, afx.intName));
+ }
+ } else if (ln.contains("DURATION")) {
+ if (splits[1].equals("ALWAYS")) {
+ efct.hasDuration = false;
+
+ efct.duration = Double.POSITIVE_INFINITY;
+ } else if (splits[1].equals("INSTANT")) {
+ efct.hasDuration = false;
+
+ efct.duration = Double.NaN;
+ } else if (splits[1].equals("PERCENT")) {
+ efct.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.duration = 0.0;
+ } else {
+ efct.hasDuration = true;
+
+ efct.duration = Double.parseDouble(splits[1]);
+ }
+ } else if (ln.contains("<FLOAT>MIN:")) {
+ efct.minValue = Double.parseDouble(splits[1]);
+ } else if (ln.contains("<FLOAT>MAX:")) {
+ efct.maxValue = Double.parseDouble(splits[1]);
+ } else if (ln.contains("USEOWNERLEVEL")) {
+ // We don't care about this, for now
+ } else if (ln.contains("LEVEL:")) {
+ efct.level = Integer.parseInt(splits[1]);
+ } else if (ln.contains("EXCLUSIVE")) {
+ efct.exclusive = Boolean.parseBoolean(splits[1]);
+ } else if (ln.contains("GRAPHOVERRIDE")) {
+ efct.graphOverride = splits[1];
+ } else if (ln.contains("USEOWNERLEVEL")) {
+ efct.ownerLevel = Boolean.parseBoolean(splits[1]);
+ } else if (ln.contains("NOGRAPH")) {
+ efct.useGraph = Boolean.parseBoolean(splits[1]);
+ } else if (ln.contains("STATNAME")) {
+ efct.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]);
+ } else if (ln.contains("RESISTANCE:")) {
+ efct.resist = Double.parseDouble(splits[1]);
+ } else if (ln.contains("FORCE:")) {
+ efct.resist = Double.parseDouble(splits[1]);
+ } else if (ln.contains("MIN_PER")) {
+ efct.minPer = Double.parseDouble(splits[1]);
+ } else if (ln.contains("MAX_PER")) {
+ efct.maxPer = Double.parseDouble(splits[1]);
+ } else if (ln.contains("RANGE:") || ln.contains("RADIUS")) {
+ efct.range = Double.parseDouble(splits[1]);
+ } else if (ln.contains("MAX_COUNT:") || ln.contains("MAX_TARGETS")) {
+ efct.maxCount = Double.parseDouble(splits[1]);
+ } else if (ln.contains("PULSE_RATE")) {
+ efct.pulse = Double.parseDouble(splits[1]);
+ } else if (ln.contains("CHANCE:")) {
+ // NOTE: Should really use its own field
+ efct.resist = Double.parseDouble(splits[1]);
+ }
+ }
+
+ long endTime = System.nanoTime();
+ if (doTiming) {
+ String fmt = "\t\tProcessed effect %s from %s in %d nanoseconds (%.2f seconds)\n";
+
+ double seconds = ((double)((endTime - startTime) / 1000000000));
+ errs.add(String.format(fmt, efct.name, scnSource, endTime - startTime, seconds));
+ }
+
+ effectCount += 1;
+
+ return efct;
+ }
}
diff --git a/src/main/java/tlIItools/Main.java b/src/main/java/tlIItools/Main.java
new file mode 100644
index 00000000..4b929381
--- /dev/null
+++ b/src/main/java/tlIItools/Main.java
@@ -0,0 +1,7 @@
+package tlIItools;
+
+public class Main {
+ public static void main(String[] args) {
+
+ }
+}
diff --git a/src/main/java/tlIItools/NameFileReader.java b/src/main/java/tlIItools/NameFileReader.java
new file mode 100644
index 00000000..ad2a83b4
--- /dev/null
+++ b/src/main/java/tlIItools/NameFileReader.java
@@ -0,0 +1,190 @@
+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.
+ *
+ * @author Ben Culkin
+ */
+public class NameFileReader {
+ /**
+ * Are we attempting to guess group names?
+ */
+ public boolean guessGroups;
+
+ /**
+ * Regex to use for guessing group names.
+ */
+ public String groupRx;
+
+ /**
+ * The default group to put files into.
+ */
+ public String defGroup;
+
+ /**
+ * The map of file groups.
+ */
+ public Map<String, List<String>> fNames;
+
+ /*
+ * The current group.
+ */
+ private String curGroup;
+ /*
+ * The list of files for the current group.
+ */
+ private List<String> curList;
+
+ /**
+ * Counts the files read in.
+ */
+ public int fCount;
+
+ public PrintStream normOut = System.out;
+ public PrintStream errOut = System.err;
+
+ /**
+ * Create a new name reader using the default settings.
+ *
+ * Guessing groups is disabled by default.
+ */
+ public NameFileReader() {
+ this(false);
+ }
+
+ /**
+ * Create a new name reader using the default settings.
+ *
+ * @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.
+ *
+ * @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<>());
+
+ this.fNames = fNames;
+
+ this.defGroup = defGroup;
+
+ this.guessGroups = guessGroups;
+
+ this.curGroup = defGroup;
+ this.curList = fNames.get(curGroup);
+
+ this.fCount = 0;
+ }
+
+ /**
+ * Read in file names from a file.
+ *
+ * @param from
+ * The name of the file to read from.
+ *
+ * @return The number of files read.
+ */
+ public void readFrom(String from) {
+ int ret;
+
+ try (FileReader fr = new FileReader(from)) {
+ readFrom(fr);
+ } catch (IOException ioex) {
+ errOut.printf("Error reading names from file %s\n", from);
+ ioex.printStackTrace(errOut);
+ errOut.println();
+ }
+ }
+
+ /**
+ * Read in file names from an input source.
+ *
+ * @param r
+ * The input source to read from.
+ *
+ * @return The number of files read.
+ */
+ public void readFrom(Reader r) {
+ int numFiles = 0;
+
+ Scanner scn = new Scanner(r);
+
+ while (scn.hasNextLine()) {
+ String ln = scn.nextLine();
+
+ boolean skipAdd = false;
+
+ if (ln.startsWith("#")) {
+ swapGroup(ln.substring(1));
+
+ skipAdd = true;
+ } else if (guessGroups && ln.contains("/mods/")) {
+ swapGroup(ln.replaceAll(groupRx, "$1"));
+ }
+
+ if (!skipAdd) {
+ fCount += 1;
+
+ curList.add(ln);
+ }
+
+ skipAdd = false;
+ }
+ }
+
+ /**
+ * Swap to a new file group.
+ *
+ * @param groupName
+ * The name of the group to swap to.
+ */
+ public void swapGroup(String groupName) {
+ curGroup = groupName;
+
+ if (!fNames.containsKey(curGroup)) {
+ curList = new ArrayList<>();
+
+ fNames.put(curGroup, curList);
+ } else {
+ curList = fNames.get(curGroup);
+ }
+ }
+
+ public void addFile(String fName) {
+ curList.add(fName);
+
+ fCount += 1;
+ }
+
+ public void addFile(String groupName, String fName) {
+ fNames.computeIfAbsent(groupName, (key) -> new ArrayList<>()).add(fName);
+
+ fCount += 1;
+ }
+}