Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
200 lines
8.0 KiB
Java
200 lines
8.0 KiB
Java
package prc.utils;
|
|
|
|
import prc.autodoc.Data_2da;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.util.*;
|
|
|
|
/**
|
|
* A class that performs some validation on spell.2da by checking if it contains duplicated
|
|
* subradial IDs.
|
|
* Also has capability to attempt to replace the duplicate IDs with unique ones selected
|
|
* automatically starting from a given index.
|
|
*/
|
|
public class DuplicateSubradials {
|
|
private static class DuplicateData {
|
|
int subnum;
|
|
//Set<Integer> indices = new HashSet<Integer>();
|
|
List<Integer> indices = new ArrayList<Integer>();
|
|
|
|
DuplicateData(int subnum) {
|
|
this.subnum = subnum;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Main method
|
|
*
|
|
* @param args The program arguments
|
|
*/
|
|
public static void main(String[] args) {
|
|
if (args.length == 0) readMe();
|
|
String pathtospells2da = null;
|
|
boolean fixduplicates = false;
|
|
int replacementstart = -1;
|
|
|
|
// parse args
|
|
for (String param : args) {//[--help] | [-f replacestart] pathtospells2da
|
|
// Parameter parseage
|
|
if (param.startsWith("-")) {
|
|
if (param.equals("--help")) readMe();
|
|
else {
|
|
for (char c : param.substring(1).toCharArray()) {
|
|
switch (c) {
|
|
case 'f':
|
|
fixduplicates = true;
|
|
break;
|
|
default:
|
|
System.out.println("Unknown parameter: " + c);
|
|
readMe();
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// The option to attempt fixing the duplicates is on and the first replacement number hasn't been given yet
|
|
if (fixduplicates == true && replacementstart == -1) {
|
|
try {
|
|
replacementstart = Integer.parseInt(param);
|
|
} catch (NumberFormatException e) {
|
|
System.out.println("replacestart value given is not numeric: " + param);
|
|
readMe();
|
|
}
|
|
if (replacementstart < 0 || replacementstart >= 0x10000) {
|
|
System.out.println("replacestart value given is not in valid range");
|
|
readMe();
|
|
}
|
|
}
|
|
// It's a pathname
|
|
else if (pathtospells2da == null)
|
|
pathtospells2da = param;
|
|
}
|
|
}
|
|
|
|
// Load the 2da to memory
|
|
Data_2da spells = Data_2da.load2da(pathtospells2da);
|
|
Map<Integer, Integer> subrads = new HashMap<Integer, Integer>(); // Map of subradial # to the first line it occurs on
|
|
Map<Integer, DuplicateData> duplicates = new HashMap<Integer, DuplicateData>();
|
|
String entry;
|
|
int subnum = 0;
|
|
// Parse through the 2da, looking for FeatID references that contain a subradial ID
|
|
for (int i = 0; i < spells.getEntryCount(); i++) {
|
|
entry = spells.getEntry("FeatID", i);
|
|
// Skip blanks
|
|
if (entry.equals("****")) continue;
|
|
try {
|
|
subnum = Integer.parseInt(entry);
|
|
} catch (NumberFormatException e) {
|
|
System.out.println("Corrupt value in FeatID on row " + i + ": " + entry);
|
|
continue;
|
|
}
|
|
// Skip non-subradial FeatIDs
|
|
if (subnum < 0x10000) continue;
|
|
subnum = subnum >>> 16;
|
|
|
|
if (subrads.containsKey(subnum)) {
|
|
if (!duplicates.containsKey(subnum))
|
|
duplicates.put(subnum, new DuplicateData(subnum));
|
|
|
|
duplicates.get(subnum).indices.add(i);
|
|
} else subrads.put(subnum, i);
|
|
}
|
|
|
|
// Print the results
|
|
int requiredtofix = 0;
|
|
for (DuplicateData dup : duplicates.values()) {
|
|
System.out.println("Duplicate subradial ID: " + dup.subnum + " first occurrence on row " + subrads.get(dup.subnum));
|
|
for (int i : dup.indices)
|
|
System.out.println("Duplicate subradial ID: " + dup.subnum + " on row " + i);
|
|
requiredtofix += dup.indices.size();
|
|
}
|
|
if (requiredtofix > 0)
|
|
System.out.println("\nNumber of new subradial IDs required to make all unique: " + requiredtofix);
|
|
|
|
if (fixduplicates && requiredtofix > 0) {
|
|
System.out.println("\n\nAttempting to fix.");
|
|
|
|
// Construct a list of the replacement subradial IDs
|
|
List<Integer> replacementlist = new ArrayList<Integer>();
|
|
int replacementid = replacementstart;
|
|
while (replacementlist.size() < requiredtofix) {
|
|
if (replacementid >= 0x10000) {// Make sure we don't exceed the bounds
|
|
System.out.println("Not enough free subradial IDs in the range from " + replacementstart + " to " + 0x10000 + "!");
|
|
System.exit(1);
|
|
}
|
|
// Pick ones not already in use
|
|
if (!subrads.containsKey(replacementid))
|
|
replacementlist.add(replacementid);
|
|
|
|
replacementid++;
|
|
}
|
|
|
|
// Loop over the duplicates, fixing as we go
|
|
Iterator<Integer> replacements = replacementlist.iterator();
|
|
int featid;
|
|
for (DuplicateData dup : duplicates.values()) {
|
|
for (int i : dup.indices) {
|
|
// Extract the base featID. Low 16 bits
|
|
featid = Integer.parseInt(spells.getEntry("FeatID", i)) & 0x0000FFFF;
|
|
// Insert new subradial number
|
|
subnum = replacements.next();
|
|
featid = featid | (subnum << 16);
|
|
|
|
// Store the new subradial'd featid in spells.2da
|
|
spells.setEntry("FeatID", i, Integer.toString(featid));
|
|
}
|
|
}
|
|
|
|
// Save the 2da
|
|
try {
|
|
spells.save2da((new File(pathtospells2da)).getParent(), true, true);
|
|
} catch (IOException e) {
|
|
System.err.println("Error while saving spells.2da!\n" + e);
|
|
System.exit(1);
|
|
}
|
|
|
|
// List the used subradial IDs
|
|
System.out.println("Subradial IDs used:");
|
|
Integer prev = null;
|
|
for (Integer subrad : replacementlist) {
|
|
// Detect if a new range is starting
|
|
if (prev == null || // Special case - just starting
|
|
subrad != (prev + 1) // There's a break in the series
|
|
) {
|
|
// Print the end of previous range
|
|
if (prev != null)
|
|
System.out.println(prev);
|
|
|
|
// Print the start of the new range
|
|
System.out.print(subrad + " - ");
|
|
}
|
|
|
|
// Update prev
|
|
prev = subrad;
|
|
}
|
|
|
|
// Print the end of the last range
|
|
System.out.println(prev);
|
|
}
|
|
}
|
|
|
|
private static void readMe() {
|
|
System.out.println("Usage:\n" +
|
|
" [--help] | [-f replacestart] pathtospells2da\n" +
|
|
"\n" +
|
|
" pathtospells2da path of the spells.2da to check\n" +
|
|
" replacestart the first subradial ID to replace duplicates\n" +
|
|
" with when fixing. optional, required if -f is set\n" +
|
|
"\n" +
|
|
" --help prints this text\n" +
|
|
" -f attempt to replace the duplicate subradial IDs with new\n" +
|
|
" unused IDs starting with the value given as replacestart\n" +
|
|
"\n" +
|
|
"\n" +
|
|
"Looks for duplicate subradial IDs in the FeatID column of the given\n" +
|
|
"spells.2da. May optionally attempt to replace the duplicates with unique\n" +
|
|
"values.\n"
|
|
);
|
|
System.exit(0);
|
|
}
|
|
} |