mirror of
http://prc.nwn.ee:3000/Jaysyn/PRC8.git
synced 2026-09-14 08:05:54 -04:00
Updated Release Archive
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.
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,169 @@
|
||||
package prc;
|
||||
|
||||
import prc.autodoc.ErrorPrinter;
|
||||
import prc.autodoc.Spinner;
|
||||
|
||||
/**
|
||||
* A menu class. Calls operations from classes in subpackages based on parameters
|
||||
*
|
||||
* @author heikki
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
/** Version number for public releases. Raise by one whenever doing a release. */
|
||||
private static final int releaseNum = 1;
|
||||
|
||||
/** A convenience object for printing both to log and System.err */
|
||||
public static ErrorPrinter err_pr = new ErrorPrinter();
|
||||
|
||||
/** A boolean determining whether to spam the user with progress information */
|
||||
public static boolean verbose = true;
|
||||
|
||||
/** A decorative spinner to look at while the program is loading big files */
|
||||
public static Spinner spinner = new Spinner();
|
||||
|
||||
/**
|
||||
* Ooh, a main method!
|
||||
*
|
||||
* @param args arguments, surprisingly enough
|
||||
*
|
||||
* @throws Throwable everything received from the classes called is passed on
|
||||
*/
|
||||
public static void main(String[] args) throws Throwable{
|
||||
if(args.length == 0 || args[0].equals("--help"))
|
||||
readMe();
|
||||
|
||||
String toCall = args[0];
|
||||
String[] paramsToPass = new String[args.length - 1];
|
||||
System.arraycopy(args, 1, paramsToPass, 0, paramsToPass.length);
|
||||
|
||||
if(toCall.equals("manual")){
|
||||
prc.autodoc.Main.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("2da")){
|
||||
prc.autodoc.Data_2da.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("codegen")){
|
||||
prc.utils.CodeGen.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("radials")){
|
||||
prc.utils.Radials.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("lssubrad")){
|
||||
prc.utils.ListSubradials.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("dupsubrad")){
|
||||
prc.utils.DuplicateSubradials.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("makedep")){
|
||||
prc.makedep.Main.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("upclsfeat")){
|
||||
prc.utils.AllClassFeatUpdater.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("lsentries")){
|
||||
prc.utils.List2daEntries.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("dupentries")){
|
||||
prc.utils.Duplicate2daEntryDetector.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("2datosql")){
|
||||
prc.utils.SQLMaker.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("spellbookmaker")){
|
||||
prc.utils.SpellbookMaker.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("amsspellbookmaker")){
|
||||
prc.utils.AMSSpellbookMaker.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("itempropmaker")){
|
||||
prc.utils.ItempropMaker.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("letoxml")){
|
||||
prc.utils.LetoListsGenerator.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("prec2dagen")){
|
||||
prc.utils.Precache2daGen.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("scrmrchgen")){
|
||||
prc.utils.ScrollMerchantGen.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("npcevol")){
|
||||
prc.utils.NPCEvolve.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("2damerge")){
|
||||
prc.utils.Data2daMerge.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("blank2da")){
|
||||
prc.utils.Blank2daRows.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("validator")){
|
||||
prc.utils.Validator.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("updatedescrft")){
|
||||
prc.utils.UpdateDes.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("scrollgen")){
|
||||
prc.utils.ScrollGen.main(paramsToPass);
|
||||
}
|
||||
else if(toCall.equals("buildscrhack")){
|
||||
prc.utils.BuildScrollHack.main(paramsToPass);
|
||||
}
|
||||
else{
|
||||
System.out.println("Unknown class: " + toCall);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints the use instructions for this program and kills execution.
|
||||
*/
|
||||
private static void readMe(){
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
System.out.println("Usage:\n"+
|
||||
" java -jar prc.jar [--help] | tool [parameters]\n"+
|
||||
"\n"+
|
||||
"tool name of the tool to call. possible values:\n"+
|
||||
" 2da - Either verifies a single 2da file or compares two\n"+
|
||||
" 2damerge - Merges 2 directories of 2da files, and outputs to a third\n" +
|
||||
" blank2da - Blanks rows in a 2da\n" +
|
||||
" codegen - Autogenerates scripts (or other files)\n"+
|
||||
" dupentries - Seeks for duplicate entries in the given columns\n" +
|
||||
" of a given 2da\n"+
|
||||
" dupsubrad - Seeks through spells.2da and prints lines\n"+
|
||||
" containing duplicate subradial values\n"+
|
||||
" letoxml - Creates Leto XML lists from 2da and TLK\n" +
|
||||
" lsentries - Lists the unique entries in given columns of a\n" +
|
||||
" given 2da\n" +
|
||||
" lssubrad - Lists subradial IDs used in spells.2da\n" +
|
||||
" makedep - Builds include dependency lists\n" +
|
||||
" radials - Generates subradial FeatID values\n"+
|
||||
"\n" +
|
||||
" The following tools are also available, but almost certainly too\n" +
|
||||
" specialized for general use:\n" +
|
||||
" 2datosql - Creates a SQL file from 2das\n" +
|
||||
" itempropmaker - Creates the itemproperty cache item templates\n" +
|
||||
" manual - Generates the manual\n"+
|
||||
" npcevol - Alters packages based on logfile scores\n" +
|
||||
" upclsfeat - Updates base cls_feat_*.2da based on given templates\n" +
|
||||
" prec2dagen - Creates a 2da file that lists spells/feat.2da rows\n" +
|
||||
" that should be precached\n" +
|
||||
" scrmrchgen - Creates scroll merchant based on des_crft_scroll.2da\n" +
|
||||
" spellbookmaker - Creates and/or updates the new spellbooks data\n" +
|
||||
" amsspellbookmaker - Creates and/or updates the new AMS spellbooks data\n" +
|
||||
" validator - Performs a bunch of 2da integrity tests\n" +
|
||||
" updatedescrft - Updates des_crft_*.2da based on spells.2da\n" +
|
||||
" scrollgen - Create spell scrolls based on (iprp_)spells.2da\n" +
|
||||
"\n"+
|
||||
"parameters a list of parameters passed to the tool called\n"+
|
||||
"\n"+
|
||||
"--help prints this info you are reading\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"Release number: " + releaseNum + "\n"
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,71 @@
|
||||
package prc.autodoc;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Data structure for a class entry.
|
||||
*/
|
||||
public class ClassEntry extends GenericEntry {
|
||||
/**
|
||||
* If <code>true</code>, this class is a base class.
|
||||
*/
|
||||
public final boolean isBase;
|
||||
|
||||
/**
|
||||
* List of BAB and saving throw values. Each list entry consists of the values
|
||||
* for the list indexth level. Order: BAB, Fort, Ref, Will.
|
||||
*/
|
||||
public final List<String[]> babSav;
|
||||
|
||||
/**
|
||||
* The list of this class's class and cross-class skills. First tuple member
|
||||
* cotnaints the class skills, the second cross-class skills.
|
||||
* Map keys are skill names.
|
||||
*/
|
||||
public final Tuple<TreeMap<String, GenericEntry>, TreeMap<String, GenericEntry>> skillList;
|
||||
|
||||
/**
|
||||
* Lists of this class's granted and selectable feats. First tuple member lists bonus feat
|
||||
* # at each level. First inner tuple member is the granted feats, second member is selectable feats.
|
||||
* Each list consists of the feats that are related to the list indexth level.
|
||||
* The map keys are feat names.
|
||||
*/
|
||||
public final Tuple<List<Integer>, Tuple<List<TreeMap<String, FeatEntry>>, List<TreeMap<String, FeatEntry>>>> featList;
|
||||
|
||||
/**
|
||||
* The alternate magic systems available to this class. Each list entry describes one
|
||||
* magic system (though there will probably never be more than one per class).
|
||||
* First member of the outer tuple is the (magic system name, magic system spell-equivalent name)
|
||||
* pair. Second member is a map keyed to spell-equivalent level, with values being maps of
|
||||
* spell-equivalent name to the spell entry.
|
||||
*/
|
||||
public final List<Tuple<Tuple<String, String>, TreeMap<Integer, TreeMap<String, SpellEntry>>>> magics;
|
||||
|
||||
/**
|
||||
* Create a new class entry.
|
||||
*
|
||||
* @param name The name of this class.
|
||||
* @param text The description of this class.
|
||||
* @param iconPath The path of this class's icon.
|
||||
* @param filePath The path of the html file that has been written for this class.
|
||||
* @param isBase If <code>true</code>, this class is a base class.
|
||||
* @param entryNum Index of the class in classes.2da.
|
||||
* @param babSav The BAB and saves of this class.
|
||||
* @param skillList The skills of this class.
|
||||
* @param featList The feats of this class.
|
||||
* @param magics The alternate magics of this class.
|
||||
*/
|
||||
public ClassEntry(String name, String text, String iconPath, String filePath,
|
||||
int entryNum, boolean isBase, List<String[]> babSav,
|
||||
Tuple<TreeMap<String, GenericEntry>, TreeMap<String, GenericEntry>> skillList,
|
||||
Tuple<List<Integer>, Tuple<List<TreeMap<String, FeatEntry>>, List<TreeMap<String, FeatEntry>>>> featList,
|
||||
List<Tuple<Tuple<String, String>, TreeMap<Integer, TreeMap<String, SpellEntry>>>> magics) {
|
||||
super(name, text, iconPath, filePath, entryNum);
|
||||
this.isBase = isBase;
|
||||
this.babSav = babSav;
|
||||
this.skillList = skillList;
|
||||
this.featList = featList;
|
||||
this.magics = magics;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,278 @@
|
||||
package prc.autodoc;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static prc.Main.spinner;
|
||||
import static prc.Main.verbose;
|
||||
|
||||
/**
|
||||
* This class forms an interface for accessing TLK files in the
|
||||
* PRC automated manual generator.
|
||||
*/
|
||||
public class Data_TLK {
|
||||
private final HashMap<Integer, String> mainData = new HashMap<Integer, String>();
|
||||
private int highestEntry = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new Data_TLK on the TLK file specified.
|
||||
*
|
||||
* @param filePath The path of the TLK file to be loaded
|
||||
* @throws IllegalArgumentException <code>filePath</code> does not filePath a TLK file
|
||||
* @throws TLKReadException reading the TLK file specified does not succeed
|
||||
*/
|
||||
public Data_TLK(String filePath) {
|
||||
// Some paranoia checking for bad parameters
|
||||
if (!filePath.toLowerCase().endsWith("tlk"))
|
||||
throw new IllegalArgumentException("Non-tlk filename passed to Data_TLK: " + filePath);
|
||||
|
||||
File baseFile = new File(filePath);
|
||||
if (!baseFile.exists())
|
||||
throw new IllegalArgumentException("Nonexistent file passed to Data_TLK: " + filePath);
|
||||
if (!baseFile.isFile())
|
||||
throw new IllegalArgumentException("Nonfile passed to Data_TLK: " + filePath);
|
||||
|
||||
|
||||
// Create a RandomAccessFile for reading the TLK. Read-only
|
||||
MappedByteBuffer reader = null;
|
||||
RandomAccessFile fileReader;
|
||||
try {
|
||||
fileReader = new RandomAccessFile(baseFile, "r");
|
||||
reader = fileReader.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, fileReader.length());
|
||||
} catch (IOException e) {
|
||||
throw new TLKReadException("Cannot access TLK file: " + filePath, e);
|
||||
}
|
||||
byte[] bytes4 = new byte[4],
|
||||
bytes8 = new byte[8];
|
||||
|
||||
// Drop the path from the filename
|
||||
String fileName = baseFile.getName();
|
||||
|
||||
// Tell the user what we are doing
|
||||
if (verbose) System.out.print("Reading TLK file: " + fileName + " ");
|
||||
|
||||
try {
|
||||
// Check the header
|
||||
reader.get(bytes4);
|
||||
if (!new String(bytes4).equals("TLK "))
|
||||
throw new TLKReadException("Wrong file type field in: " + fileName);
|
||||
|
||||
// Check the version
|
||||
reader.get(bytes4);
|
||||
if (!new String(bytes4).equals("V3.0"))
|
||||
throw new TLKReadException("Wrong TLK version number in: " + fileName);
|
||||
|
||||
// Skip the language ID
|
||||
reader.position(reader.position() + 4);
|
||||
|
||||
// Read the entrycount
|
||||
int stringCount = readLittleEndianInt(reader, bytes4);
|
||||
int stringOffset = readLittleEndianInt(reader, bytes4);
|
||||
|
||||
// Read the entry lengths
|
||||
int[] stringLengths = readStringLengths(reader, stringCount);
|
||||
|
||||
// Read the strings themselves
|
||||
readStrings(reader, stringLengths, stringOffset);
|
||||
|
||||
// Store the highest string for writing back later
|
||||
highestEntry = stringLengths.length;
|
||||
} catch (IOException e) {
|
||||
throw new TLKReadException("IOException while reading TLK file: " + fileName, e);
|
||||
} finally {
|
||||
try {
|
||||
fileReader.close();
|
||||
} catch (IOException e) {
|
||||
// No idea under what conditions closing a file could fail and not cause an Error to be thrown...
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) System.out.println("- Done");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the given TLK entry.
|
||||
*
|
||||
* @param strRef the number of the entry to get
|
||||
* @return the entry string or "Bad StrRef" if the entry wasn't in the TLK
|
||||
*/
|
||||
public String getEntry(int strRef) {
|
||||
if (strRef > 0x01000000) strRef -= 0x01000000;
|
||||
String toReturn = mainData.get(strRef);
|
||||
if (toReturn == null) toReturn = Main.badStrRef;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the given TLK entry.
|
||||
*
|
||||
* @param strRef the number of the entry to get as a string
|
||||
* @return the entry string or "Bad StrRef" if the entry wasn't in the TLK
|
||||
* @throws NumberFormatException if <code>strRef</code> cannot be converted to an integer
|
||||
*/
|
||||
public String getEntry(String strRef) {
|
||||
try {
|
||||
return getEntry(Integer.parseInt(strRef));
|
||||
} catch (NumberFormatException e) {
|
||||
return Main.badStrRef;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given TLK entry.
|
||||
*
|
||||
* @param strRef the number of the entry to set
|
||||
* @param value the value of the entry to set
|
||||
*/
|
||||
public void setEntry(int strRef, String value) {
|
||||
if (strRef > 0x01000000) strRef -= 0x01000000;
|
||||
mainData.put(strRef, value);
|
||||
if (strRef > highestEntry)
|
||||
highestEntry = strRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the tlk file to the given XML.
|
||||
*
|
||||
* @param name the name of the resulting file, without extensions
|
||||
* @param path the path to the directory to save the file to
|
||||
* @param allowOverWrite Whether to allow overwriting existing files
|
||||
* @throws IOException if cannot overwrite, or the underlying IO throws one
|
||||
*/
|
||||
public void saveAsXML(String name, String path, boolean allowOverWrite) throws IOException {
|
||||
if (path == null || path.equals(""))
|
||||
path = "." + File.separator;
|
||||
if (!path.endsWith(File.separator))
|
||||
path += File.separator;
|
||||
|
||||
File file = new File(path + name + ".tlk.xml");
|
||||
if (file.exists() && !allowOverWrite)
|
||||
throw new IOException("File exists already: " + file.getAbsolutePath());
|
||||
|
||||
// Inform user
|
||||
if (verbose) System.out.print("Saving tlk file: " + name + " ");
|
||||
|
||||
PrintWriter writer = new PrintWriter(file);
|
||||
|
||||
//write the header
|
||||
writer.println("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
|
||||
writer.println("<!DOCTYPE tlk SYSTEM \"tlk2xml.dtd\">");
|
||||
writer.println("<tlk>");
|
||||
|
||||
//loop over each row and write it
|
||||
for (int row = 0; row < highestEntry; row++) {
|
||||
String data = mainData.get(row);
|
||||
if (data != null) {
|
||||
//replace with paired characters
|
||||
data = data.replace("&", "&"); //this must be before the others
|
||||
data = data.replace("<", "<");
|
||||
data = data.replace(">", ">");
|
||||
writer.println(" <entry id=\"" + row + "\" lang=\"en\" sex=\"m\">" + data + "</entry>");
|
||||
}
|
||||
if (verbose) spinner.spin();
|
||||
}
|
||||
|
||||
//write the footer
|
||||
writer.println("</tlk>");
|
||||
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
if (verbose) System.out.println("- Done");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads the string lengths from this TLK's string data elements.
|
||||
*
|
||||
* @param reader RandomAccessFile read from
|
||||
* @param stringCount number of strings in the TLK
|
||||
* @return an array of integers containing the lengths of the strings in this TLK
|
||||
* @throws IOException if there is an error while reading from <code>reader</code>
|
||||
*/
|
||||
private int[] readStringLengths(MappedByteBuffer reader, int stringCount) throws IOException {
|
||||
int[] toReturn = new int[stringCount];
|
||||
byte[] bytes4 = new byte[4];
|
||||
int curOffset = 20; // The number of bytes in the TLK header section
|
||||
|
||||
for (int i = 0; i < stringCount; i++) {
|
||||
// Skip everything up to the length
|
||||
curOffset += 32;
|
||||
reader.position(curOffset);
|
||||
// Read the value
|
||||
toReturn[i] = readLittleEndianInt(reader, bytes4);
|
||||
// Skip to the end of the record
|
||||
curOffset += 8;
|
||||
|
||||
if (verbose) spinner.spin();
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the strings from the TLK into the hashmap.
|
||||
*
|
||||
* @param reader RandomAccessFile read from
|
||||
* @param stringLengths an array of integers containing the lengths of the strings in this TLK
|
||||
* @param curOffset the offset to start reading from in the file
|
||||
* @throws IOException if there is an error while reading from <code>reader</code>
|
||||
*/
|
||||
private void readStrings(MappedByteBuffer reader, int[] stringLengths, int curOffset) throws IOException {
|
||||
StringBuffer buffer = new StringBuffer(200);
|
||||
reader.position(curOffset);
|
||||
|
||||
for (int i = 0; i < stringLengths.length; i++) {
|
||||
if (stringLengths[i] > 0) {
|
||||
// Read the specified number of bytes, convert them into chars
|
||||
// and put them in the buffer
|
||||
for (int j = 0; j < stringLengths[i]; j++)
|
||||
buffer.append((char) (reader.get() & 0xff));
|
||||
// Store the buffer contents
|
||||
mainData.put(i, buffer.toString());
|
||||
// Wipe the buffer for next round
|
||||
buffer.delete(0, buffer.length());
|
||||
}
|
||||
if (verbose) spinner.spin();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next 4 bytes into the given array from the TLK and then
|
||||
* writes them into an integer in inverse order.
|
||||
*
|
||||
* @param reader RandomAccessFile read from
|
||||
* @param readArray array of bytes read to. For efficiency of not having to create a new array every time
|
||||
* @return integer read
|
||||
* @throws IOException if there is an error while reading from <code>reader</code>
|
||||
*/
|
||||
private int readLittleEndianInt(MappedByteBuffer reader, byte[] readArray) throws IOException {
|
||||
int toReturn = 0;
|
||||
reader.get(readArray);
|
||||
for (int i = readArray.length - 1; i >= 0; i--) {
|
||||
// What's missing here is the implicit promotion of readArray[i] to
|
||||
// int. A byte is a signed element, and as such, has max value of 0x7f.
|
||||
toReturn = (toReturn << 8) | readArray[i] & 0xff;
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method, as usual
|
||||
*
|
||||
* @param args
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
Data_TLK test = new Data_TLK(args[0]);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
package prc.autodoc;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Data structure for a domain entry.
|
||||
*/
|
||||
public class DomainEntry extends GenericEntry {
|
||||
|
||||
/**
|
||||
* This domain's domain power, if any
|
||||
*/
|
||||
public final FeatEntry grantedFeat;
|
||||
/**
|
||||
* The domain's spells. List of spell entry.
|
||||
*/
|
||||
public final List<SpellEntry> spells;
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
*
|
||||
* @param name Name of the domain
|
||||
* @param text Description of the domain
|
||||
* @param iconPath Path of the domain's icon
|
||||
* @param filePath Path where the html page for this domain will be written to
|
||||
* @param entryNum domains.2da index
|
||||
* @param grantedFeat Domain power feat
|
||||
* @param spells The domain spells
|
||||
*/
|
||||
public DomainEntry(String name, String text, String iconPath, String filePath,
|
||||
int entryNum, FeatEntry grantedFeat,
|
||||
List<SpellEntry> spells) {
|
||||
super(name, text, iconPath, filePath, entryNum);
|
||||
this.grantedFeat = grantedFeat;
|
||||
this.spells = spells;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,66 @@
|
||||
package prc.autodoc;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* A convenience class for printing errors to both log and System.err
|
||||
*/
|
||||
public class ErrorPrinter {
|
||||
private PrintWriter writer;
|
||||
private boolean isInit = false;
|
||||
|
||||
/**
|
||||
* Initializes the ErrorPrinter.
|
||||
* Attempts to open a log file by name of "errorlog" for writing. If this
|
||||
* fails, aborts the program.
|
||||
*/
|
||||
private void init() {
|
||||
try {
|
||||
writer = new PrintWriter(new FileOutputStream("errorlog", false), true);
|
||||
isInit = true;
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error while creating error logger. Yes, it's ironic. Now debug");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints the given string to both stderr and errorlog.
|
||||
*
|
||||
* @param toPrint string to write
|
||||
*/
|
||||
public void print(String toPrint) {
|
||||
if (!isInit)
|
||||
init();
|
||||
writer.print(toPrint);
|
||||
System.err.print(toPrint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given string to both stderr and errorlog. In addition, adds
|
||||
* a line terminator to the end of the string.
|
||||
*
|
||||
* @param toPrint string to write
|
||||
*/
|
||||
public void println(String toPrint) {
|
||||
if (!isInit)
|
||||
init();
|
||||
writer.println(toPrint);
|
||||
System.err.println(toPrint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given exception's stack trace to both stderr and errorlog.
|
||||
*
|
||||
* @param e exception to print
|
||||
*/
|
||||
public void printException(Exception e) {
|
||||
if (!isInit)
|
||||
init();
|
||||
e.printStackTrace(System.out);
|
||||
e.printStackTrace(writer);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,88 @@
|
||||
package prc.autodoc;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Data structure for a feat or masterfeat entry.
|
||||
*/
|
||||
public class FeatEntry extends GenericEntry {
|
||||
/**
|
||||
* A list of masterfeat's children
|
||||
*/
|
||||
public TreeMap<String, FeatEntry> childFeats = new TreeMap<String, FeatEntry>();
|
||||
/**
|
||||
* A list of feats that have this feat as their prerequisite
|
||||
*/
|
||||
public TreeMap<String, FeatEntry> requiredForFeats = new TreeMap<String, FeatEntry>();
|
||||
/**
|
||||
* A list of this feat's AND prerequisites
|
||||
*/
|
||||
public TreeMap<String, FeatEntry> andRequirements = new TreeMap<String, FeatEntry>();
|
||||
/**
|
||||
* A list of this feat's OR prerequisites
|
||||
*/
|
||||
public TreeMap<String, FeatEntry> orRequirements = new TreeMap<String, FeatEntry>();
|
||||
|
||||
/**
|
||||
* This feat's masterfeat, if any
|
||||
*/
|
||||
public FeatEntry master;
|
||||
/**
|
||||
* This feat's successor, if any
|
||||
*/
|
||||
public FeatEntry successor;
|
||||
|
||||
/**
|
||||
* Whether this feat is epic, as defined by feat.2da column PreReqEpic. For masterfeats, if any of the children are epic
|
||||
*/
|
||||
public boolean isEpic;
|
||||
/**
|
||||
* Whether all of a masterfeat's children are epic. This is used to determine which menus a link to it will be printed
|
||||
*/
|
||||
public boolean allChildrenEpic;
|
||||
/**
|
||||
* Whether the feat is a class-specific feat, as defined by feat.2da column ALLCLASSESCANUSE. For masterfeats, if any of the children are class-specific
|
||||
*/
|
||||
public boolean isClassFeat;
|
||||
/**
|
||||
* Whether all of a masterfeat's children are class-specific. This is used to determine which menus a link to it will be printed
|
||||
*/
|
||||
public boolean allChildrenClassFeat;
|
||||
/**
|
||||
* Whether this feat has a successor
|
||||
*/
|
||||
public boolean isSuccessor;
|
||||
|
||||
/**
|
||||
* The feat's subradials, if any. List of feat name, icon path tuples.
|
||||
*/
|
||||
public final List<Tuple<String, String>> subradials;
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
*
|
||||
* @param name Name of the feat/masterfeat
|
||||
* @param text Description of the feat
|
||||
* @param iconPath Path of the feat's icon
|
||||
* @param filePath Path where the html page for this feat will be written to
|
||||
* @param entryNum feat.2da / masterfeats.2da index
|
||||
* @param isEpic Whether the feat is an epic feat
|
||||
* @param isClassFeat Whether the feat is a class-specific feat
|
||||
* @param subradials List of this feat's subradials, if any
|
||||
*/
|
||||
public FeatEntry(String name, String text, String iconPath, String filePath,
|
||||
int entryNum, boolean isEpic, boolean isClassFeat,
|
||||
List<Tuple<String, String>> subradials) {
|
||||
super(name, text, iconPath, filePath, entryNum);
|
||||
this.isEpic = isEpic;
|
||||
this.isClassFeat = isClassFeat;
|
||||
this.subradials = subradials;
|
||||
|
||||
master = null;
|
||||
successor = null;
|
||||
isSuccessor = false;
|
||||
allChildrenClassFeat = false;
|
||||
allChildrenEpic = false;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,57 @@
|
||||
package prc.autodoc;
|
||||
|
||||
/**
|
||||
* Data structure for a skill /domain / race / class / whatever that doesn't need
|
||||
* the extra fields used for feats & spells & skills
|
||||
*/
|
||||
public class GenericEntry implements Comparable<GenericEntry> {
|
||||
/**
|
||||
* The name of this entry.
|
||||
*/
|
||||
public final String name;
|
||||
|
||||
/**
|
||||
* The contents of this entry.
|
||||
*/
|
||||
public final String text;
|
||||
|
||||
/**
|
||||
* The path of the icon file attached to this entry.
|
||||
*/
|
||||
public final String iconPath;
|
||||
|
||||
/**
|
||||
* The path of the html file that has been written for this entry.
|
||||
*/
|
||||
public final String filePath;
|
||||
|
||||
/**
|
||||
* Index of the entry in whichever 2da defines it.
|
||||
*/
|
||||
public final int entryNum;
|
||||
|
||||
/**
|
||||
* @param name Name of the entry
|
||||
* @param text Content of the entry
|
||||
* @param iconPath Path of this entry's icon
|
||||
* @param filePath Path the generated file will be located in
|
||||
* @param entryNum Number of the
|
||||
*/
|
||||
public GenericEntry(String name, String text, String iconPath, String filePath, int entryNum) {
|
||||
this.name = name;
|
||||
this.text = text;
|
||||
this.iconPath = iconPath;
|
||||
this.filePath = filePath;
|
||||
this.entryNum = entryNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparable implementation. Uses the name fields for comparison.
|
||||
*
|
||||
* @param other GenericEntry to compare this one to
|
||||
* @return @see java.lang.Comparable#compareTo
|
||||
*/
|
||||
public int compareTo(GenericEntry other) {
|
||||
return name.compareTo(other.name);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,215 @@
|
||||
package prc.autodoc;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static prc.Main.err_pr;
|
||||
import static prc.autodoc.Main.*;
|
||||
|
||||
/**
|
||||
* This class handles generating
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class Icons {
|
||||
|
||||
/**
|
||||
* Visible from outside so that Main can wait on it.
|
||||
*/
|
||||
public static ExecutorService executor;
|
||||
//private static Timer timer;
|
||||
|
||||
private static boolean init = false;
|
||||
|
||||
private static HashSet<String> existingIcons = null;
|
||||
|
||||
private static HashMap<String, File> rawIcons = null;
|
||||
|
||||
private static void init() {
|
||||
/*try{
|
||||
reader = Jimi.createTypedJimiReader("image/targa");
|
||||
writer = Jimi.createTypedJimiWriter("image/png");
|
||||
}catch(JimiException e){
|
||||
err_pr.printException(e);
|
||||
icons = false;
|
||||
return;
|
||||
}*/
|
||||
init = true;
|
||||
existingIcons = new HashSet<String>();
|
||||
ImageIO.setUseCache(false);
|
||||
//executor = new ThreadPoolExecutor(50, 1000, 60, TimeUnit.SECONDS, bq);
|
||||
//timer = new Timer("Checker", true);
|
||||
executor = Executors.newCachedThreadPool();
|
||||
|
||||
rawIcons = new HashMap<String, File>();
|
||||
File[] tgas = new File("rawicons").listFiles(new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
return file.getName().toLowerCase().endsWith(".tga");
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure the icons directory exists
|
||||
if (tgas == null) {
|
||||
err_pr.println("Error: Icons directory is missing!");
|
||||
if (tolErr) return;
|
||||
else System.exit(1);
|
||||
}
|
||||
|
||||
for (File tga : tgas)
|
||||
rawIcons.put(tga.getName().toLowerCase(), tga);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds an <img>-tag pointing at a png-converted version of the
|
||||
* given icon.
|
||||
* If such an icon does not exist, returns a blank string.
|
||||
* The icon will be converted to PNG format if it has not yet been.
|
||||
*
|
||||
* @param iconName name of the icon to use
|
||||
* @return <img>-tag pointing at the image or a blank string
|
||||
*/
|
||||
public static String buildIcon(String iconName) {
|
||||
if (!icons) return "";
|
||||
else if (!init) init();
|
||||
|
||||
if (iconName.equals("****"))
|
||||
return "";
|
||||
|
||||
// Lowercase the name
|
||||
iconName = iconName.toLowerCase();
|
||||
|
||||
// Build the html
|
||||
String tag = iconTemplate.replace("~~~ImageURL~~~", "../../../images/" + iconName + ".png")
|
||||
.replace("~~~ImageName~~~", iconName);
|
||||
|
||||
// Case of already existing and indexed image
|
||||
if (existingIcons.contains(iconName))
|
||||
return tag;
|
||||
|
||||
File png = new File(imagePath + iconName + ".png");
|
||||
// See if the converted image exists already, but just hasn't been indexed yet
|
||||
if (png.exists()) {
|
||||
existingIcons.add(iconName);
|
||||
return tag;
|
||||
}
|
||||
|
||||
File tga = rawIcons.get(iconName + ".tga");
|
||||
// There is no icon to convert
|
||||
if (tga == null) {
|
||||
err_pr.println("Error: Missing icon file: " + iconName + ".tga");
|
||||
return "";
|
||||
}
|
||||
|
||||
// Schedule the conversion for execution
|
||||
Convert task = new Convert();
|
||||
task.init(tga, png);
|
||||
Future fut = executor.submit(task);
|
||||
|
||||
|
||||
// Schedule timer task
|
||||
/*
|
||||
Check check = new Check();
|
||||
check.init(fut, iconName);
|
||||
timer.schedule(check, System.currentTimeMillis() + 30000);
|
||||
*/
|
||||
/*
|
||||
try{
|
||||
reader.setSource(new FileInputStream(new File("rawicons" + fileSeparator + iconName + ".tga")));
|
||||
writer.setSource(reader.getImage());
|
||||
writer.putImage(imagePath + iconName + ".png");
|
||||
}catch(Exception e){
|
||||
err_pr.printException(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
*/
|
||||
// Assume eventual success and add the newly created image to the index
|
||||
existingIcons.add(iconName);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
private static class Convert implements Runnable {
|
||||
private File inFile, outFile;
|
||||
|
||||
/**
|
||||
* Initialization method
|
||||
*
|
||||
* @param inFile input file, Targa format
|
||||
* @param outFile output file, Portable Network Graphics format
|
||||
*/
|
||||
public void init(File inFile, File outFile) {
|
||||
this.inFile = inFile;
|
||||
this.outFile = outFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
if (!ImageIO.write(ImageIO.read(inFile), "png", outFile))
|
||||
err_pr.println("Error: Failed to convert image " + inFile);
|
||||
} catch (IOException e) {
|
||||
err_pr.printException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Check extends TimerTask {
|
||||
private Future toCheck;
|
||||
private String iconName;
|
||||
|
||||
/**
|
||||
* Initialization method
|
||||
*
|
||||
* @param toCheck future representing the image conversion to check on
|
||||
* @param iconName name of the icon being converted by the task to check on
|
||||
*/
|
||||
public void init(Future toCheck, String iconName) {
|
||||
this.toCheck = toCheck;
|
||||
this.iconName = iconName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.util.TimerTask#run()
|
||||
*/
|
||||
public void run() {
|
||||
if (!toCheck.isDone()) {
|
||||
toCheck.cancel(true);
|
||||
err_pr.println("Error: Failed icon conversion on file " + iconName + ".tga");
|
||||
}
|
||||
|
||||
//executor.purge();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
public static void main(String[] args) throws Exception{
|
||||
|
||||
System.out.println("Yar!");
|
||||
icons = true;
|
||||
iconTemplate = readTemplate("templates" + fileSeparator + "english" + fileSeparator + "icon.html");
|
||||
System.out.println(buildImg("test"));
|
||||
|
||||
ImageIO.setUseCache(false);
|
||||
Iterator<ImageReader> it = ImageIO.getImageReadersByMIMEType("image/targa");
|
||||
while(it.hasNext())
|
||||
System.out.println(it.next().getFormatName());
|
||||
|
||||
java.awt.image.BufferedImage buf = ImageIO.read(new File("isk_x1app.tga"));
|
||||
System.out.println("Tar!");
|
||||
ImageIO.write(buf, "png", new File("test.png"));
|
||||
System.out.println("Far!");
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,984 @@
|
||||
package prc.autodoc;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static prc.Main.*;
|
||||
import static prc.autodoc.EntryGeneration.*;
|
||||
import static prc.autodoc.MenuGeneration.*;
|
||||
import static prc.autodoc.PageGeneration.*;
|
||||
|
||||
/**
|
||||
* The main purpose of this autodocumenter is to create parts of the manual for
|
||||
* the PRC pack from 2da and TLK files. As a side effect of doing so, it finds
|
||||
* many errors present in the 2das.
|
||||
*/
|
||||
public class Main {
|
||||
/**
|
||||
* A small data structure class that gives access to both normal and custom
|
||||
* TLK with the same method
|
||||
*/
|
||||
public static class TLKStore {
|
||||
private final Data_TLK normal;
|
||||
private final Data_TLK custom;
|
||||
|
||||
/**
|
||||
* Creates a new TLKStore around the given two filenames. Equivalent to
|
||||
* TLKStore(normalName, customName, "tlk").
|
||||
*
|
||||
* @param normalName dialog.tlk or equivalent for the given language
|
||||
* @param customName prc_consortium.tlk or equivalent for the given languag
|
||||
* @throws TLKReadException if there are any problems reading either TLK
|
||||
*/
|
||||
public TLKStore(String normalName, String customName) {
|
||||
this.normal = new Data_TLK("tlk" + fileSeparator + normalName);
|
||||
this.custom = new Data_TLK("tlk" + fileSeparator + customName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TLKStore around the given two filenames.
|
||||
*
|
||||
* @param normalName dialog.tlk or equivalent for the given language
|
||||
* @param customName prc_consortium.tlk or equivalent for the given languag
|
||||
* @param tlkDir Directory containing the two .tlk files
|
||||
* @throws TLKReadException if there are any problems reading either TLK
|
||||
*/
|
||||
public TLKStore(String normalName, String customName, String tlkDir) {
|
||||
this.normal = new Data_TLK(tlkDir + fileSeparator + normalName);
|
||||
this.custom = new Data_TLK(tlkDir + fileSeparator + customName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the TLK entry for the given StrRef. If there is nothing
|
||||
* at the location, returns Bad StrRef. Automatically picks between
|
||||
* normal and custom TLKs.
|
||||
*
|
||||
* @param num the line number in TLK
|
||||
* @return the contents of the given TLK slot, or Bad StrRef
|
||||
*/
|
||||
public String get(int num) {
|
||||
return num < 0x01000000 ? normal.getEntry(num) : custom.getEntry(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* See above, except that this one automatically parses the string for
|
||||
* the number.
|
||||
*
|
||||
* @param num the line number in TLK as string
|
||||
* @return as above, except it returns Bad StrRef in case parsing failed
|
||||
*/
|
||||
public String get(String num) {
|
||||
try {
|
||||
return get(Integer.parseInt(num));
|
||||
} catch (NumberFormatException e) {
|
||||
return Main.badStrRef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Another data structure class. Stores 2das and handles loading them.
|
||||
*/
|
||||
public static class TwoDAStore {
|
||||
private static class Loader implements Runnable {
|
||||
private final String pathToLoad;
|
||||
private final List<Data_2da> list;
|
||||
private final CountDownLatch latch;
|
||||
|
||||
/**
|
||||
* Creates a new Loader to load the given 2da file
|
||||
*
|
||||
* @param pathToLoad path of the 2da to load
|
||||
* @param list list to store the loaded data into
|
||||
* @param latch latch to countdown on once loading is complete
|
||||
*/
|
||||
public Loader(String pathToLoad, List<Data_2da> list, CountDownLatch latch) {
|
||||
this.pathToLoad = pathToLoad;
|
||||
this.list = list;
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
Data_2da data = Data_2da.load2da(pathToLoad, true);
|
||||
list.add(data);
|
||||
latch.countDown();
|
||||
} catch (Exception e) {
|
||||
err_pr.println("Error: Failure while reading main 2das. Exception data:\n");
|
||||
err_pr.printException(e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final HashMap<String, Data_2da> data = new HashMap<String, Data_2da>();
|
||||
private final String twoDAPath;
|
||||
|
||||
/**
|
||||
* Creates a new TwoDAStore, without preloading anything.
|
||||
*
|
||||
* @param twoDAPath Path of the directory containing 2da files.
|
||||
*/
|
||||
public TwoDAStore(String twoDAPath) {
|
||||
this.twoDAPath = twoDAPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new TwoDAStore with all the main 2das preread in.
|
||||
* On a read failure, kills program execution, since there's nothing
|
||||
* that could be done anyway.
|
||||
*/
|
||||
public TwoDAStore() {
|
||||
this("2da");
|
||||
//long start = System.currentTimeMillis();
|
||||
if (verbose) System.out.print("Loading main 2da files ");
|
||||
boolean oldVerbose = verbose;
|
||||
verbose = false;
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(7);
|
||||
List<Data_2da> list = Collections.synchronizedList(new ArrayList<Data_2da>());
|
||||
// Read the main 2das
|
||||
new Thread(new Loader("2da" + fileSeparator + "classes.2da", list, latch)).start();
|
||||
new Thread(new Loader("2da" + fileSeparator + "domains.2da", list, latch)).start();
|
||||
new Thread(new Loader("2da" + fileSeparator + "feat.2da", list, latch)).start();
|
||||
new Thread(new Loader("2da" + fileSeparator + "masterfeats.2da", list, latch)).start();
|
||||
new Thread(new Loader("2da" + fileSeparator + "racialtypes.2da", list, latch)).start();
|
||||
new Thread(new Loader("2da" + fileSeparator + "skills.2da", list, latch)).start();
|
||||
new Thread(new Loader("2da" + fileSeparator + "spells.2da", list, latch)).start();
|
||||
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
err_pr.println("Error: Interrupted while reading main 2das. Exception data:\n");
|
||||
err_pr.printException(e);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
for (Data_2da entry : list)
|
||||
data.put(entry.getName(), entry);
|
||||
verbose = oldVerbose;
|
||||
if (verbose) System.out.println("- Done");
|
||||
/*
|
||||
try{
|
||||
data.put("classes", new Data_2da("2da" + fileSeparator + "classes.2da"));
|
||||
data.put("domains", new Data_2da("2da" + fileSeparator + "domains.2da"));
|
||||
data.put("feat", new Data_2da("2da" + fileSeparator + "feat.2da"));
|
||||
data.put("masterfeats", new Data_2da("2da" + fileSeparator + "masterfeats.2da"));
|
||||
data.put("racialtypes", new Data_2da("2da" + fileSeparator + "racialtypes.2da"));
|
||||
data.put("skills", new Data_2da("2da" + fileSeparator + "skills.2da"));
|
||||
data.put("spells", new Data_2da("2da" + fileSeparator + "spells.2da"));
|
||||
}catch(Exception e){
|
||||
err_pr.println("Error: Failure while reading main 2das. Exception data:\n");
|
||||
err_pr.printException(e);
|
||||
System.exit(1);
|
||||
}
|
||||
*/
|
||||
//System.out.println("Time taken: " + (System.currentTimeMillis() - start));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Data_2da structure wrapping the given 2da. If it hasn't been loaded
|
||||
* yet, the loading is done now.
|
||||
*
|
||||
* @param name name of the 2da to get. Without the file end ".2da".
|
||||
* @return a Data_2da structure
|
||||
* @throws TwoDAReadException if any errors are encountered while reading
|
||||
*/
|
||||
public Data_2da get(String name) {
|
||||
if (data.containsKey(name))
|
||||
return data.get(name);
|
||||
else {
|
||||
Data_2da temp = null;
|
||||
try {
|
||||
temp = Data_2da.load2da(twoDAPath + fileSeparator + name + ".2da", true);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new TwoDAReadException("Problem with filename when trying to read from 2da:\n" + e);
|
||||
}
|
||||
data.put(name, temp);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class for handling the settings file.
|
||||
*/
|
||||
public static class Settings {
|
||||
/* Some pattern matchers for use when parsing the settings file */
|
||||
private final Matcher mainMatch = Pattern.compile("\\S+:").matcher("");
|
||||
private final Matcher paraMatch = Pattern.compile("\"[^\"]+\"").matcher("");
|
||||
private final Matcher langMatch = Pattern.compile("\\w+=\"[^\"]+\"").matcher("");
|
||||
|
||||
/* An enumeration of the possible setting types */
|
||||
private enum Modes {
|
||||
/**
|
||||
* The parser is currently working on lines specifying languages used.
|
||||
*/
|
||||
LANGUAGE,
|
||||
/**
|
||||
* The parser is currently working on lines containing string patterns that are
|
||||
* used in differentiating between entries in spells.2da.
|
||||
*/
|
||||
SIGNATURE,
|
||||
/**
|
||||
* The parser is currently working on lines listing spells.2da entries that contain
|
||||
* a significantly modified BW spell.
|
||||
*/
|
||||
MODIFIED_SPELL
|
||||
}
|
||||
|
||||
/* Settings data read in */
|
||||
/**
|
||||
* The settings for languages. An ArrayList of String[] containing setting for a specific language
|
||||
*/
|
||||
public ArrayList<String[]> languages = new ArrayList<String[]>();
|
||||
/**
|
||||
* An ArrayList of Integers. Indices to spells.2da of standard spells modified by the PRC
|
||||
*/
|
||||
public ArrayList<Integer> modifiedSpells = new ArrayList<Integer>();
|
||||
/**
|
||||
* A set of script name prefixes used to find epic spell entries in spells.2da
|
||||
*/
|
||||
public String[] epicspellSignatures = null;
|
||||
/*/** A set of script name prefixes used to find psionic power entries in spells.2da *
|
||||
public String[] psionicpowerSignatures = null;*/
|
||||
|
||||
/**
|
||||
* Read the settings file in and store the data for later access.
|
||||
* Terminates execution on any errors.
|
||||
*/
|
||||
public Settings() {
|
||||
try {
|
||||
// The settings file should be present in the directory this is run from
|
||||
Scanner reader = new Scanner(new File("settings"));
|
||||
String check;
|
||||
Modes mode = null;
|
||||
while (reader.hasNextLine()) {
|
||||
check = reader.nextLine();
|
||||
|
||||
// Skip comments and blank lines
|
||||
if (check.startsWith("#") || check.trim().equals("")) continue;
|
||||
|
||||
// Check if a new rule is starting
|
||||
mainMatch.reset(check);
|
||||
if (mainMatch.find()) {
|
||||
if (mainMatch.group().equals("language:")) mode = Modes.LANGUAGE;
|
||||
else if (mainMatch.group().equals("signature:")) mode = Modes.SIGNATURE;
|
||||
else if (mainMatch.group().equals("modified_spell:")) mode = Modes.MODIFIED_SPELL;
|
||||
else {
|
||||
throw new Exception("Unrecognized setting detected");
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Take action based on current mode
|
||||
if (mode == Modes.LANGUAGE) {
|
||||
String[] temp = new String[LANGDATA_NUMENTRIES];
|
||||
String result;
|
||||
langMatch.reset(check);
|
||||
// parse the language entry
|
||||
for (int i = 0; i < LANGDATA_NUMENTRIES; i++) {
|
||||
if (!langMatch.find())
|
||||
throw new Exception("Missing language parameter");
|
||||
result = langMatch.group();
|
||||
|
||||
if (result.startsWith("name=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_LANGNAME] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("base=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_BASETLK] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("prc=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_PRCTLK] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("feats=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_FEATSTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("allfeats=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_ALLFEATSTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("epicfeats=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_EPICFEATSTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("allepicfeats=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_ALLEPICFEATSTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("baseclasses=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_BASECLASSESTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("prestigeclasses=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_PRESTIGECLASSESTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("spells=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_SPELLSTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("epicspells=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_EPICSPELLSTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("psipowers=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_PSIONICPOWERSTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("modspells=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_MODIFIEDSPELLSTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("skills=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_SKILLSTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("domains=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_DOMAINSTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("races=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_RACESTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("spellbook=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_SPELLBOOKTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("powers=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_POWERTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("truenameutterances=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_TRUENAMEUTTERANCETXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("invocations=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_INVOCATIONTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("maneuvers=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_MANEUVERTXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else if (result.startsWith("utterances=")) {
|
||||
paraMatch.reset(result);
|
||||
paraMatch.find();
|
||||
temp[LANGDATA_UTTERANCETXT] = paraMatch.group().substring(1, paraMatch.group().length() - 1);
|
||||
} else
|
||||
throw new Exception("Unknown language parameter encountered\n" + check);
|
||||
}
|
||||
languages.add(temp);
|
||||
}
|
||||
// Parse the spell script name signatures
|
||||
if (mode == Modes.SIGNATURE) {
|
||||
String[] temp = check.trim().split("=");
|
||||
if (temp[0].equals("epicspell")) {
|
||||
epicspellSignatures = temp[1].replace("\"", "").split("\\|");
|
||||
}/* Not needed anymore
|
||||
else if(temp[0].equals("psionicpower")){
|
||||
psionicpowerSignatures = temp[1].replace("\"", "").split("\\|");
|
||||
}*/ else
|
||||
throw new Exception("Unknown signature parameter encountered:\n" + check);
|
||||
}
|
||||
// Parse the spell modified spell indices
|
||||
if (mode == Modes.MODIFIED_SPELL) {
|
||||
modifiedSpells.add(Integer.parseInt(check.trim()));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
err_pr.println("Error: Failed to read settings file:\n" + e + "\nAborting");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A small enumeration for use in spell printing methods
|
||||
*/
|
||||
public enum SpellType {
|
||||
/**
|
||||
* The spell is not a real spell or psionic power, instead specifies some feat's spellscript.
|
||||
*/
|
||||
NONE,
|
||||
/**
|
||||
* The spell is a normal spell.
|
||||
*/
|
||||
NORMAL,
|
||||
/**
|
||||
* The spell is an epic spell.
|
||||
*/
|
||||
EPIC,
|
||||
/**
|
||||
* The spell is a psionic power.
|
||||
*/
|
||||
PSIONIC,
|
||||
/**
|
||||
* The spell is a truename utterance.
|
||||
*/
|
||||
UTTERANCE,
|
||||
/**
|
||||
* The spell is an invocation.
|
||||
*/
|
||||
INVOCATION,
|
||||
/**
|
||||
* The spell is a maneuver.
|
||||
*/
|
||||
MANEUVER
|
||||
}
|
||||
|
||||
/**
|
||||
* A switche determinining how errors are handled
|
||||
*/
|
||||
public static boolean tolErr = true;
|
||||
|
||||
/**
|
||||
* A boolean determining whether to print icons for the pages or not
|
||||
*/
|
||||
public static boolean icons = false;
|
||||
|
||||
/**
|
||||
* A constant signifying Bad StrRef
|
||||
*/
|
||||
public static final String badStrRef = "Bad StrRef";
|
||||
|
||||
/**
|
||||
* The container object for general configuration data read from file
|
||||
*/
|
||||
public static Settings settings;// = new Settings();
|
||||
|
||||
/**
|
||||
* The file separator, given it's own constant for ease of use
|
||||
*/
|
||||
public static final String fileSeparator = System.getProperty("file.separator");
|
||||
|
||||
/**
|
||||
* Array of the settings for currently used language. Index with the LANGDATA_ constants
|
||||
*/
|
||||
public static String[] curLanguageData = null;
|
||||
|
||||
/**
|
||||
* Size of the curLanguageData array
|
||||
*/
|
||||
public static final int LANGDATA_NUMENTRIES = 22;
|
||||
/**
|
||||
* curLanguageData index of the language name
|
||||
*/
|
||||
public static final int LANGDATA_LANGNAME = 0;
|
||||
/**
|
||||
* curLanguageData index of the name of the dialog.tlk equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_BASETLK = 1;
|
||||
/**
|
||||
* curLanguageData index of the name of the prc_consortium.tlk equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_PRCTLK = 2;
|
||||
/**
|
||||
* curLanguageData index of the name of the "All Feats" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_ALLFEATSTXT = 3;
|
||||
/**
|
||||
* curLanguageData index of the name of the "All Epic Feats" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_ALLEPICFEATSTXT = 4;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Feats" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_FEATSTXT = 5;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Epic Feats" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_EPICFEATSTXT = 6;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Base Classes" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_BASECLASSESTXT = 7;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Prestige Classes" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_PRESTIGECLASSESTXT = 8;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Spells" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_SPELLSTXT = 9;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Epic Spells" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_EPICSPELLSTXT = 10;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Psionic Powers" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_PSIONICPOWERSTXT = 11;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Modified Spells" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_MODIFIEDSPELLSTXT = 12;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Domains" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_DOMAINSTXT = 13;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Skills" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_SKILLSTXT = 14;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Races" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_RACESTXT = 15;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Spellbook" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_SPELLBOOKTXT = 16;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Powers" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_POWERTXT = 17;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Truename Utterances" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_TRUENAMEUTTERANCETXT = 18;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Invocations" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_INVOCATIONTXT = 19;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Maneuvers" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_MANEUVERTXT = 20;
|
||||
/**
|
||||
* curLanguageData index of the name of the "Utterances" string equivalent for this language
|
||||
*/
|
||||
public static final int LANGDATA_UTTERANCETXT = 21;
|
||||
|
||||
|
||||
/**
|
||||
* Current language name
|
||||
*/
|
||||
public static String curLanguage = null;
|
||||
|
||||
/**
|
||||
* The base path. <code>"manual" + fileSeparator + curLanguage + fileSeparator</code>
|
||||
*/
|
||||
public static String mainPath = null;
|
||||
/**
|
||||
* The path to content directory. <code>mainPath + "content" + fileSeparator</code>
|
||||
*/
|
||||
public static String contentPath = null;
|
||||
/**
|
||||
* The path to menu directory. <code>mainPath + "mainPath" + fileSeparator</code>
|
||||
*/
|
||||
public static String menuPath = null;
|
||||
/**
|
||||
* The path to the image directory. <code>"manual" + fileSeparator + "images" + fileSeparator</code>
|
||||
*/
|
||||
public static String imagePath = "manual" + fileSeparator + "images" + fileSeparator;
|
||||
|
||||
/**
|
||||
* Data structures for accessing TLKs
|
||||
*/
|
||||
public static TwoDAStore twoDA;
|
||||
/**
|
||||
* Data structures for accessing TLKs
|
||||
*/
|
||||
public static TLKStore tlk;
|
||||
|
||||
|
||||
/**
|
||||
* The template files
|
||||
*/
|
||||
public static String babAndSavthrTableHeaderTemplate = null,
|
||||
classTemplate = null,
|
||||
classTablesEntryTemplate = null,
|
||||
domainTemplate = null,
|
||||
featTemplate = null,
|
||||
mFeatTemplate = null,
|
||||
menuTemplate = null,
|
||||
menuItemTemplate = null,
|
||||
prereqANDFeatHeaderTemplate = null,
|
||||
prereqORFeatHeaderTemplate = null,
|
||||
raceTemplate = null,
|
||||
spellTemplate = null,
|
||||
skillTableHeaderTemplate = null,
|
||||
skillTemplate = null,
|
||||
successorFeatHeaderTemplate = null,
|
||||
iconTemplate = null,
|
||||
listEntrySetTemplate = null,
|
||||
listEntryTemplate = null,
|
||||
alphaSortedListTemplate = null,
|
||||
requiredForFeatHeaderTemplate = null,
|
||||
pageLinkTemplate = null,
|
||||
featMenuTemplate = null,
|
||||
spellSubradialListTemplate = null,
|
||||
spellSubradialListEntryTemplate = null,
|
||||
classFeatTableTemplate = null,
|
||||
classFeatTableEntryTemplate = null,
|
||||
classMagicTableTemplate = null,
|
||||
classMagicTableEntryTemplate = null,
|
||||
craftTemplate = null;
|
||||
|
||||
|
||||
/* Data structures to store generated entry data in */
|
||||
public static HashMap<Integer, SpellEntry> spells;
|
||||
public static HashMap<Integer, FeatEntry> masterFeats,
|
||||
feats;
|
||||
public static HashMap<Integer, ClassEntry> classes;
|
||||
public static HashMap<Integer, DomainEntry> domains;
|
||||
public static HashMap<Integer, RaceEntry> races;
|
||||
public static HashMap<Integer, GenericEntry> skills;
|
||||
|
||||
public static HashMap<Integer, GenericEntry> craft_armour;
|
||||
public static HashMap<Integer, GenericEntry> craft_weapon;
|
||||
public static HashMap<Integer, GenericEntry> craft_ring;
|
||||
public static HashMap<Integer, GenericEntry> craft_wondrous;
|
||||
|
||||
/**
|
||||
* Map of psionic power names to the indexes of the spells.2da entries chosen to represent the power in question
|
||||
*/
|
||||
public static HashMap<String, Integer> psiPowMap;
|
||||
|
||||
/**
|
||||
* Map of truenaming utterance names to the spells.2da indexes that contain utterance feat-linked entries
|
||||
*/
|
||||
public static HashMap<String, Integer> utterMap;
|
||||
|
||||
/**
|
||||
* Map of invocations to spells.2da
|
||||
*/
|
||||
public static HashMap<String, Integer> invMap;
|
||||
|
||||
/**
|
||||
* Map of maneuvers to spells.2da
|
||||
*/
|
||||
public static HashMap<String, Integer> maneuverMap;
|
||||
|
||||
|
||||
/**
|
||||
* Ye olde maine methode
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
/* Argument parsing */
|
||||
for (String opt : args) {
|
||||
if (opt.equals("--help"))
|
||||
readMe();
|
||||
|
||||
if (opt.startsWith("-")) {
|
||||
if (opt.contains("a"))
|
||||
tolErr = true;
|
||||
if (opt.contains("q")) {
|
||||
verbose = false;
|
||||
spinner.disable();
|
||||
}
|
||||
if (opt.contains("i"))
|
||||
icons = true;
|
||||
if (opt.contains("s"))
|
||||
spinner.disable();
|
||||
if (opt.contains("?"))
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
|
||||
// Load the settings
|
||||
settings = new Settings();
|
||||
|
||||
// Initialize the 2da container data structure
|
||||
twoDA = new TwoDAStore();
|
||||
|
||||
|
||||
// Print the manual files for each language specified
|
||||
for (int i = 0; i < settings.languages.size(); i++) {
|
||||
// Set language, path and load TLKs
|
||||
curLanguageData = settings.languages.get(i);
|
||||
curLanguage = curLanguageData[LANGDATA_LANGNAME];
|
||||
mainPath = "manual" + fileSeparator + curLanguage + fileSeparator;
|
||||
contentPath = mainPath + "content" + fileSeparator;
|
||||
menuPath = mainPath + "menus" + fileSeparator;
|
||||
|
||||
// If we fail on a language, skip to next one
|
||||
try {
|
||||
tlk = new TLKStore(curLanguageData[LANGDATA_BASETLK], curLanguageData[LANGDATA_PRCTLK]);
|
||||
} catch (TLKReadException e) {
|
||||
err_pr.println("Error: Failure while reading TLKs for language: " + curLanguage + ":\n" + e);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip to next if there is any problem with directories or templates
|
||||
if (!(readTemplates() && buildDirectories())) continue;
|
||||
|
||||
// Do the actual work
|
||||
createPages();
|
||||
createMenus();
|
||||
}
|
||||
|
||||
// Wait for the image conversion to finish before exiting main
|
||||
if (Icons.executor != null) {
|
||||
Icons.executor.shutdown();
|
||||
try {
|
||||
Icons.executor.awaitTermination(120, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
err_pr.println("Error: Interrupted while waiting for image conversion to finish");
|
||||
} finally {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the use instructions for this program and kills execution.
|
||||
*/
|
||||
private static void readMe() {
|
||||
System.out.println("Usage:\n" +
|
||||
" java prc/autodoc/Main [--help][-aiqs?]\n" +
|
||||
"\n" +
|
||||
"-a forces aborting printing on errors\n" +
|
||||
"-i adds icons to pages\n" +
|
||||
"-q quiet mode. Does not print any progress info, only failure messages\n" +
|
||||
"-s disable the spinner. Useful when logging to file\n" +
|
||||
"\n" +
|
||||
"--help prints this info you are reading\n" +
|
||||
"-? see --help\n"
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all the template files for the current language.
|
||||
*
|
||||
* @return <code>true</code> if all the reads succeeded, <code>false</code> otherwise
|
||||
*/
|
||||
private static boolean readTemplates() {
|
||||
String templatePath = "templates" + fileSeparator + curLanguage + fileSeparator;
|
||||
|
||||
try {
|
||||
babAndSavthrTableHeaderTemplate = readTemplate(templatePath + "babNsavthrtableheader.html");
|
||||
classTablesEntryTemplate = readTemplate(templatePath + "classtablesentry.html");
|
||||
classTemplate = readTemplate(templatePath + "class.html");
|
||||
domainTemplate = readTemplate(templatePath + "domain.html");
|
||||
featTemplate = readTemplate(templatePath + "feat.html");
|
||||
mFeatTemplate = readTemplate(templatePath + "masterfeat.html");
|
||||
menuTemplate = readTemplate(templatePath + "menu.html");
|
||||
menuItemTemplate = readTemplate(templatePath + "menuitem.html");
|
||||
prereqANDFeatHeaderTemplate = readTemplate(templatePath + "prerequisiteandfeatheader.html");
|
||||
prereqORFeatHeaderTemplate = readTemplate(templatePath + "prerequisiteorfeatheader.html");
|
||||
raceTemplate = readTemplate(templatePath + "race.html");
|
||||
spellTemplate = readTemplate(templatePath + "spell.html");
|
||||
skillTableHeaderTemplate = readTemplate(templatePath + "skilltableheader.html");
|
||||
skillTemplate = readTemplate(templatePath + "skill.html");
|
||||
successorFeatHeaderTemplate = readTemplate(templatePath + "successorfeatheader.html");
|
||||
iconTemplate = readTemplate(templatePath + "icon.html");
|
||||
listEntrySetTemplate = readTemplate(templatePath + "listpageentryset.html");
|
||||
listEntryTemplate = readTemplate(templatePath + "listpageentry.html");
|
||||
alphaSortedListTemplate = readTemplate(templatePath + "alphasorted_listpage.html");
|
||||
requiredForFeatHeaderTemplate = readTemplate(templatePath + "reqforfeatheader.html");
|
||||
pageLinkTemplate = readTemplate(templatePath + "pagelink.html");
|
||||
featMenuTemplate = readTemplate(templatePath + "featmenu.html");
|
||||
spellSubradialListTemplate = readTemplate(templatePath + "spellsubradials.html");
|
||||
spellSubradialListEntryTemplate = readTemplate(templatePath + "spellsubradialsentry.html");
|
||||
classFeatTableTemplate = readTemplate(templatePath + "classfeattable.html");
|
||||
classFeatTableEntryTemplate = readTemplate(templatePath + "classfeattableentry.html");
|
||||
classMagicTableTemplate = readTemplate(templatePath + "classmagictable.html");
|
||||
classMagicTableEntryTemplate = readTemplate(templatePath + "classmagictableentry.html");
|
||||
craftTemplate = readTemplate(templatePath + "craftprop.html");
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the template file given as parameter and returns a string with it's contents
|
||||
* Kills execution if any operations fail.
|
||||
*
|
||||
* @param filePath string representing the path of the template file
|
||||
* @return the contents of the template file as a string
|
||||
* @throws IOException if the reading fails
|
||||
*/
|
||||
private static String readTemplate(String filePath) throws IOException {
|
||||
try {
|
||||
Scanner reader = new Scanner(new File(filePath));
|
||||
StringBuffer temp = new StringBuffer();
|
||||
|
||||
while (reader.hasNextLine()) temp.append(reader.nextLine() + "\n");
|
||||
|
||||
return temp.toString();
|
||||
} catch (Exception e) {
|
||||
err_pr.println("Error: Failed to read template file:\n" + e);
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the directory structure for the current language
|
||||
* being processed.
|
||||
*
|
||||
* @return <code>true</code> if all directories are successfully created,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
private static boolean buildDirectories() {
|
||||
String dirPath = mainPath + "content";
|
||||
|
||||
boolean toReturn = buildDir(dirPath);
|
||||
dirPath += fileSeparator;
|
||||
|
||||
toReturn = toReturn
|
||||
&& buildDir(dirPath + "base_classes")
|
||||
&& buildDir(dirPath + "class_epic_feats")
|
||||
&& buildDir(dirPath + "class_feats")
|
||||
&& buildDir(dirPath + "domains")
|
||||
&& buildDir(dirPath + "epic_feats")
|
||||
&& buildDir(dirPath + "epic_spells")
|
||||
&& buildDir(dirPath + "feats")
|
||||
&& buildDir(dirPath + "itemcrafting")
|
||||
&& buildDir(dirPath + "master_feats")
|
||||
&& buildDir(dirPath + "prestige_classes")
|
||||
&& buildDir(dirPath + "psionic_powers")
|
||||
&& buildDir(dirPath + "races")
|
||||
&& buildDir(dirPath + "skills")
|
||||
&& buildDir(dirPath + "spells")
|
||||
&& buildDir(dirPath + "utterances")
|
||||
&& buildDir(dirPath + "invocations")
|
||||
&& buildDir(dirPath + "maneuvers")
|
||||
|
||||
&& buildDir(mainPath + "menus");
|
||||
|
||||
System.gc();
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the actual work of building the directories
|
||||
*
|
||||
* @param path the target directory to create
|
||||
* @return <code>true</code> if the directory was already present or was successfully created,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
private static boolean buildDir(String path) {
|
||||
File builder = new File(path);
|
||||
if (!builder.exists()) {
|
||||
if (!builder.mkdirs()) {
|
||||
err_pr.println("Error: Failure creating directory:\n" + builder.getPath());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!builder.isDirectory()) {
|
||||
err_pr.println(builder.getPath() + " already exists as a file!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replaces each line break in the given TLK entry with
|
||||
* a line break followed by <code><br /></code>.
|
||||
*
|
||||
* @param toHTML tlk entry to convert
|
||||
* @return the modified string
|
||||
*/
|
||||
public static String htmlizeTLK(String toHTML) {
|
||||
return toHTML.replaceAll("\n", "\n<br />");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new file at the given <code>path</code>, erasing previous file if present.
|
||||
* Prints the given <code>content</code> string into the file.
|
||||
*
|
||||
* @param path the path of the file to be created
|
||||
* @param content the string to be printed into the file
|
||||
* @throws PageGenerationException if one of the file operations fails
|
||||
*/
|
||||
public static void printPage(String path, String content) {
|
||||
try {
|
||||
File target = new File(path);
|
||||
// Clean up old version if necessary
|
||||
if (target.exists()) {
|
||||
if (verbose) System.out.println("Deleting previous version of " + path);
|
||||
target.delete();
|
||||
}
|
||||
target.createNewFile();
|
||||
|
||||
// Creater the writer and print
|
||||
FileWriter writer = new FileWriter(target, false);
|
||||
writer.write(content);
|
||||
// Clean up
|
||||
writer.flush();
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
throw new PageGenerationException("IOException when printing " + path, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Page creation. Calls all the specific functions for different page types
|
||||
*/
|
||||
private static void createPages() {
|
||||
/* First, do the pages that do not require linking to other pages */
|
||||
doSkills();
|
||||
doCrafting();
|
||||
listPsionicPowers();
|
||||
listTruenameUtterances();
|
||||
listInvocations();
|
||||
listManeuvers();
|
||||
doSpells();
|
||||
|
||||
/* Then, build the feats */
|
||||
preliMasterFeats();
|
||||
preliFeats();
|
||||
linkFeats();
|
||||
|
||||
/* Last, domains, races and classes, which all link to the previous */
|
||||
doDomains();
|
||||
doRaces();
|
||||
doClasses();
|
||||
|
||||
/* Then, print all of it */
|
||||
printSkills();
|
||||
printSpells();
|
||||
printFeats();
|
||||
printDomains();
|
||||
printRaces();
|
||||
printClasses();
|
||||
printCrafting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu creation. Calls the specific functions for different menu types
|
||||
*/
|
||||
private static void createMenus() {
|
||||
/* First, the types that do not need any extra data beyond name & path
|
||||
* and use GenericEntry
|
||||
*/
|
||||
doGenericMenu(skills, curLanguageData[LANGDATA_SKILLSTXT], "manual_menus_skills.html");
|
||||
doGenericMenu(domains, curLanguageData[LANGDATA_DOMAINSTXT], "manual_menus_domains.html");
|
||||
doGenericMenu(races, curLanguageData[LANGDATA_RACESTXT], "manual_menus_races.html");
|
||||
doGenericMenu(craft_armour, curLanguageData[LANGDATA_SKILLSTXT], "manual_menus_craft_armour.html");
|
||||
doGenericMenu(craft_weapon, curLanguageData[LANGDATA_SKILLSTXT], "manual_menus_craft_weapon.html");
|
||||
doGenericMenu(craft_ring, curLanguageData[LANGDATA_SKILLSTXT], "manual_menus_craft_ring.html");
|
||||
doGenericMenu(craft_wondrous, curLanguageData[LANGDATA_SKILLSTXT], "manual_menus_craft_wondrous.html");
|
||||
/* Then the more specialised data where it needs to be split over several
|
||||
* menu pages
|
||||
*/
|
||||
doSpellMenus();
|
||||
doFeatMenus();
|
||||
doClassMenus();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,263 @@
|
||||
package prc.autodoc;
|
||||
|
||||
//import java.io.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static prc.Main.verbose;
|
||||
import static prc.autodoc.Main.*;
|
||||
import static prc.autodoc.Main.SpellType.*;
|
||||
|
||||
public final class MenuGeneration {
|
||||
private MenuGeneration() {/* No instances */}
|
||||
|
||||
/**
|
||||
* Sorts any of the pages for which GenericEntry is enough into alphabetic order
|
||||
* using a TreeMap, and prints a menu page out of the results.
|
||||
*/
|
||||
public static void doGenericMenu(HashMap<Integer, ? extends GenericEntry> entries, String menuName, String menuFileName) {
|
||||
TreeMap<String, String> links = new TreeMap<String, String>();
|
||||
StringBuffer toPrint = new StringBuffer();
|
||||
|
||||
if (verbose) System.out.println("Printing menu for " + menuName);
|
||||
|
||||
for (GenericEntry entry : entries.values()) {
|
||||
links.put(entry.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
entry.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", entry.name));
|
||||
}
|
||||
|
||||
while (links.size() > 0) {
|
||||
toPrint.append(links.remove(links.firstKey()));
|
||||
}
|
||||
|
||||
printPage(menuPath + menuFileName, menuTemplate.replaceAll("~~~menuName~~~", menuName)
|
||||
.replaceAll("~~~menuEntries~~~", toPrint.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the spells into alphabetic order using a TreeMap, and prints a menu
|
||||
* page out of the results. Normal, epic and psionics get their own menus
|
||||
*/
|
||||
public static void doSpellMenus() {
|
||||
TreeMap<String, String> normalSpellLinks = new TreeMap<String, String>(),
|
||||
epicSpellLinks = new TreeMap<String, String>(),
|
||||
psionicPowerLinks = new TreeMap<String, String>(),
|
||||
utteranceLinks = new TreeMap<String, String>(),
|
||||
invocationLinks = new TreeMap<String, String>(),
|
||||
maneuverLinks = new TreeMap<String, String>(),
|
||||
modSpellLinks = new TreeMap<String, String>();
|
||||
StringBuffer normalPrint = new StringBuffer(),
|
||||
epicPrint = new StringBuffer(),
|
||||
psionicPrint = new StringBuffer(),
|
||||
utterancePrint = new StringBuffer(),
|
||||
invocationPrint = new StringBuffer(),
|
||||
maneuverPrint = new StringBuffer(),
|
||||
modSpellPrint = new StringBuffer();
|
||||
String temp = null;
|
||||
|
||||
if (verbose) System.out.println("Printing spell menus");
|
||||
|
||||
for (SpellEntry spell : spells.values()) {
|
||||
switch (spell.type) {
|
||||
case NORMAL:
|
||||
normalSpellLinks.put(spell.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
spell.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", spell.name));
|
||||
break;
|
||||
case EPIC:
|
||||
temp = spell.name.startsWith("Epic Spell: ") ? spell.name.substring(12) : spell.name;
|
||||
epicSpellLinks.put(spell.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
spell.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", temp));
|
||||
break;
|
||||
case PSIONIC:
|
||||
psionicPowerLinks.put(spell.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
spell.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", spell.name));
|
||||
break;
|
||||
case UTTERANCE:
|
||||
utteranceLinks.put(spell.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
spell.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", spell.name));
|
||||
break;
|
||||
case INVOCATION:
|
||||
invocationLinks.put(spell.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
spell.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", spell.name));
|
||||
break;
|
||||
case MANEUVER:
|
||||
maneuverLinks.put(spell.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
spell.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", spell.name));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new AssertionError("Unhandled spelltype: " + spell.type);
|
||||
}
|
||||
|
||||
if (settings.modifiedSpells.contains(spell.entryNum))
|
||||
modSpellLinks.put(spell.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
spell.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", spell.name));
|
||||
}
|
||||
|
||||
while (normalSpellLinks.size() > 0)
|
||||
normalPrint.append(normalSpellLinks.remove(normalSpellLinks.firstKey()));
|
||||
while (epicSpellLinks.size() > 0)
|
||||
epicPrint.append(epicSpellLinks.remove(epicSpellLinks.firstKey()));
|
||||
while (psionicPowerLinks.size() > 0)
|
||||
psionicPrint.append(psionicPowerLinks.remove(psionicPowerLinks.firstKey()));
|
||||
while (utteranceLinks.size() > 0)
|
||||
utterancePrint.append(utteranceLinks.remove(utteranceLinks.firstKey()));
|
||||
while (invocationLinks.size() > 0)
|
||||
invocationPrint.append(invocationLinks.remove(invocationLinks.firstKey()));
|
||||
while (maneuverLinks.size() > 0)
|
||||
maneuverPrint.append(maneuverLinks.remove(maneuverLinks.firstKey()));
|
||||
while (modSpellLinks.size() > 0)
|
||||
modSpellPrint.append(modSpellLinks.remove(modSpellLinks.firstKey()));
|
||||
|
||||
printPage(menuPath + "manual_menus_spells.html", menuTemplate.replaceAll("~~~menuName~~~", curLanguageData[LANGDATA_SPELLSTXT])
|
||||
.replaceAll("~~~menuEntries~~~", normalPrint.toString()));
|
||||
printPage(menuPath + "manual_menus_epic_spells.html", menuTemplate.replaceAll("~~~menuName~~~", curLanguageData[LANGDATA_EPICSPELLSTXT])
|
||||
.replaceAll("~~~menuEntries~~~", epicPrint.toString()));
|
||||
printPage(menuPath + "manual_menus_psionic_powers.html", menuTemplate.replaceAll("~~~menuName~~~", curLanguageData[LANGDATA_PSIONICPOWERSTXT])
|
||||
.replaceAll("~~~menuEntries~~~", psionicPrint.toString()));
|
||||
printPage(menuPath + "manual_menus_truename_utterances.html", menuTemplate.replaceAll("~~~menuName~~~", curLanguageData[LANGDATA_TRUENAMEUTTERANCETXT])
|
||||
.replaceAll("~~~menuEntries~~~", utterancePrint.toString()));
|
||||
printPage(menuPath + "manual_menus_invocations.html", menuTemplate.replaceAll("~~~menuName~~~", curLanguageData[LANGDATA_INVOCATIONTXT])
|
||||
.replaceAll("~~~menuEntries~~~", invocationPrint.toString()));
|
||||
printPage(menuPath + "manual_menus_maneuvers.html", menuTemplate.replaceAll("~~~menuName~~~", curLanguageData[LANGDATA_MANEUVERTXT])
|
||||
.replaceAll("~~~menuEntries~~~", maneuverPrint.toString()));
|
||||
printPage(menuPath + "manual_menus_modified_spells.html", menuTemplate.replaceAll("~~~menuName~~~", curLanguageData[LANGDATA_MODIFIEDSPELLSTXT])
|
||||
.replaceAll("~~~menuEntries~~~", modSpellPrint.toString()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sorts the feats into alphabetic order using a TreeMap, and prints a menu
|
||||
* page out of the results. Normal and epic feats get their own menus and class feats
|
||||
* are skipped.
|
||||
*/
|
||||
public static void doFeatMenus() {
|
||||
TreeMap<String, String> normalFeatLinks = new TreeMap<String, String>(),
|
||||
normalMasterfeatLinks = new TreeMap<String, String>(),
|
||||
epicFeatLinks = new TreeMap<String, String>(),
|
||||
epicMasterfeatLinks = new TreeMap<String, String>();
|
||||
StringBuffer normalList = new StringBuffer(),
|
||||
normalMasterList = new StringBuffer(),
|
||||
epicList = new StringBuffer(),
|
||||
epicMasterList = new StringBuffer();
|
||||
String temp = null;
|
||||
String normalMenu = featMenuTemplate,
|
||||
epicMenu = featMenuTemplate;
|
||||
|
||||
if (verbose) System.out.println("Printing feat menus");
|
||||
|
||||
// Print names
|
||||
normalMenu = normalMenu.replaceAll("~~~menuName~~~", curLanguageData[LANGDATA_FEATSTXT]);
|
||||
epicMenu = epicMenu.replaceAll("~~~menuName~~~", curLanguageData[LANGDATA_EPICFEATSTXT]);
|
||||
|
||||
// Parse through feats
|
||||
for (FeatEntry feat : feats.values()) {
|
||||
// Skip class feats and feats with masterfeat or a predecessor
|
||||
if (feat.isClassFeat || feat.isSuccessor || feat.master != null) continue;
|
||||
if (!feat.isEpic)
|
||||
normalFeatLinks.put(feat.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
feat.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", feat.name));
|
||||
else
|
||||
epicFeatLinks.put(feat.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
feat.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", feat.name));
|
||||
}
|
||||
|
||||
// Transfer the feat link lists into text form
|
||||
while (normalFeatLinks.size() > 0)
|
||||
normalList.append(normalFeatLinks.remove(normalFeatLinks.firstKey()));
|
||||
while (epicFeatLinks.size() > 0)
|
||||
epicList.append(epicFeatLinks.remove(epicFeatLinks.firstKey()));
|
||||
|
||||
// Parse through masterfeats
|
||||
for (FeatEntry masterfeat : masterFeats.values()) {
|
||||
if (masterfeat.isClassFeat && masterfeat.allChildrenClassFeat) continue;
|
||||
if (masterfeat.isEpic)
|
||||
epicMasterfeatLinks.put(masterfeat.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
masterfeat.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", masterfeat.name));
|
||||
if (!masterfeat.allChildrenEpic)
|
||||
normalMasterfeatLinks.put(masterfeat.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
masterfeat.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", masterfeat.name));
|
||||
}
|
||||
|
||||
// Transfer the masterfeat link lists into text form
|
||||
while (normalMasterfeatLinks.size() > 0)
|
||||
normalMasterList.append(normalMasterfeatLinks.remove(normalMasterfeatLinks.firstKey()));
|
||||
while (epicMasterfeatLinks.size() > 0)
|
||||
epicMasterList.append(epicMasterfeatLinks.remove(epicMasterfeatLinks.firstKey()));
|
||||
|
||||
// Add in a link to the page listing *all* feats
|
||||
normalMenu = normalMenu.replaceAll("~~~allFeatsLink~~~", menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
(contentPath + "feats" + fileSeparator + "alphasortedfeats.html")
|
||||
.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", curLanguageData[LANGDATA_ALLFEATSTXT]));
|
||||
|
||||
// Add in a link to the page listing all epic feats
|
||||
epicMenu = epicMenu.replaceAll("~~~allFeatsLink~~~", menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
(contentPath + "epic_feats" + fileSeparator + "alphasortedepicfeats.html")
|
||||
.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", curLanguageData[LANGDATA_ALLEPICFEATSTXT]));
|
||||
|
||||
// Add in the masterfeat links
|
||||
normalMenu = normalMenu.replaceAll("~~~masterFeats~~~", normalMasterList.toString());
|
||||
epicMenu = epicMenu.replaceAll("~~~masterFeats~~~", epicMasterList.toString());
|
||||
|
||||
// Add in the feat links
|
||||
normalMenu = normalMenu.replaceAll("~~~featLinks~~~", normalList.toString());
|
||||
epicMenu = epicMenu.replaceAll("~~~featLinks~~~", epicList.toString());
|
||||
|
||||
// Print the pages
|
||||
printPage(menuPath + "manual_menus_feat.html", normalMenu);
|
||||
printPage(menuPath + "manual_menus_epic_feat.html", epicMenu);
|
||||
}
|
||||
|
||||
//private static void doFeatMenusAux()
|
||||
|
||||
|
||||
/**
|
||||
* Sorts the classes into alphabetic order using a TreeMap, and prints a menu
|
||||
* page out of the results. Base and prestige classes get their own menus
|
||||
*/
|
||||
public static void doClassMenus() {
|
||||
TreeMap<String, String> baseLinks = new TreeMap<String, String>(),
|
||||
prestigeLinks = new TreeMap<String, String>();
|
||||
StringBuffer basePrint = new StringBuffer(),
|
||||
prestigePrint = new StringBuffer();
|
||||
String temp = null;
|
||||
|
||||
if (verbose) System.out.println("Printing class menus");
|
||||
|
||||
for (ClassEntry clazz : classes.values()) {
|
||||
if (clazz.isBase)
|
||||
baseLinks.put(clazz.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
clazz.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", clazz.name));
|
||||
else
|
||||
prestigeLinks.put(clazz.name, menuItemTemplate.replaceAll("~~~TargetPath~~~",
|
||||
clazz.filePath.replace(mainPath, "../").replaceAll("\\\\", "/"))
|
||||
.replaceAll("~~~targetName~~~", clazz.name));
|
||||
}
|
||||
|
||||
while (baseLinks.size() > 0)
|
||||
basePrint.append(baseLinks.remove(baseLinks.firstKey()));
|
||||
while (prestigeLinks.size() > 0)
|
||||
prestigePrint.append(prestigeLinks.remove(prestigeLinks.firstKey()));
|
||||
|
||||
printPage(menuPath + "manual_menus_base_classes.html", menuTemplate.replaceAll("~~~menuName~~~", curLanguageData[LANGDATA_BASECLASSESTXT])
|
||||
.replaceAll("~~~menuEntries~~~", basePrint.toString()));
|
||||
printPage(menuPath + "manual_menus_prestige_classes.html", menuTemplate.replaceAll("~~~menuName~~~", curLanguageData[LANGDATA_PRESTIGECLASSESTXT])
|
||||
.replaceAll("~~~menuEntries~~~", prestigePrint.toString()));
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,602 @@
|
||||
package prc.autodoc;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static prc.Main.err_pr;
|
||||
import static prc.Main.verbose;
|
||||
import static prc.autodoc.Main.*;
|
||||
|
||||
/**
|
||||
* This class contains the methods for manual page generation.
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public final class PageGeneration {
|
||||
private PageGeneration() {/* No need for instantiation */}
|
||||
|
||||
/**
|
||||
* Handles printing of the skill pages.
|
||||
*/
|
||||
public static void printSkills() {
|
||||
String text = null;
|
||||
|
||||
for (GenericEntry skill : skills.values()) {
|
||||
if (verbose) System.out.println("Printing page for " + skill.name);
|
||||
// Start building the entry data. First, place in the name
|
||||
text = skillTemplate;
|
||||
text = text.replaceAll("~~~SkillName~~~", skill.name);
|
||||
// Then, put in the description
|
||||
text = text.replaceAll("~~~SkillTLKDescription~~~",
|
||||
skill.text);
|
||||
// Add in the icon
|
||||
text = text.replaceAll("~~~Icon~~~", skill.iconPath);
|
||||
|
||||
// Print the page
|
||||
try {
|
||||
printPage(skill.filePath, text);
|
||||
} catch (PageGenerationException e) {
|
||||
err_pr.println("Error: Exception when writing page for skill " + skill.entryNum + ": " + skill.name + ":\n" + e);
|
||||
}
|
||||
}
|
||||
System.gc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles printing of the crafting property pages.
|
||||
*/
|
||||
public static void printCrafting() {
|
||||
String text = null;
|
||||
|
||||
for (GenericEntry craft_armour_var : craft_armour.values()) {
|
||||
if (verbose) System.out.println("Printing page for " + craft_armour_var.name);
|
||||
// Start building the entry data. First, place in the name
|
||||
text = craftTemplate;
|
||||
text = text.replaceAll("~~~CraftPropName~~~", craft_armour_var.name);
|
||||
// Then, put in the description
|
||||
text = text.replaceAll("~~~CraftPropTLKDescription~~~",
|
||||
craft_armour_var.text);
|
||||
// Print the page
|
||||
try {
|
||||
printPage(craft_armour_var.filePath, text);
|
||||
} catch (PageGenerationException e) {
|
||||
err_pr.println("Error: Exception when writing page for skill " + craft_armour_var.entryNum + ": " + craft_armour_var.name + ":\n" + e);
|
||||
}
|
||||
}
|
||||
for (GenericEntry craft_weapon_var : craft_weapon.values()) {
|
||||
if (verbose) System.out.println("Printing page for " + craft_weapon_var.name);
|
||||
// Start building the entry data. First, place in the name
|
||||
text = craftTemplate;
|
||||
text = text.replaceAll("~~~CraftPropName~~~", craft_weapon_var.name);
|
||||
// Then, put in the description
|
||||
text = text.replaceAll("~~~CraftPropTLKDescription~~~",
|
||||
craft_weapon_var.text);
|
||||
// Print the page
|
||||
try {
|
||||
printPage(craft_weapon_var.filePath, text);
|
||||
} catch (PageGenerationException e) {
|
||||
err_pr.println("Error: Exception when writing page for skill " + craft_weapon_var.entryNum + ": " + craft_weapon_var.name + ":\n" + e);
|
||||
}
|
||||
}
|
||||
for (GenericEntry craft_ring_var : craft_ring.values()) {
|
||||
if (verbose) System.out.println("Printing page for " + craft_ring_var.name);
|
||||
// Start building the entry data. First, place in the name
|
||||
text = craftTemplate;
|
||||
text = text.replaceAll("~~~CraftPropName~~~", craft_ring_var.name);
|
||||
// Then, put in the description
|
||||
text = text.replaceAll("~~~CraftPropTLKDescription~~~",
|
||||
craft_ring_var.text);
|
||||
// Print the page
|
||||
try {
|
||||
printPage(craft_ring_var.filePath, text);
|
||||
} catch (PageGenerationException e) {
|
||||
err_pr.println("Error: Exception when writing page for skill " + craft_ring_var.entryNum + ": " + craft_ring_var.name + ":\n" + e);
|
||||
}
|
||||
}
|
||||
for (GenericEntry craft_wondrous_var : craft_wondrous.values()) {
|
||||
if (verbose) System.out.println("Printing page for " + craft_wondrous_var.name);
|
||||
// Start building the entry data. First, place in the name
|
||||
text = craftTemplate;
|
||||
text = text.replaceAll("~~~CraftPropName~~~", craft_wondrous_var.name);
|
||||
// Then, put in the description
|
||||
text = text.replaceAll("~~~CraftPropTLKDescription~~~",
|
||||
craft_wondrous_var.text);
|
||||
// Print the page
|
||||
try {
|
||||
printPage(craft_wondrous_var.filePath, text);
|
||||
} catch (PageGenerationException e) {
|
||||
err_pr.println("Error: Exception when writing page for skill " + craft_wondrous_var.entryNum + ": " + craft_wondrous_var.name + ":\n" + e);
|
||||
}
|
||||
}
|
||||
System.gc();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints all spells and spell-likes (psionics, truenaming).
|
||||
* As of now, all of these are similar enough to share the same
|
||||
* template, so they can be done here together.
|
||||
*/
|
||||
public static void printSpells() {
|
||||
String text = null;
|
||||
StringBuilder subradialText = null;
|
||||
|
||||
for (SpellEntry spell : spells.values()) {
|
||||
if (verbose) System.out.println("Printing page for " + spell.name);
|
||||
// Start building the entry data. First, place in the name
|
||||
text = spellTemplate;
|
||||
text = text.replaceAll("~~~SpellName~~~", spell.name);
|
||||
// Then, put in the description
|
||||
text = text.replaceAll("~~~SpellTLKDescription~~~",
|
||||
spell.text);
|
||||
// Add in the icon
|
||||
text = text.replaceAll("~~~Icon~~~", spell.iconPath);
|
||||
|
||||
// Handle subradials, if any
|
||||
subradialText = new StringBuilder();
|
||||
if (spell.subradials != null) {
|
||||
for (Tuple<String, String> subradial : spell.subradials) {
|
||||
subradialText.append(spellSubradialListEntryTemplate.replaceAll("~~~Icon~~~", subradial.e2)
|
||||
.replaceAll("~~~SubradialName~~~", subradial.e1));
|
||||
}
|
||||
subradialText = new StringBuilder(spellSubradialListTemplate.replaceAll("~~~EntryList~~~", subradialText.toString()));
|
||||
}
|
||||
text = text.replaceAll("~~~SubradialNames~~~", subradialText.toString());
|
||||
|
||||
// Print the page
|
||||
try {
|
||||
printPage(spell.filePath, text);
|
||||
} catch (PageGenerationException e) {
|
||||
err_pr.println("Error: Exception when writing page for spell " + spell.entryNum + ": " + spell.name + ":\n" + e);
|
||||
}
|
||||
}
|
||||
// Force a clean-up of dead objects. This will keep discarded objects from slowing down the program as it
|
||||
// hits the memory limit
|
||||
System.gc();
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple method for printing out all the feat pages.
|
||||
*/
|
||||
public static void printFeats() {
|
||||
// Print feats
|
||||
printFeatsAux();
|
||||
|
||||
// Print masterfeats
|
||||
printMasterFeatsAux();
|
||||
|
||||
// Print a page with alphabetically sorted list of all feats
|
||||
printPage(contentPath + "feats" + fileSeparator + "alphasortedfeats.html", buildAllFeatsList(false));
|
||||
|
||||
// Print a page with alphabetically sorted list of all epic feats
|
||||
printPage(contentPath + "epic_feats" + fileSeparator + "alphasortedepicfeats.html", buildAllFeatsList(true));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints the masterfeat pages.
|
||||
*/
|
||||
private static void printMasterFeatsAux() {
|
||||
String text = null,
|
||||
temp = null;
|
||||
|
||||
for (FeatEntry masterfeat : masterFeats.values()) {
|
||||
if (verbose) System.out.println("Printing page for " + masterfeat.name);
|
||||
// Build the entry data
|
||||
text = mFeatTemplate;
|
||||
text = text.replaceAll("~~~FeatName~~~",
|
||||
masterfeat.name);
|
||||
text = text.replaceAll("~~~FeatTLKDescription~~~",
|
||||
masterfeat.text);
|
||||
// Add in the icon
|
||||
text = text.replaceAll("~~~Icon~~~", masterfeat.iconPath);
|
||||
|
||||
// Add in child feats
|
||||
temp = "";
|
||||
for (FeatEntry child : masterfeat.childFeats.values()) {
|
||||
temp += pageLinkTemplate.replace("~~~Path~~~", child.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~Name~~~", child.name);
|
||||
}
|
||||
text = text.replaceAll("~~~MasterFeatChildList~~~", temp);
|
||||
|
||||
// Print the page
|
||||
try {
|
||||
printPage(masterfeat.filePath, text);
|
||||
} catch (PageGenerationException e) {
|
||||
err_pr.println("Error: Exception when writing page for masterfeat " + masterfeat.entryNum + ": " + masterfeat.name + ":\n" + e);
|
||||
}
|
||||
}
|
||||
System.gc();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints the feat pages.
|
||||
*/
|
||||
private static void printFeatsAux() {
|
||||
String text = null,
|
||||
temp = null;
|
||||
StringBuilder subradialText = null;
|
||||
|
||||
for (FeatEntry feat : feats.values()) {
|
||||
if (verbose) System.out.println("Printing page for " + feat.name);
|
||||
// Build the entry data
|
||||
text = featTemplate;
|
||||
text = text.replaceAll("~~~FeatName~~~",
|
||||
feat.name);
|
||||
text = text.replaceAll("~~~FeatTLKDescription~~~",
|
||||
feat.text);
|
||||
// Add in the icon
|
||||
text = text.replaceAll("~~~Icon~~~", feat.iconPath);
|
||||
|
||||
// Print prerequisites into the entry
|
||||
temp = "";
|
||||
if (feat.andRequirements.size() != 0) {
|
||||
temp += prereqANDFeatHeaderTemplate;
|
||||
for (FeatEntry andReq : feat.andRequirements.values())
|
||||
temp += pageLinkTemplate.replace("~~~Path~~~", andReq.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~Name~~~", andReq.name);
|
||||
}
|
||||
if (feat.orRequirements.size() != 0) {
|
||||
temp += prereqORFeatHeaderTemplate;
|
||||
for (FeatEntry orReq : feat.orRequirements.values())
|
||||
temp += pageLinkTemplate.replace("~~~Path~~~", orReq.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~Name~~~", orReq.name);
|
||||
}
|
||||
text = text.replaceAll("~~~PrerequisiteFeatList~~~", temp);
|
||||
|
||||
// Print the successor, if any, into the entry
|
||||
temp = "";
|
||||
if (feat.successor != null) {
|
||||
temp += successorFeatHeaderTemplate + pageLinkTemplate.replace("~~~Path~~~", feat.successor.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~Name~~~", feat.successor.name);
|
||||
}
|
||||
text = text.replaceAll("~~~SuccessorFeat~~~", temp);
|
||||
|
||||
// Handle subradials, if any
|
||||
subradialText = new StringBuilder();
|
||||
if (feat.subradials != null) {
|
||||
for (Tuple<String, String> subradial : feat.subradials) {
|
||||
subradialText.append(spellSubradialListEntryTemplate.replaceAll("~~~Icon~~~", subradial.e2)
|
||||
.replaceAll("~~~SubradialName~~~", subradial.e1));
|
||||
}
|
||||
subradialText = new StringBuilder(spellSubradialListTemplate.replaceAll("~~~EntryList~~~", subradialText.toString()));
|
||||
}
|
||||
text = text.replaceAll("~~~SubradialNames~~~", subradialText.toString());
|
||||
|
||||
// Handle feats that have this as their prerequisite
|
||||
temp = "";
|
||||
if (feat.requiredForFeats.size() != 0) {
|
||||
temp += requiredForFeatHeaderTemplate;
|
||||
for (FeatEntry req : feat.requiredForFeats.values()) {
|
||||
temp += pageLinkTemplate.replace("~~~Path~~~", req.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~Name~~~", req.name);
|
||||
}
|
||||
}
|
||||
text = text.replaceAll("~~~RequiredForFeatList~~~", temp);
|
||||
|
||||
// Print the page
|
||||
try {
|
||||
printPage(feat.filePath, text);
|
||||
} catch (PageGenerationException e) {
|
||||
err_pr.println("Error: Exception when writing page for feat " + feat.entryNum + ": " + feat.name + ":\n" + e);
|
||||
}
|
||||
}
|
||||
System.gc();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an alphabetically sorted list of all (or only all epic) feats.
|
||||
*
|
||||
* @param epicOnly if <code>true</code>, only feats that are epic are placed in the list. Otherwise, all feats.
|
||||
* @return an html page containing the list
|
||||
*/
|
||||
private static String buildAllFeatsList(boolean epicOnly) {
|
||||
TreeMap<String, FeatEntry> sorted = new TreeMap<String, FeatEntry>(String.CASE_INSENSITIVE_ORDER);
|
||||
for (FeatEntry entry : feats.values())
|
||||
if (!epicOnly || (epicOnly && entry.isEpic))
|
||||
sorted.put(entry.name, entry);
|
||||
String toReturn = alphaSortedListTemplate,
|
||||
entrySet;
|
||||
FeatEntry entry;
|
||||
char cha = (char) 0;
|
||||
int counter = 0;
|
||||
boolean addedAny;
|
||||
while (sorted.size() > 0) {
|
||||
// Build the list for a single letter
|
||||
entrySet = listEntrySetTemplate.replace("~~~LinkId~~~", new String(new char[]{cha}))
|
||||
.replace("~~~EntrySetName~~~", new String(new char[]{cha}).toUpperCase());
|
||||
addedAny = false;
|
||||
while (sorted.size() > 0 &&
|
||||
sorted.firstKey().toLowerCase().startsWith(new String(new char[]{cha}))) {
|
||||
addedAny = true;
|
||||
entry = sorted.remove(sorted.firstKey());
|
||||
|
||||
entrySet = entrySet.replace("~~~FeatList~~~", listEntryTemplate.replace("~~~EvenOrOdd~~~", (counter++ % 2) == 0 ? "even" : "odd")
|
||||
.replace("~~~EntryPath~~~",
|
||||
entry.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~EntryName~~~", entry.name)
|
||||
+ "~~~FeatList~~~");
|
||||
}
|
||||
entrySet = entrySet.replace("~~~FeatList~~~", "");
|
||||
cha++;
|
||||
|
||||
// Add the sublist to the page
|
||||
if (addedAny)
|
||||
toReturn = toReturn.replace("~~~Content~~~", entrySet + "\n" + "~~~Content~~~");
|
||||
}
|
||||
// Clear off the last replacement marker
|
||||
toReturn = toReturn.replace("~~~Content~~~", "");
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles creation of the domain pages.
|
||||
*/
|
||||
public static void printDomains() {
|
||||
String text = null;
|
||||
StringBuffer spellList = null;
|
||||
|
||||
for (DomainEntry domain : domains.values()) {
|
||||
if (verbose) System.out.println("Printing page for " + domain.name);
|
||||
// Build the entry data
|
||||
text = domainTemplate;
|
||||
text = text.replaceAll("~~~DomainName~~~",
|
||||
domain.name);
|
||||
text = text.replaceAll("~~~DomainTLKDescription~~~",
|
||||
domain.text);
|
||||
// Add in the icon
|
||||
text = text.replaceAll("~~~Icon~~~", domain.iconPath);
|
||||
|
||||
// Add a link to the granted feat
|
||||
text = text.replaceAll("~~~DomainFeat~~~",
|
||||
pageLinkTemplate.replace("~~~Path~~~", domain.grantedFeat.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~Name~~~", domain.grantedFeat.name));
|
||||
|
||||
// Add links to the granted spells
|
||||
spellList = new StringBuffer();
|
||||
for (SpellEntry grantedSpell : domain.spells) {
|
||||
spellList.append(pageLinkTemplate.replace("~~~Path~~~", grantedSpell.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~Name~~~", grantedSpell.name));
|
||||
}
|
||||
text = text.replaceAll("~~~DomainSpellList~~~", spellList.toString());
|
||||
|
||||
// Print the page
|
||||
try {
|
||||
printPage(domain.filePath, text);
|
||||
} catch (PageGenerationException e) {
|
||||
err_pr.println("Error: Exception when writing page for domain " + domain.entryNum + ": " + domain.name + ":\n" + e);
|
||||
}
|
||||
}
|
||||
System.gc();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles creation of the race pages.
|
||||
*/
|
||||
public static void printRaces() {
|
||||
String text = null;
|
||||
StringBuffer featList = null;
|
||||
|
||||
for (RaceEntry race : races.values()) {
|
||||
if (verbose) System.out.println("Printing page for " + race.name);
|
||||
// Build the entry data
|
||||
text = raceTemplate;
|
||||
text = text.replaceAll("~~~RaceName~~~",
|
||||
race.name);
|
||||
text = text.replaceAll("~~~RaceTLKDescription~~~",
|
||||
race.text);
|
||||
|
||||
// Add links to the racial feats
|
||||
featList = new StringBuffer();
|
||||
for (FeatEntry grantedFeat : race.raceFeats.values()) {
|
||||
featList.append(pageLinkTemplate.replace("~~~Path~~~", grantedFeat.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~Name~~~", grantedFeat.name));
|
||||
}
|
||||
text = text.replaceAll("~~~RaceFeats~~~", featList.toString());
|
||||
|
||||
// Print the page
|
||||
try {
|
||||
printPage(race.filePath, text);
|
||||
} catch (PageGenerationException e) {
|
||||
err_pr.println("Error: Exception when writing page for race " + race.entryNum + ": " + race.name + ":\n" + e);
|
||||
}
|
||||
}
|
||||
System.gc();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles creation of the class pages.
|
||||
* Subsections handled by several following methods.
|
||||
*/
|
||||
public static void printClasses() {
|
||||
String text = null,
|
||||
temp = null;
|
||||
String[] tempArr = null;
|
||||
|
||||
for (ClassEntry class_ : classes.values()) {
|
||||
if (verbose) System.out.println("Printing page for " + class_.name);
|
||||
// Build the entry data
|
||||
text = classTemplate;
|
||||
text = text.replaceAll("~~~ClassName~~~",
|
||||
class_.name);
|
||||
text = text.replaceAll("~~~ClassTLKDescription~~~",
|
||||
class_.text);
|
||||
// Add in the icon
|
||||
text = text.replaceAll("~~~Icon~~~", class_.iconPath);
|
||||
|
||||
// Add in the BAB and saving throws table
|
||||
text = text.replaceAll("~~~ClassBABAndSavThrTable~~~", buildBabAndSaveTable(class_));
|
||||
|
||||
// Add in the skills table
|
||||
text = text.replaceAll("~~~ClassSkillTable~~~", buildSkillTable(class_));
|
||||
|
||||
// Add in the feat table
|
||||
text = text.replaceAll("~~~ClassFeatTable~~~", buildClassFeatTables(class_));
|
||||
|
||||
// Add in the spells / powers table
|
||||
text = text.replaceAll("~~~ClassSpellAndPowerTables~~~", buildClassSpellAndPowerTables(class_));
|
||||
|
||||
|
||||
// Print the page
|
||||
try {
|
||||
printPage(class_.filePath, text);
|
||||
} catch (PageGenerationException e) {
|
||||
err_pr.println("Error: Exception when writing page for class " + class_.entryNum + ": " + class_.name + ":\n" + e);
|
||||
}
|
||||
}
|
||||
System.gc();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs the html table of levels and their bab + saving throw bonus values.
|
||||
*
|
||||
* @param class_ The class entry data structure of the class to generate the table for
|
||||
* @return string representation of the table
|
||||
*/
|
||||
private static String buildBabAndSaveTable(ClassEntry class_) {
|
||||
String toReturn = "";
|
||||
if (class_.babSav.size() != 0) {
|
||||
toReturn += babAndSavthrTableHeaderTemplate + "\n";
|
||||
// Start building the table
|
||||
for (int i = 0; i < class_.babSav.size(); i++) {
|
||||
toReturn += "<tr>\n";
|
||||
toReturn += classTablesEntryTemplate.replaceAll("~~~Entry~~~", (i + 1) + "");
|
||||
toReturn += classTablesEntryTemplate.replaceAll("~~~Entry~~~", class_.babSav.get(i)[0]);
|
||||
toReturn += classTablesEntryTemplate.replaceAll("~~~Entry~~~", class_.babSav.get(i)[1]);
|
||||
toReturn += classTablesEntryTemplate.replaceAll("~~~Entry~~~", class_.babSav.get(i)[2]);
|
||||
toReturn += classTablesEntryTemplate.replaceAll("~~~Entry~~~", class_.babSav.get(i)[3]);
|
||||
toReturn += "</tr>\n";
|
||||
}
|
||||
toReturn += "</table>\n";
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the html table of the class & cross-class skills of this class.
|
||||
* TreeMaps are used to arrange the printed skills in alphabetic order.
|
||||
*
|
||||
* @param class_ The class entry data structure of the class to generate the table for
|
||||
* @return string representation of the table
|
||||
*/
|
||||
private static String buildSkillTable(ClassEntry class_) {
|
||||
String toReturn = skillTableHeaderTemplate;
|
||||
GenericEntry tempSkill = null;
|
||||
// Clone the maps, since we'll be performing destructive operations on them
|
||||
TreeMap<String, GenericEntry> classSkills = new TreeMap<String, GenericEntry>(class_.skillList.e1),
|
||||
crossClassSkills = new TreeMap<String, GenericEntry>(class_.skillList.e2);
|
||||
|
||||
while (classSkills.size() > 0 || crossClassSkills.size() > 0) {
|
||||
toReturn += "<tr>\n";
|
||||
|
||||
if (classSkills.size() > 0) {
|
||||
tempSkill = classSkills.remove(classSkills.firstKey());
|
||||
toReturn += classTablesEntryTemplate.replaceAll("~~~Entry~~~", "<a href=\"" + tempSkill.filePath.replace(contentPath, "../").replaceAll("\\\\", "/") + "\" target=\"content\">" + tempSkill.name + "</a>");
|
||||
} else
|
||||
toReturn += classTablesEntryTemplate.replaceAll("~~~Entry~~~", " ");
|
||||
|
||||
if (crossClassSkills.size() > 0) {
|
||||
tempSkill = crossClassSkills.remove(crossClassSkills.firstKey());
|
||||
toReturn += classTablesEntryTemplate.replaceAll("~~~Entry~~~", "<a href=\"" + tempSkill.filePath.replace(contentPath, "../").replaceAll("\\\\", "/") + "\" target=\"content\">" + tempSkill.name + "</a>");
|
||||
} else
|
||||
toReturn += classTablesEntryTemplate.replaceAll("~~~Entry~~~", " ");
|
||||
|
||||
toReturn += "</tr>\n";
|
||||
}
|
||||
|
||||
toReturn += "</table>\n";
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs the html table of the bonus and selectable class feats of the given class.
|
||||
* TreeMaps are used to arrange the printed feats in alphabetic order.
|
||||
*
|
||||
* @param class_ The class entry data structure of the class to generate the table for
|
||||
* @return String that contains the table
|
||||
*/
|
||||
private static String buildClassFeatTables(ClassEntry class_) {
|
||||
List<TreeMap<String, FeatEntry>> grantedFeatList = class_.featList.e2.e1,
|
||||
selectableFeatList = class_.featList.e2.e2;
|
||||
List<Integer> bonusFeatCounts = class_.featList.e1;
|
||||
|
||||
// Start constructing the table
|
||||
StringBuffer tableText = new StringBuffer();
|
||||
StringBuffer linkList = null;
|
||||
String tableLine = null;
|
||||
for (int i = 0; i < grantedFeatList.size(); i++) {
|
||||
tableLine = classFeatTableEntryTemplate.replace("~~~Level~~~", String.valueOf(i + 1))
|
||||
.replace("~~~NumberOfBonusFeats~~~", bonusFeatCounts.get(i).toString());
|
||||
// Generate the granted feats list
|
||||
linkList = new StringBuffer();
|
||||
if (grantedFeatList.get(i) != null)
|
||||
for (FeatEntry feat : grantedFeatList.get(i).values()) {
|
||||
linkList.append(pageLinkTemplate.replace("~~~Path~~~", feat.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~Name~~~", feat.name));
|
||||
}
|
||||
else
|
||||
linkList.append(" ");
|
||||
tableLine = tableLine.replace("~~~FeatsGrantedList~~~", linkList.toString());
|
||||
|
||||
// Generate the granted feats list
|
||||
linkList = new StringBuffer();
|
||||
if (selectableFeatList.get(i) != null)
|
||||
for (FeatEntry feat : selectableFeatList.get(i).values()) {
|
||||
linkList.append(pageLinkTemplate.replace("~~~Path~~~", feat.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~Name~~~", feat.name));
|
||||
}
|
||||
else
|
||||
linkList.append(" ");
|
||||
tableLine = tableLine.replace("~~~SelectableFeatsList~~~", linkList.toString());
|
||||
|
||||
// Append the line to the table
|
||||
tableText.append(tableLine);
|
||||
}
|
||||
|
||||
return classFeatTableTemplate.replace("~~~TableContents~~~", tableText.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the html table of the new spellbook spells and psionic powers lists of
|
||||
* the given class. The entries are ordered by spell / power level
|
||||
*
|
||||
* @param class_ The class entry data structure of the class to generate the table for
|
||||
* @return String that contains the table
|
||||
*/
|
||||
private static String buildClassSpellAndPowerTables(ClassEntry class_) {
|
||||
StringBuffer toReturn = new StringBuffer();
|
||||
|
||||
for (Tuple<Tuple<String, String>, TreeMap<Integer, TreeMap<String, SpellEntry>>> magicData : class_.magics) {
|
||||
// Map of level numbers to maps of spell names to html links. Cloned due to destructive operations
|
||||
TreeMap<Integer, TreeMap<String, SpellEntry>> levelLists =
|
||||
new TreeMap<Integer, TreeMap<String, SpellEntry>>(magicData.e2);
|
||||
|
||||
StringBuffer tableLines = new StringBuffer(),
|
||||
spellLinks;
|
||||
String tableLine;
|
||||
while (levelLists.size() > 0) {
|
||||
tableLine = classMagicTableEntryTemplate.replace("~~~Level~~~", levelLists.firstKey().toString());
|
||||
spellLinks = new StringBuffer();
|
||||
for (SpellEntry spell : levelLists.remove(levelLists.firstKey()).values())
|
||||
spellLinks.append(pageLinkTemplate.replace("~~~Path~~~", spell.filePath.replace(contentPath, "../").replaceAll("\\\\", "/"))
|
||||
.replace("~~~Name~~~", spell.name));
|
||||
tableLines.append(tableLine.replace("~~~EntryList~~~", spellLinks.toString()));
|
||||
}
|
||||
|
||||
toReturn.append(classMagicTableTemplate.replace("~~~TableName~~~", magicData.e1.e1)
|
||||
.replace("~~~Type~~~", magicData.e1.e2)
|
||||
.replace("~~~TableContents~~~", tableLines.toString()));
|
||||
}
|
||||
|
||||
return toReturn.toString();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
package prc.autodoc;
|
||||
|
||||
/**
|
||||
* An exception indicating failure while generating a page.
|
||||
*/
|
||||
public class PageGenerationException extends java.lang.RuntimeException{
|
||||
private static final long serialVersionUID = 0x2L;
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param message The message this exception is to carry
|
||||
*/
|
||||
public PageGenerationException(String message) { super(message); }
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param message The message this exception is to carry
|
||||
* @param cause Another exception that caused this one to be thrown
|
||||
*/
|
||||
public PageGenerationException(String message, Throwable cause){ super(message, cause); }
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,29 @@
|
||||
package prc.autodoc;
|
||||
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Data structure for a race entry.
|
||||
*/
|
||||
public class RaceEntry extends GenericEntry {
|
||||
|
||||
/**
|
||||
* A list of masterfeat's children
|
||||
*/
|
||||
public final TreeMap<String, FeatEntry> raceFeats;
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
*
|
||||
* @param name Name of the race
|
||||
* @param text Description of the race
|
||||
* @param filePath Path where the html page for this race will be written to
|
||||
* @param entryNum racialtypes.2da index
|
||||
* @param raceFeats Racial feat list
|
||||
*/
|
||||
public RaceEntry(String name, String text, String filePath,
|
||||
int entryNum, TreeMap<String, FeatEntry> raceFeats) {
|
||||
super(name, text, null, filePath, entryNum);
|
||||
this.raceFeats = raceFeats;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,38 @@
|
||||
package prc.autodoc;
|
||||
|
||||
import prc.autodoc.Main.SpellType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Data structure for a spell entry.
|
||||
*/
|
||||
public class SpellEntry extends GenericEntry {
|
||||
/**
|
||||
* Type of this spell entry
|
||||
*/
|
||||
public final SpellType type;
|
||||
|
||||
/**
|
||||
* The spell's subradials, if any. List of spell name, icon path tuples.
|
||||
*/
|
||||
public final List<Tuple<String, String>> subradials;
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
*
|
||||
* @param name Name of the spell
|
||||
* @param text Description of the spell
|
||||
* @param iconPath Path of the spell's icon
|
||||
* @param filePath Path of the html file describing the spell.
|
||||
* @param entryNum spells.2da index
|
||||
* @param type Type of the spell: Normal / Epic / Psionic / whatever
|
||||
* @param subradials
|
||||
*/
|
||||
public SpellEntry(String name, String text, String iconPath, String filePath,
|
||||
int entryNum, SpellType type, List<Tuple<String, String>> subradials) {
|
||||
super(name, text, iconPath, filePath, entryNum);
|
||||
this.type = type;
|
||||
this.subradials = subradials;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,34 @@
|
||||
package prc.autodoc;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* An absolutely critical part of the Document Creator, not. Prints a spinning line
|
||||
* for the user to look at while the program is working.
|
||||
*/
|
||||
public final class Spinner {
|
||||
private final char[] states = new char[]{'|', '/', '-', '\\'};
|
||||
private int curState = 0;
|
||||
private boolean active = true;
|
||||
private Date lastSpinTime = new Date();
|
||||
|
||||
|
||||
/**
|
||||
* Spins the spinner.
|
||||
*/
|
||||
public void spin() {
|
||||
long minTimeBetweenSpinsInMS = 300;
|
||||
if (active && new Date().getTime() - lastSpinTime.getTime() > minTimeBetweenSpinsInMS) {
|
||||
System.out.print(states[curState = ++curState % states.length] + "\u0008");
|
||||
lastSpinTime = new Date();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Turns the spinner off.
|
||||
*/
|
||||
public void disable() {
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
package prc.autodoc;
|
||||
|
||||
/**
|
||||
* An exception indicating TLK read failed.
|
||||
*/
|
||||
public class TLKReadException extends java.lang.RuntimeException{
|
||||
private static final long serialVersionUID = 0x0L;
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param message The message this exception is to carry
|
||||
*/
|
||||
public TLKReadException(String message) { super(message); }
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param message The message this exception is to carry
|
||||
* @param cause Another exception that caused this one to be thrown
|
||||
*/
|
||||
public TLKReadException(String message, Throwable cause){ super(message, cause); }
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
package prc.autodoc;
|
||||
|
||||
/**
|
||||
* A simple tuple class
|
||||
*
|
||||
* @param <T1> The type of the first element of the tuple
|
||||
* @param <T2> The type of the second element of the tuple
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class Tuple<T1, T2> {
|
||||
/**
|
||||
* The first element
|
||||
*/
|
||||
public final T1 e1;
|
||||
/**
|
||||
* The second element
|
||||
*/
|
||||
public final T2 e2;
|
||||
|
||||
/**
|
||||
* Generates a new tuple out of the given two objects.
|
||||
*
|
||||
* @param e1 The object to become the first element of the new tuple
|
||||
* @param e2 The object to become the second element of the new tuple
|
||||
*/
|
||||
public Tuple(T1 e1, T2 e2) {
|
||||
this.e1 = e1;
|
||||
this.e2 = e2;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
package prc.autodoc;
|
||||
|
||||
/**
|
||||
* An exception indicating 2da read failed.
|
||||
*/
|
||||
public class TwoDAReadException extends java.lang.RuntimeException{
|
||||
private static final long serialVersionUID = 0x1L;
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param message The message this exception is to carry
|
||||
*/
|
||||
public TwoDAReadException(String message) { super(message); }
|
||||
|
||||
/**
|
||||
* Creates a new exception.
|
||||
*
|
||||
* @param message The message this exception is to carry
|
||||
* @param cause Another exception that caused this one to be thrown
|
||||
*/
|
||||
public TwoDAReadException(String message, Throwable cause){ super(message, cause); }
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* A system for calculating nwscript dependencies. Makes some assumptions specific
|
||||
* to the PRC setup.
|
||||
*/
|
||||
package prc.makedep;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
import static prc.Main.*;
|
||||
|
||||
|
||||
/**
|
||||
* Calculates nwscript dependencies.
|
||||
*
|
||||
* Usage: makedep [-aio?] targetlist
|
||||
* Options:
|
||||
* -a Append to outputfile. This option must be defined before -o
|
||||
* -n Ignore include file if not found
|
||||
* -sPATH[,PATH...] List of source directories
|
||||
* -oFILE Use FILE as outputfile, stdout assumed
|
||||
* -?, --help This text
|
||||
*
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
static Map<String, NSSNode> scripts = new LinkedHashMap<String, NSSNode>();
|
||||
|
||||
protected static boolean append = false,
|
||||
ignoreMissing = false,
|
||||
error = false;
|
||||
static PrintStream oStrm = System.out;
|
||||
|
||||
/**
|
||||
* Main method. Entrypoint to the program
|
||||
*
|
||||
* @param args The arguments. See readMe() for accepted ones
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
HashMap<String, String> targetList = new LinkedHashMap<String, String>();
|
||||
List<String> targetListFileNames = new ArrayList<String>();
|
||||
boolean targetsFromStdin = false;
|
||||
|
||||
// Parse arguments
|
||||
for(int i = 0; i < args.length; i++) {//[-aio?] targetslist+
|
||||
// Parameter parseage
|
||||
String param = args[i];
|
||||
if(param.startsWith("-")) {
|
||||
if(param.startsWith("-s")) {
|
||||
getFiles(param.substring(2));
|
||||
}
|
||||
else if(param.startsWith("-o")) {
|
||||
setOutput(param.substring(2));
|
||||
}
|
||||
else {
|
||||
if(param.equals("--help")) readMe();
|
||||
else if(param.equals("-")) {
|
||||
targetsFromStdin = true;
|
||||
}
|
||||
else {
|
||||
for(char c : param.substring(1).toCharArray()){
|
||||
switch(c) {
|
||||
case 'a':
|
||||
append = true;
|
||||
break;
|
||||
case 'n':
|
||||
ignoreMissing = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
System.out.println("Unknown parameter: " + c);
|
||||
case '?':
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// It's a targets list file
|
||||
targetListFileNames.add(param);
|
||||
}
|
||||
}
|
||||
|
||||
// Read targets from stdin if so specified
|
||||
Scanner scan;
|
||||
String targetName;
|
||||
if(targetsFromStdin) {
|
||||
scan = new Scanner(System.in);
|
||||
while(scan.hasNextLine()) {
|
||||
targetName = scan.nextLine().toLowerCase();
|
||||
// Strip everything after the .ncs from the line
|
||||
targetName = targetName.substring(0, targetName.indexOf(".ncs") + 4);
|
||||
targetList.put(NSSNode.getScriptName(targetName), targetName);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the target file list
|
||||
File targetListFile;
|
||||
for(String fileName : targetListFileNames) {
|
||||
targetListFile = new File(fileName);
|
||||
// Read the contents
|
||||
try {
|
||||
scan = new Scanner(targetListFile);
|
||||
} catch (FileNotFoundException e) {
|
||||
err_pr.println("Error: Could not find file: " + fileName);
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
while(scan.hasNextLine()) {
|
||||
targetName = scan.nextLine().toLowerCase();
|
||||
// Strip everything after the .ncs from the line
|
||||
targetName = targetName.substring(0, targetName.indexOf(".ncs") + 4);
|
||||
targetList.put(NSSNode.getScriptName(targetName), targetName);
|
||||
}
|
||||
}
|
||||
|
||||
// Input sanity checks
|
||||
if(targetList.size() == 0) {
|
||||
err_pr.println("Error: No targets specified.");
|
||||
error = true;
|
||||
}
|
||||
for(String target : targetList.keySet()) {
|
||||
if(scripts.get(target.toLowerCase()) == null) {
|
||||
err_pr.println("Error: Script file for target " + target + " not found in given source directories.");
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Terminate if errored
|
||||
if(error) System.exit(1);
|
||||
|
||||
// TODO: Load the files concurrently. I suspect it will give a slight performance boost
|
||||
//NSSNode[] debugArr = debugMap.values().toArray(new NSSNode[0]);
|
||||
for(NSSNode script: scripts.values())
|
||||
script.linkDirect();
|
||||
|
||||
// Check for errors again
|
||||
if(error) System.exit(1);
|
||||
|
||||
|
||||
// Start a depth-first-search to find all the include trees
|
||||
for(NSSNode node : scripts.values()){
|
||||
node.linkFullyAndGetIncludes(null);
|
||||
//node.printSelf(oStrm, append);
|
||||
}
|
||||
|
||||
// Do the printing
|
||||
for(String target : targetList.keySet()) {
|
||||
scripts.get(target.toLowerCase()).printSelf(oStrm, append, targetList.get(target));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints usage and terminates.
|
||||
*/
|
||||
private static void readMe() {
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
System.out.println("Usage: makedep [-aio?] targetslist+\n" +
|
||||
"Options:\n" +
|
||||
"-a Append to outputfile. This option must be defined before -o\n"+
|
||||
"-n Ignore include file if not found\n"+
|
||||
"-sPATH[,PATH...] List of source directories\n"+
|
||||
"-oFILE Use FILE as outputfile, stdout assumed\n" +
|
||||
"- Read targets from stdin. Same format as targets list files\n"+
|
||||
"-?, --help This text\n"+
|
||||
"\n"+
|
||||
"targetslist Name of a file containing a list of object (.ncs) files to\n"+
|
||||
" generate a make targets for.\n" +
|
||||
" File format is one path-to-target per line."
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks in the directories specified by the given list for .nss
|
||||
* files and adds them to the sources list.
|
||||
*
|
||||
* @param pathList comma-separated list of directories to look in
|
||||
*/
|
||||
private static void getFiles(String pathList){
|
||||
String[] paths = pathList.split(",");
|
||||
File[] files;
|
||||
String temp;
|
||||
for(String path : paths){
|
||||
files = new File(path).listFiles(new FileFilter(){
|
||||
public boolean accept(File file){
|
||||
return file.getName().endsWith(".nss");
|
||||
}
|
||||
});
|
||||
for(File file: files){
|
||||
temp = NSSNode.getScriptName(file.getName()).toLowerCase();
|
||||
if(!scripts.containsKey(temp))
|
||||
scripts.put(temp, new NSSNode(file.getPath()));
|
||||
else{
|
||||
err_pr.println("Error: Duplicate script file: " + temp);
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the output to write the results to to a file specified by the
|
||||
* given filename.
|
||||
* If the file is not found, the program terminates.
|
||||
*
|
||||
* @param outFileName Name of the file to print results to
|
||||
*/
|
||||
private static void setOutput(String outFileName){
|
||||
try{
|
||||
oStrm = new PrintStream(new FileOutputStream(outFileName, append), true);
|
||||
}catch(FileNotFoundException e){
|
||||
err_pr.println("Error: Missing output file " + outFileName + "\nTerminating!");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,89 @@
|
||||
package prc.makedep;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class MakedepChecker {
|
||||
private static class Node{
|
||||
private HashSet<String> deps = new HashSet<String>();
|
||||
private String full;
|
||||
|
||||
public Node(String full, String sdeps) {
|
||||
this.full = full;
|
||||
String[] sdepsar = sdeps.split(" ");
|
||||
for(String s : sdepsar)
|
||||
if(!s.equals(""))
|
||||
deps.add(s);
|
||||
}
|
||||
|
||||
public void compare(Node another){
|
||||
if(!(this.deps.containsAll(another.deps) && another.deps.containsAll(this.deps))){
|
||||
System.out.println("Differing lines:\n " + this.full + "\n " + another.full);
|
||||
if(!this.deps.containsAll(another.deps)){
|
||||
System.out.println(" Missing in olds:");
|
||||
HashSet<String> temp = another.deps;
|
||||
temp.removeAll(this.deps);
|
||||
for(String s : temp)
|
||||
System.out.println(" " + s);
|
||||
}
|
||||
if(!another.deps.containsAll(this.deps)){
|
||||
System.out.println(" Missing in news:");
|
||||
HashSet<String> temp = this.deps;
|
||||
temp.removeAll(another.deps);
|
||||
for(String s : temp)
|
||||
System.out.println(" " + s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Throwable{
|
||||
// Load old and new lists
|
||||
File odf = new File("oldmakedep.txt");
|
||||
File ndf = new File("newmakedep.txt");
|
||||
|
||||
HashMap<String, Node> olds = new HashMap<String, Node>();
|
||||
HashMap<String, Node> news = new HashMap<String, Node>();
|
||||
|
||||
Scanner scan = new Scanner(odf);
|
||||
while(scan.hasNextLine()){
|
||||
String s = scan.nextLine();
|
||||
if(s.equals(""))
|
||||
continue;
|
||||
String[] ss = s.split(":");
|
||||
olds.put(ss[0], new Node(s, ss[1]));
|
||||
}
|
||||
scan = new Scanner(ndf);
|
||||
while(scan.hasNextLine()){
|
||||
String s = scan.nextLine();
|
||||
if(s.equals(""))
|
||||
continue;
|
||||
String[] ss = s.split(":");
|
||||
news.put(ss[0], new Node(s, ss[1]));
|
||||
}
|
||||
|
||||
if(!(olds.keySet().containsAll(news.keySet()) &&
|
||||
news.keySet().containsAll(olds.keySet())
|
||||
)){
|
||||
System.out.println("Differing line counts!");
|
||||
|
||||
Set<String> foo = olds.keySet();
|
||||
foo.removeAll(news.keySet());
|
||||
System.out.println("Files not defined in news:");
|
||||
for(String s : foo)
|
||||
System.out.println(s);
|
||||
|
||||
|
||||
foo = news.keySet();
|
||||
foo.removeAll(olds.keySet());
|
||||
System.out.println("Files not defined in olds:");
|
||||
for(String s : foo)
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
for(String key : olds.keySet()){
|
||||
olds.get(key).compare(news.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,259 @@
|
||||
package prc.makedep;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import static prc.Main.*;
|
||||
|
||||
/**
|
||||
* A node in an NWScript include tree.
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class NSSNode {
|
||||
private static enum STATES{
|
||||
/**
|
||||
* This node has not been visited yet in the full linking phase.
|
||||
*/
|
||||
UNSTARTED,
|
||||
/**
|
||||
* The depth-first-search has reached this node, but has not returned to it yet.
|
||||
*/
|
||||
WORKING,
|
||||
/**
|
||||
* All the includes for this node have been resolved.
|
||||
*/
|
||||
DONE};
|
||||
|
||||
private STATES state = STATES.UNSTARTED;
|
||||
|
||||
/**
|
||||
* While the node is in WORKING state, it's includes have not been resolved yet.
|
||||
* So, if a circular include is found, it is added here so that this node's includes
|
||||
* can be added to it's list once the DFS returns to this node.
|
||||
*/
|
||||
private HashSet<NSSNode> mergeLater = new HashSet<NSSNode>();
|
||||
|
||||
/**
|
||||
* A container for marking files that are already being handled during a merging cascade.
|
||||
*/
|
||||
private static HashSet<NSSNode> inMerge;
|
||||
|
||||
/**
|
||||
* The nodes included directly by this node via #include statements.
|
||||
*/
|
||||
private HashSet<NSSNode> adjenct = new LinkedHashSet<NSSNode>();
|
||||
|
||||
/**
|
||||
* The nodes included by this node either directly or via intermediary steps. Also,
|
||||
* each file is considered to include itself in order to make printing include lists
|
||||
* a bit less complex.
|
||||
*/
|
||||
private HashSet<NSSNode> includes = new LinkedHashSet<NSSNode>();
|
||||
|
||||
/**
|
||||
* The first node to call linkFullyAndGetIncludes() on this node.
|
||||
*/
|
||||
public NSSNode priCaller;
|
||||
|
||||
/**
|
||||
* The path used to reference this file.
|
||||
*/
|
||||
public String fileName;
|
||||
|
||||
/**
|
||||
* Creates a new, unlinked NSSNode
|
||||
*
|
||||
* @param fileName
|
||||
*/
|
||||
public NSSNode(String fileName) {
|
||||
fileName = fileName.toLowerCase();
|
||||
// Make sure the file exists
|
||||
if(!new File(fileName).exists()){
|
||||
Main.error = true;
|
||||
err_pr.println("Error: Missing script file: " + fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Each node is dependent on itself
|
||||
includes.add(this);
|
||||
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link this script file to those files it directly includes.
|
||||
*/
|
||||
public void linkDirect(){
|
||||
// Load the text for this file
|
||||
File file = new File(fileName);
|
||||
char[] cArray = new char[(int)file.length()];
|
||||
try{
|
||||
FileReader fr = new FileReader(fileName);
|
||||
fr.read(cArray);
|
||||
fr.close();
|
||||
}catch(Exception e){
|
||||
err_pr.println("Error: Error while reading file: " + fileName);
|
||||
Main.error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Debuggage
|
||||
if(fileName.indexOf("psi_inc_psifunc") != -1)
|
||||
System.currentTimeMillis();
|
||||
//*/
|
||||
|
||||
|
||||
String[] directIncludes = NWScript.findIncludes(new String(cArray));
|
||||
|
||||
for(String name : directIncludes){
|
||||
name = name.toLowerCase();
|
||||
NSSNode adj = Main.scripts.get(name);
|
||||
if(adj != null){
|
||||
if(adjenct.contains(adj))
|
||||
//System.out.println("Warning: " + getScriptName(fileName) + " includes " + getScriptName(adj.fileName) + " multiple times");
|
||||
System.out.printf("Warning: %-16s includes %-16s multiple times\n",
|
||||
getScriptName(fileName),
|
||||
getScriptName(adj.fileName)
|
||||
);
|
||||
adjenct.add(adj);
|
||||
}else if(!Main.ignoreMissing){
|
||||
System.out.println("Script file not found: " + name);
|
||||
Main.error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the full list of files included by this script.
|
||||
*
|
||||
* @param caller the node calling this function recursively passes a reference
|
||||
* to itself. Used in cases where the target node was already in
|
||||
* WORKING state.
|
||||
* @return HashSet containing the fully resolved list of files included by this one
|
||||
*/
|
||||
public HashSet<NSSNode> linkFullyAndGetIncludes(NSSNode caller) {
|
||||
if(state != STATES.UNSTARTED)
|
||||
if(state == STATES.DONE)
|
||||
return includes;
|
||||
else{
|
||||
// Add to a list to merge include lists later once this node is done
|
||||
NSSNode toMergeLater = caller;
|
||||
while(toMergeLater != this){
|
||||
mergeLater.add(toMergeLater);
|
||||
toMergeLater = toMergeLater.priCaller;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/* Debuggage stuff
|
||||
if(//fileName.indexOf("ss_ep_psionicsal") != -1 ||
|
||||
//fileName.indexOf("psi_inc_psifunc") != -1 ||
|
||||
//fileName.indexOf("prc_alterations") != -1 ||
|
||||
//fileName.indexOf("bonsum_shapelem") != -1 ||
|
||||
fileName.indexOf("pnp_shft_poly") != -1 ||
|
||||
false
|
||||
)
|
||||
System.currentTimeMillis();
|
||||
//*/
|
||||
// Mark the node as work-in-progress, so it won't be handled again
|
||||
state = STATES.WORKING;
|
||||
priCaller = caller;
|
||||
// Initialize the includes list for this script with the direct includes
|
||||
includes.addAll(adjenct);
|
||||
|
||||
HashSet<NSSNode> temp;
|
||||
for(NSSNode adj : adjenct){
|
||||
temp = adj.linkFullyAndGetIncludes(this);
|
||||
if(temp != null)
|
||||
includes.addAll(temp);
|
||||
}
|
||||
|
||||
// Do the delayed include list merges
|
||||
inMerge = new HashSet<NSSNode>();
|
||||
this.doMerge();
|
||||
/*for(NSSNode node : mergeLater)
|
||||
node.includes.addAll(this.includes);*/
|
||||
inMerge = null;
|
||||
|
||||
state = STATES.DONE;
|
||||
return includes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the include list of this file with all files that included this one while
|
||||
* it was still being worked on. Recurses to each of these files in order to update
|
||||
* files dependent on them.
|
||||
*/
|
||||
private void doMerge(){
|
||||
for(NSSNode node : mergeLater){
|
||||
if(!inMerge.contains(node)){
|
||||
inMerge.add(node);
|
||||
node.includes.addAll(this.includes);
|
||||
node.doMerge();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name used in include statements for the given filename.
|
||||
*
|
||||
* @param path the path to parse
|
||||
* @return string, name used in include statements
|
||||
*/
|
||||
public static String getScriptName(String path) {
|
||||
// Cut out the .nss or .ncs
|
||||
try{
|
||||
path = path.substring(0, path.indexOf(".nss") != -1 ? path.indexOf(".nss") : path.indexOf(".ncs"));
|
||||
}catch(Exception e){
|
||||
err_pr.println(path);
|
||||
}
|
||||
|
||||
// Cut out the directories, if present
|
||||
if(path.indexOf(File.separator) != -1)
|
||||
path = path.substring(path.lastIndexOf(File.separator) + 1, path.length());
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints this node's list of includes to a stream.
|
||||
*
|
||||
* @param strm stream to print to
|
||||
* @param append if this is <code>true</code>, the PrintStream's <code>append</code> methods
|
||||
* are used instead of <code>print</code> methods.
|
||||
* @param target name of the object file to be built from this script
|
||||
*/
|
||||
public void printSelf(PrintStream strm, boolean append, String target) {
|
||||
String lineSeparator = System.getProperty("line.separator");
|
||||
if(append){
|
||||
//strm.append(fileName.replace(".nss", ".ncs") + ":"/* + fileName*/);
|
||||
strm.append(target + ":");
|
||||
for(NSSNode include : includes)
|
||||
strm.append(" " + include.fileName);
|
||||
strm.append(lineSeparator + lineSeparator);
|
||||
}else{
|
||||
strm.print(target + ":");
|
||||
for(NSSNode include : includes)
|
||||
strm.print(" " + include.fileName);
|
||||
strm.print(lineSeparator + lineSeparator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A test main.
|
||||
*
|
||||
* @param args Ye olde parameters. Doesn't accept any
|
||||
*/
|
||||
public static void main(String[] args){
|
||||
System.out.println(getScriptName("C:\\foo\\bar\\meh.nss"));
|
||||
System.out.println(getScriptName("boo.nss"));
|
||||
System.out.println(getScriptName("lar\\floob.nss"));
|
||||
}
|
||||
|
||||
/**
|
||||
* An NSSNode's string representation is it's filename.
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString(){return fileName;}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,144 @@
|
||||
package prc.makedep;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.*;
|
||||
|
||||
|
||||
/**
|
||||
* A class for parsing NWScript files.
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class NWScript {
|
||||
private static enum STATES{
|
||||
/**
|
||||
* Normal code, can switch to the other modes from here.
|
||||
*/
|
||||
NORMAL,
|
||||
/**
|
||||
* String mode. Exited by an unescaped " (technically should be ended
|
||||
* by a new line as well, but we assume the code is not that badly fubar'd).
|
||||
*/
|
||||
STRING,
|
||||
/**
|
||||
* Singe line comment, started by //. Exited by a newline.
|
||||
*/
|
||||
SCOMMENT,
|
||||
/**
|
||||
* Multi-line comment.
|
||||
*/
|
||||
MCOMMENT
|
||||
};
|
||||
|
||||
private static Matcher matcher = Pattern.compile("#include[ \t\u000B\f\r]*\"(.*)\"").matcher("");
|
||||
|
||||
|
||||
/**
|
||||
* Parses the given source text for #include directives and returns the names of
|
||||
* the files included.
|
||||
*
|
||||
* @param srcText contents of a nwscript source file
|
||||
* @return array of String containing the names of files included by this one
|
||||
*/
|
||||
public static String[] findIncludes(CharSequence srcText){
|
||||
StringBuffer wip = new StringBuffer(srcText);
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
|
||||
removeComments(wip);
|
||||
|
||||
// Parse for remaining #include statements
|
||||
//#include[ \t\x0B\f\r]*"(.*)"
|
||||
matcher.reset(wip);
|
||||
//String debug;
|
||||
while(matcher.find()){
|
||||
//debug = matcher.group(1);
|
||||
//list.add(debug);
|
||||
list.add(matcher.group(1));
|
||||
}
|
||||
|
||||
|
||||
return list.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the contents of comments with spaces.
|
||||
*
|
||||
* @param sbuf Stringbuffer containing nwscript to strip comments from
|
||||
*/
|
||||
private static void removeComments(StringBuffer sbuf){
|
||||
STATES state = STATES.NORMAL;
|
||||
char prev = '\u0000', cur;
|
||||
boolean evenBSlash = true;
|
||||
|
||||
for(int i = 0; i < sbuf.length(); i++){
|
||||
cur = sbuf.charAt(i);
|
||||
switch(state){
|
||||
case NORMAL:
|
||||
if(prev == '/'){
|
||||
if(cur == '/'){
|
||||
state = STATES.SCOMMENT;
|
||||
sbuf.setCharAt(i - 1, ' ');
|
||||
sbuf.setCharAt(i, ' ');
|
||||
}
|
||||
else if(cur == '*'){
|
||||
state = STATES.MCOMMENT;
|
||||
sbuf.setCharAt(i - 1, ' ');
|
||||
sbuf.setCharAt(i, ' ');
|
||||
|
||||
// Null current so that /*/ won't get mistakenly detected as having closed
|
||||
cur = ' ';
|
||||
}
|
||||
}
|
||||
else if(cur == '\"')
|
||||
state = STATES.STRING;
|
||||
break;
|
||||
case STRING:
|
||||
if(cur == '\"'){
|
||||
if(evenBSlash)
|
||||
state = STATES.NORMAL;
|
||||
}
|
||||
else if(cur == '\\')
|
||||
evenBSlash = !evenBSlash;
|
||||
else
|
||||
evenBSlash = true;
|
||||
break;
|
||||
case SCOMMENT:
|
||||
if(cur == '\n')
|
||||
state = STATES.NORMAL;
|
||||
else
|
||||
sbuf.setCharAt(i, ' ');
|
||||
break;
|
||||
case MCOMMENT:
|
||||
if(prev == '*' && cur == '/')
|
||||
state = STATES.NORMAL;
|
||||
|
||||
sbuf.setCharAt(i, ' ');
|
||||
break;
|
||||
}
|
||||
|
||||
prev = cur;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test main
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
findIncludes(
|
||||
"/**\n" +
|
||||
" * Mof! \" \"\n" +
|
||||
" */\n" +
|
||||
"#include \"test\"\n" +
|
||||
"#include \"tset\"\n" +
|
||||
"/*/ */\n"+
|
||||
"\n"+
|
||||
"void main()\n"+
|
||||
"{// Rar!\n"+
|
||||
" florb(); /* call florb */\n"+
|
||||
" /* another call */ florb();\n"+
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
Main-Class: prc.Main
|
||||
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,691 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static prc.Main.spinner;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class AMSSpellbookMaker {
|
||||
private AMSSpellbookMaker() {/* Prevent instantiation */}
|
||||
|
||||
private static int spells2daRow = 0;
|
||||
private static int feat2daRow = 0;
|
||||
private static int iprp_feats2daRow = 0;
|
||||
private static int tlkRow = 0;
|
||||
private static int classSpellRow = 0;
|
||||
private static int classFeatRow = 0;
|
||||
private static int subradialID = 7000;
|
||||
private static Data_2da classes2da;
|
||||
private static Data_2da spells2da;
|
||||
private static Data_2da feat2da;
|
||||
private static Data_2da iprp_feats2da;
|
||||
private static Data_TLK customtlk;
|
||||
private static Data_TLK dialogtlk;
|
||||
private static Data_2da classSpell2da;
|
||||
private static Data_2da classFeat2da;
|
||||
private static String[] spellLabels;
|
||||
|
||||
private static final int MAGIC_TLK = 0x01000000;
|
||||
|
||||
private static String start_label = "####START_OF_AMS_SPELLBOOK_RESERVE";
|
||||
private static String end_label = "####END_OF_AMS_SPELLBOOK_RESERVE";
|
||||
|
||||
private static String spellbook_filename_start = "cls_spcr_";
|
||||
private static String class_filename_start = "cls_spell_";
|
||||
private static String AMSheader = "prc_";
|
||||
private static int classlength = 5;
|
||||
|
||||
/**
|
||||
* The main method, as usual.
|
||||
*
|
||||
* @param args do I really need to explain this?
|
||||
* @throws Exception this is a simple tool, just let all failures blow up
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Parse args
|
||||
for (String param : args) {//[--help]
|
||||
// Parameter parseage
|
||||
if (param.startsWith("-")) {
|
||||
if (param.equals("--help")) readMe();
|
||||
else if (param.equals("-tob")) {
|
||||
classlength = 3;
|
||||
spellbook_filename_start = "cls_mvcr_";
|
||||
AMSheader = "tob_";
|
||||
class_filename_start = "cls_move_";
|
||||
start_label = "####START_OF_TOB_SPELLBOOK_RESERVE";
|
||||
end_label = "####END_OF_TOB_SPELLBOOK_RESERVE";
|
||||
|
||||
System.out.println("Assembling Tome of Battle spellbooks...");
|
||||
} else if (param.equals("-inv")) {
|
||||
classlength = 3;
|
||||
spellbook_filename_start = "cls_ivcr_";
|
||||
AMSheader = "inv_";
|
||||
class_filename_start = "cls_inv_";
|
||||
start_label = "####START_OF_INV_SPELLBOOK_RESERVE";
|
||||
end_label = "####END_OF_INV_SPELLBOOK_RESERVE";
|
||||
|
||||
System.out.println("Assembling Invocation spellbooks...");
|
||||
} else {
|
||||
for (char c : param.substring(1).toCharArray()) {
|
||||
switch (c) {
|
||||
default:
|
||||
System.out.println("Unknown parameter: " + c);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.out.println("Unknown parameter: " + param);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//load all the data files in advance
|
||||
//this is quite slow, but needed
|
||||
classes2da = Data_2da.load2da("2das" + File.separator + "classes.2da", true);
|
||||
spells2da = Data_2da.load2da("2das" + File.separator + "spells.2da", true);
|
||||
feat2da = Data_2da.load2da("2das" + File.separator + "feat.2da", true);
|
||||
iprp_feats2da = Data_2da.load2da("2das" + File.separator + "iprp_feats.2da", true);
|
||||
customtlk = new Data_TLK("tlk" + File.separator + "prc_consortium.tlk");
|
||||
dialogtlk = new Data_TLK("tlk" + File.separator + "dialog.tlk");
|
||||
spellLabels = spells2da.getLabels();
|
||||
|
||||
//get the start/end rows for each file for the reserved blocks
|
||||
getFirstSpells2daRow();
|
||||
getFirstFeat2daRow();
|
||||
getFirstIPRPFeats2daRow();
|
||||
getFirstTlkRow();
|
||||
System.out.println("First free spells.2da row is " + spells2daRow);
|
||||
System.out.println("First free feat.2da row is " + feat2daRow);
|
||||
System.out.println("First free iprp_feats.2da row is " + iprp_feats2daRow);
|
||||
System.out.println("First free tlk row is " + tlkRow);
|
||||
|
||||
//now process each class in turn
|
||||
for (int classRow = 0; classRow < classes2da.getEntryCount(); classRow++) {
|
||||
//the feat file is the root of the file naming layout
|
||||
String classfilename = classes2da.getEntry("FeatsTable", classRow);
|
||||
|
||||
//check its a real class not padding
|
||||
if (classfilename != null && classfilename.length() > 9) {
|
||||
classfilename = classfilename.substring(9);
|
||||
String classCoreFilename = spellbook_filename_start + classfilename;
|
||||
|
||||
//check the file exists
|
||||
File classCoreFile = new File("2das" + File.separator + classCoreFilename + ".2da");
|
||||
|
||||
if (classCoreFile.exists()) {
|
||||
//open the core spell file
|
||||
Data_2da classCoreSpell2da = Data_2da.load2da(classCoreFile.getPath(), true);
|
||||
|
||||
// If the cls_spell file for this class does not exist yet, create it
|
||||
File classSpell2daFile = new File("2das" + File.separator + class_filename_start + classfilename + ".2da");
|
||||
if (!classSpell2daFile.exists()) {
|
||||
System.out.println("File " + classSpell2daFile.getPath() + " did not exist, creating");
|
||||
classSpell2da = new Data_2da(class_filename_start + classfilename, "");
|
||||
classSpell2da.addColumn("Label");
|
||||
classSpell2da.addColumn("Level");
|
||||
classSpell2da.addColumn("FeatID");
|
||||
classSpell2da.addColumn("IPFeatID");
|
||||
classSpell2da.addColumn("SpellID");
|
||||
classSpell2da.addColumn("RealSpellID");
|
||||
classSpell2da.addColumn("ReqFeat");
|
||||
} else {
|
||||
classSpell2da = Data_2da.load2da(classSpell2daFile.getPath(), true);
|
||||
|
||||
// Clear all the existing rows
|
||||
for (String label : classSpell2da.getLabels())
|
||||
for (int i = 0; i < classSpell2da.getEntryCount(); i++)
|
||||
classSpell2da.setEntry(label, i, "****");
|
||||
}
|
||||
|
||||
// Make sure the file contains at least one line
|
||||
if (classSpell2da.getEntryCount() == 0) {
|
||||
classSpell2da.appendRow();
|
||||
}
|
||||
|
||||
// The first line should be left blank, so initialise index to 1
|
||||
classSpellRow = 1;
|
||||
|
||||
// Load the class feats 2da
|
||||
classFeat2da = Data_2da.load2da("2das" + File.separator + "cls_feat_" + classfilename + ".2da", true);
|
||||
getFirstClassFeat2daRow();
|
||||
|
||||
//get the class name
|
||||
String className = getCheckedTlkEntry(classes2da.getBiowareEntryAsInt("Name", classRow)) + " ";
|
||||
|
||||
// Construct the class portion of labels to be generated
|
||||
String classLabel = classes2da.getEntry("Label", classRow);
|
||||
// Nothing longer than Suel_Archanamach (16 chars) allowed in order to avoid extending the length of all spells.2da rows again
|
||||
if (classLabel.length() > 16)
|
||||
classLabel = classLabel.substring(0, 17);
|
||||
classLabel += "_";
|
||||
|
||||
//get the maximum spell level
|
||||
int maxLevel = 0;
|
||||
for (int row = 0; row < classCoreSpell2da.getEntryCount(); row++)
|
||||
maxLevel = Math.max(maxLevel, classCoreSpell2da.getBiowareEntryAsInt("Level", row));
|
||||
|
||||
//loop over all the spells
|
||||
for (int row = 0; row < classCoreSpell2da.getEntryCount(); row++) {
|
||||
//check its not a null row
|
||||
if (!classCoreSpell2da.getEntry("SpellID", row).equals("****")) {
|
||||
//get the real spellID
|
||||
int spellID = classCoreSpell2da.getBiowareEntryAsInt("SpellID", row);
|
||||
//get the level of the spell
|
||||
int spellLevel = classCoreSpell2da.getBiowareEntryAsInt("Level", row);
|
||||
//get the metamagic reference to know what types work
|
||||
int metamagic = spells2da.getBiowareEntryAsInt("Metamagic", spellID);
|
||||
/* not really necessary
|
||||
if(metamagic == 0)
|
||||
System.out.println("Check metamagic for spell " + spellID);
|
||||
*/
|
||||
|
||||
// Hack - Determine how radial masters there might be: 1 + metamagics
|
||||
int masterCount = 1;
|
||||
for (int metamagicFlag = 0x1; metamagicFlag <= 0x20; metamagicFlag <<= 1)
|
||||
if ((metamagic & metamagicFlag) != 0) {
|
||||
/*
|
||||
* 0x01 = 1 = Empower
|
||||
* 0x02 = 2 = Extend
|
||||
* 0x04 = 4 = Maximize
|
||||
* 0x08 = 8 = Quicken
|
||||
* 0x10 = 16 = Silent
|
||||
* 0x20 = 32 = Still
|
||||
*/
|
||||
int metaCost = 0;
|
||||
if (metamagicFlag == 0x01) metaCost = 2;
|
||||
else if (metamagicFlag == 0x02) metaCost = 1;
|
||||
else if (metamagicFlag == 0x04) metaCost = 3;
|
||||
else if (metamagicFlag == 0x08) metaCost = 4;
|
||||
else if (metamagicFlag == 0x10) metaCost = 1;
|
||||
else if (metamagicFlag == 0x20) metaCost = 1;
|
||||
|
||||
if (spellLevel + metaCost <= maxLevel)
|
||||
masterCount += 1;
|
||||
}
|
||||
List<Integer> preReservedClassSpell2daRows = new ArrayList<Integer>();
|
||||
// Reserve a number of cls_spell_ rows for the main entries.
|
||||
for (int i = 0; i < masterCount; i++) {
|
||||
// If needed, add rows to the file to prevent errors in addNewSpellbookData
|
||||
if (classSpellRow >= classSpell2da.getEntryCount()) {
|
||||
classSpell2da.appendRow();
|
||||
}
|
||||
preReservedClassSpell2daRows.add(classSpellRow++);
|
||||
}
|
||||
// Generate an iterator for it
|
||||
Iterator<Integer> preReservedClassSpell2daRowIterator = preReservedClassSpell2daRows.iterator();
|
||||
|
||||
//now loop over the metamagic varients
|
||||
//-1 represents no metamagic
|
||||
for (int metamagicNo = -1; metamagicNo < 6; metamagicNo++) {
|
||||
/*
|
||||
* 0x01 = 1 = Empower
|
||||
* 0x02 = 2 = Extend
|
||||
* 0x04 = 4 = Maximize
|
||||
* 0x08 = 8 = Quicken
|
||||
* 0x10 = 16 = Silent
|
||||
* 0x20 = 32 = Still
|
||||
*/
|
||||
// If creating the base entry, or the given metamagic applies
|
||||
if (metamagicNo == -1 || (metamagic & (1 << metamagicNo)) != 0) {
|
||||
String spellNameMetamagic = "";
|
||||
String spellLabelMetamagic = "";
|
||||
String metaScript = "";
|
||||
int metamagicLevel = 0;
|
||||
String metamagicFeat = "****";
|
||||
if (metamagicNo == -1) {
|
||||
spellNameMetamagic = "";
|
||||
spellLabelMetamagic = "";
|
||||
metaScript = "sp";
|
||||
metamagicLevel = 0;
|
||||
metamagicFeat = "****";
|
||||
} else if (metamagicNo == 0) {
|
||||
spellNameMetamagic = "Empowered ";
|
||||
spellLabelMetamagic = "Empowered_";
|
||||
metaScript = "em";
|
||||
metamagicLevel = 2;
|
||||
metamagicFeat = "11";
|
||||
} else if (metamagicNo == 1) {
|
||||
spellNameMetamagic = "Extended ";
|
||||
spellLabelMetamagic = "Exteneded_";
|
||||
metaScript = "ex";
|
||||
metamagicLevel = 1;
|
||||
metamagicFeat = "12";
|
||||
} else if (metamagicNo == 2) {
|
||||
spellNameMetamagic = "Maximized ";
|
||||
spellLabelMetamagic = "Maximized_";
|
||||
metaScript = "ma";
|
||||
metamagicLevel = 3;
|
||||
metamagicFeat = "25";
|
||||
} else if (metamagicNo == 3) {
|
||||
spellNameMetamagic = "Quickened ";
|
||||
spellLabelMetamagic = "Quickened_";
|
||||
metaScript = "qu";
|
||||
metamagicLevel = 4;
|
||||
metamagicFeat = "29";
|
||||
} else if (metamagicNo == 4) {
|
||||
spellNameMetamagic = "Silent ";
|
||||
spellLabelMetamagic = "Silent_";
|
||||
metaScript = "si";
|
||||
metamagicLevel = 1;
|
||||
metamagicFeat = "33";
|
||||
} else if (metamagicNo == 5) {
|
||||
spellNameMetamagic = "Still ";
|
||||
spellLabelMetamagic = "Still_";
|
||||
metaScript = "st";
|
||||
metamagicLevel = 1;
|
||||
metamagicFeat = "37";
|
||||
}
|
||||
//check if the metamagic adjusted level is less than the maximum level
|
||||
if ((metamagicLevel + spellLevel) <= maxLevel) {
|
||||
//debug printout
|
||||
//System.out.println(name+" : "+label);
|
||||
addNewSpellbookData(spellID,
|
||||
classfilename,
|
||||
metaScript,
|
||||
metamagicNo,
|
||||
metamagicLevel,
|
||||
metamagicFeat,
|
||||
spellLevel,
|
||||
className,
|
||||
spellNameMetamagic,
|
||||
classLabel,
|
||||
spellLabelMetamagic,
|
||||
preReservedClassSpell2daRowIterator,
|
||||
0);
|
||||
}//end of level check
|
||||
}//end of metamamgic check
|
||||
}//end of metamagic loop
|
||||
}// end if - The cls_spcr row contains an entry
|
||||
}//end of cls_spells_*_core.2da loop
|
||||
|
||||
//save the new cls_spell_*.2da file
|
||||
classSpell2da.save2da("2das", true, true);
|
||||
classFeat2da.save2da("2das", true, true);
|
||||
} else {
|
||||
//System.out.println(classfilename+" does not exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
//now resave the files we opened
|
||||
spells2da.save2da("2das", true, true);
|
||||
feat2da.save2da("2das", true, true);
|
||||
iprp_feats2da.save2da("2das", true, true);
|
||||
customtlk.saveAsXML("prc_consortium", "tlk", true);
|
||||
}
|
||||
|
||||
private static void addNewSpellbookData(int spellID,
|
||||
String classfilename,
|
||||
String metaScript,
|
||||
int metamagicNo,
|
||||
int metamagicLevel,
|
||||
String metamagicFeat,
|
||||
int spellLevel,
|
||||
String className,
|
||||
String spellNameMetamagic,
|
||||
String classLabel,
|
||||
String spellLabelMetamagic,
|
||||
Iterator<Integer> preReservedClassSpell2daRows,
|
||||
int subradialMaster) {
|
||||
// Hack - If not a subradial, use prereserved cls_spell row
|
||||
int localClassSpellRow;
|
||||
if (subradialMaster == 0) {
|
||||
localClassSpellRow = preReservedClassSpell2daRows.next();
|
||||
} else {
|
||||
// Grab the current value of classSpellRow for use and then increment it
|
||||
localClassSpellRow = classSpellRow++;
|
||||
}
|
||||
|
||||
//get the name of the spell
|
||||
String spellName = getCheckedTlkEntry(spells2da.getBiowareEntryAsInt("Name", spellID));
|
||||
//get the label of the spell
|
||||
String spellLabel = spells2da.getEntry("Label", spellID);
|
||||
//assemble the name
|
||||
String name = className + spellNameMetamagic + spellName;
|
||||
//assemble the label
|
||||
String label = classLabel + spellLabelMetamagic + spellLabel;
|
||||
//set the next tlk line to the name
|
||||
customtlk.setEntry(tlkRow, name);
|
||||
|
||||
//copy the original spells.2da line to the next free spells.2da line
|
||||
String[] originalSpellRow = spells2da.getRow(spellID);
|
||||
for (int i = 0; i < originalSpellRow.length; i++) {
|
||||
spells2da.setEntry(spellLabels[i], spells2daRow, spells2da.getEntry(spellLabels[i], spellID));
|
||||
}
|
||||
|
||||
//change the ImpactScript
|
||||
String script = AMSheader + (classfilename.length() <= 5 ? classfilename : classfilename.substring(0, classlength)) + "_generic";
|
||||
spells2da.setEntry("ImpactScript", spells2daRow, script);
|
||||
//change the Label
|
||||
spells2da.setEntry("Label", spells2daRow, label);
|
||||
//change the Name
|
||||
spells2da.setEntry("Name", spells2daRow, Integer.toString(tlkRow + MAGIC_TLK));
|
||||
|
||||
//if quickened, set conjuring/casting duration to zero
|
||||
if (metamagicNo == 3) {
|
||||
spells2da.setEntry("ConjTime", spells2daRow, "0");
|
||||
spells2da.setEntry("CastTime", spells2daRow, "0");
|
||||
}
|
||||
//if silenced, set it to no vocals
|
||||
if (metamagicNo == 4) {
|
||||
spells2da.setEntry("ConjSoundVFX", spells2daRow, "****");
|
||||
spells2da.setEntry("ConjSoundMale", spells2daRow, "****");
|
||||
spells2da.setEntry("ConjSoundFemale", spells2daRow, "****");
|
||||
spells2da.setEntry("CastSound", spells2daRow, "****");
|
||||
}
|
||||
//if stilled, set it to no casting animations
|
||||
if (metamagicNo == 5) {
|
||||
spells2da.setEntry("CastAnim", spells2daRow, "****");
|
||||
spells2da.setEntry("ConjAnim", spells2daRow, "****");
|
||||
}
|
||||
|
||||
//set the level to the correct value, including metamagic
|
||||
spells2da.setEntry("Innate", spells2daRow, Integer.toString(metamagicLevel + spellLevel));
|
||||
//clear class levels
|
||||
spells2da.setEntry("Bard", spells2daRow, "****");
|
||||
spells2da.setEntry("Cleric", spells2daRow, "****");
|
||||
spells2da.setEntry("Druid", spells2daRow, "****");
|
||||
spells2da.setEntry("Paladin", spells2daRow, "****");
|
||||
spells2da.setEntry("Ranger", spells2daRow, "****");
|
||||
spells2da.setEntry("Wiz_Sorc", spells2daRow, "****");
|
||||
|
||||
// set subradial master, if applicable
|
||||
if (subradialMaster != 0) {
|
||||
spells2da.setEntry("Master", spells2daRow, Integer.toString(subradialMaster));
|
||||
//calculate the new feat id
|
||||
int subradialFeatID = spells2da.getBiowareEntryAsInt("FeatID", subradialMaster);
|
||||
//Set the FEATID on each of the subspells as follows: (65536 * subfeat) + feat ID.
|
||||
//The top 16 bits is used for subfeat, the bottom for feat.
|
||||
subradialFeatID = (65536 * subradialID) + subradialFeatID;
|
||||
spells2da.setEntry("FeatID", spells2daRow, Integer.toString(subradialFeatID));
|
||||
} else {
|
||||
spells2da.setEntry("Master", spells2daRow, "****");
|
||||
//make it point to the new feat.2da line that will be added soon
|
||||
spells2da.setEntry("FeatID", spells2daRow, Integer.toString(feat2daRow));
|
||||
}
|
||||
|
||||
//remove projectiles from firing because the real spell will do this
|
||||
spells2da.setEntry("Proj", spells2daRow, "0");
|
||||
spells2da.setEntry("ProjModel", spells2daRow, "****");
|
||||
spells2da.setEntry("ProjType", spells2daRow, "****");
|
||||
spells2da.setEntry("ProjSpwnPoint", spells2daRow, "****");
|
||||
spells2da.setEntry("ProjSound", spells2daRow, "****");
|
||||
spells2da.setEntry("ProjOrientation", spells2daRow, "****");
|
||||
spells2da.setEntry("HasProjectile", spells2daRow, "0");
|
||||
|
||||
//add a feat.2da line
|
||||
if (subradialMaster == 0) {
|
||||
// Clear the line of old values
|
||||
for (String featLabel : feat2da.getLabels())
|
||||
feat2da.setEntry(featLabel, feat2daRow, "****");
|
||||
|
||||
// Reset the ReqAction column to 1
|
||||
feat2da.setEntry("ReqAction", feat2daRow, "1");
|
||||
|
||||
//make it point to the new spells.2da line
|
||||
feat2da.setEntry("SPELLID", feat2daRow, Integer.toString(spells2daRow));
|
||||
//change the Name
|
||||
feat2da.setEntry("FEAT", feat2daRow, Integer.toString(tlkRow + MAGIC_TLK));
|
||||
//change the Label
|
||||
feat2da.setEntry("LABEL", feat2daRow, label);
|
||||
//change the description
|
||||
feat2da.setEntry("DESCRIPTION", feat2daRow, spells2da.getEntry("SpellDesc", spells2daRow));
|
||||
//change the icon
|
||||
feat2da.setEntry("ICON", feat2daRow, spells2da.getEntry("IconResRef", spells2daRow));
|
||||
//personal range
|
||||
feat2da.setEntry("TARGETSELF", feat2daRow, spells2da.getEntry("Range", spellID).equals("P") ? "1" : "0");
|
||||
//if spell is hostile, make feat hostile
|
||||
if (spells2da.getEntry("HostileSetting", spellID).equals("1")) {
|
||||
feat2da.setEntry("HostileFeat", feat2daRow, "1");
|
||||
} else {
|
||||
feat2da.setEntry("HostileFeat", feat2daRow, "0");
|
||||
}
|
||||
//set the category to the same as the spell
|
||||
feat2da.setEntry("CATEGORY", feat2daRow, spells2da.getEntry("Category", spells2daRow));
|
||||
}
|
||||
|
||||
|
||||
//add an iprp_feats.2da line
|
||||
if (subradialMaster == 0) {
|
||||
// Clear the line of old values
|
||||
for (String iprpLabel : iprp_feats2da.getLabels())
|
||||
iprp_feats2da.setEntry(iprpLabel, iprp_feats2daRow, "****");
|
||||
|
||||
//set its label
|
||||
iprp_feats2da.setEntry("Label", iprp_feats2daRow, label);
|
||||
//set its name
|
||||
iprp_feats2da.setEntry("Name", iprp_feats2daRow, Integer.toString(tlkRow + MAGIC_TLK));
|
||||
//make it point to the new feat.2da line
|
||||
iprp_feats2da.setEntry("FeatIndex", iprp_feats2daRow, Integer.toString(feat2daRow));
|
||||
//set its cost to 0.0
|
||||
iprp_feats2da.setEntry("Cost", iprp_feats2daRow, "0.0");
|
||||
}
|
||||
|
||||
//add a cls_spell_*.2da line if needed
|
||||
if (localClassSpellRow >= classSpell2da.getEntryCount()) {
|
||||
classSpell2da.appendRow();
|
||||
}
|
||||
//set its label
|
||||
classSpell2da.setEntry("Label", localClassSpellRow, label);
|
||||
//make it point to the new spells.2da
|
||||
classSpell2da.setEntry("SpellID", localClassSpellRow, Integer.toString(spells2daRow));
|
||||
//make it point to the old spells.2da
|
||||
classSpell2da.setEntry("RealSpellID", localClassSpellRow, Integer.toString(spellID));
|
||||
|
||||
//if its a subradial, dont do this
|
||||
if (subradialMaster == 0) {
|
||||
//make it point to the new feat.2da
|
||||
classSpell2da.setEntry("FeatID", localClassSpellRow, Integer.toString(feat2daRow));
|
||||
//make it point to the new iprp_feats.2da
|
||||
classSpell2da.setEntry("IPFeatID", localClassSpellRow, Integer.toString(iprp_feats2daRow));
|
||||
//add the metamagic checks
|
||||
classSpell2da.setEntry("ReqFeat", localClassSpellRow, metamagicFeat);
|
||||
//set its level
|
||||
classSpell2da.setEntry("Level", localClassSpellRow, Integer.toString(metamagicLevel + spellLevel));
|
||||
} else {
|
||||
//make it point to the new feat.2da
|
||||
classSpell2da.setEntry("FeatID", localClassSpellRow, "****");
|
||||
//make it point to the new iprp_feats.2da
|
||||
classSpell2da.setEntry("IPFeatID", localClassSpellRow, "****");
|
||||
//add the metamagic checks
|
||||
classSpell2da.setEntry("ReqFeat", localClassSpellRow, "****");
|
||||
//set its level
|
||||
classSpell2da.setEntry("Level", localClassSpellRow, "****");
|
||||
}
|
||||
|
||||
//cls_feat_*.2da
|
||||
if (subradialMaster == 0) {
|
||||
classFeat2da.setEntry("FeatLabel", classFeatRow, label);
|
||||
classFeat2da.setEntry("FeatIndex", classFeatRow, Integer.toString(feat2daRow));
|
||||
classFeat2da.setEntry("List", classFeatRow, Integer.toString(0));
|
||||
classFeat2da.setEntry("GrantedOnLevel", classFeatRow, Integer.toString(99));
|
||||
classFeat2da.setEntry("OnMenu", classFeatRow, Integer.toString(1));
|
||||
}
|
||||
|
||||
|
||||
//move to next file lines
|
||||
getNextSpells2daRow();
|
||||
getNextTlkRow();
|
||||
//only need new ones of these if its not a subradial
|
||||
if (subradialMaster == 0) {
|
||||
getNextFeat2daRow();
|
||||
getNextIPRPFeats2daRow();
|
||||
getNextClassFeat2daRow();
|
||||
} else { //do this if it is a subradial
|
||||
// increase the subradial id ready for next one
|
||||
subradialID++;
|
||||
}
|
||||
|
||||
//add subradial spells
|
||||
if (subradialMaster == 0) {
|
||||
//store the spell row the master uses
|
||||
//will be incremented by subradials
|
||||
//the -1 is because you want the last used row, not the current blank row
|
||||
int masterSpellID = spells2daRow - 1;
|
||||
boolean doOnce = false;
|
||||
for (int subradial = 1; subradial <= 5; subradial++) {
|
||||
if (spells2da.getBiowareEntryAsInt("SubRadSpell" + subradial, spellID) != 0) {
|
||||
// It is, in fact, a radial master, so set it's ImpactScript to tell people
|
||||
// about the BioBug triggered by using subradial feats directly from class radial
|
||||
if (!doOnce) {
|
||||
doOnce = true;
|
||||
|
||||
spells2da.setEntry("ImpactScript", masterSpellID, "prc_radialbug");
|
||||
}
|
||||
addNewSpellbookData(spells2da.getBiowareEntryAsInt("SubRadSpell" + subradial, spellID),
|
||||
classfilename,
|
||||
metaScript,
|
||||
metamagicNo,
|
||||
metamagicLevel,
|
||||
metamagicFeat,
|
||||
spellLevel,
|
||||
className,
|
||||
spellNameMetamagic,
|
||||
classLabel,
|
||||
spellLabelMetamagic,
|
||||
preReservedClassSpell2daRows,
|
||||
masterSpellID);
|
||||
//update the master rows with the subradial spell rows
|
||||
//the -1 is because you want the last used row, not the current blank row
|
||||
spells2da.setEntry("SubRadSpell" + subradial, masterSpellID, Integer.toString(spells2daRow - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void getFirstSpells2daRow() {
|
||||
System.out.print("Finding start of spells.2da ");
|
||||
while (!spells2da.getEntry("Label", spells2daRow).equals(start_label)) {
|
||||
spells2daRow++;
|
||||
if (spells2daRow > spells2da.getEntryCount()) {
|
||||
System.out.println("Spells.2da reached the end of the file.");
|
||||
System.exit(1);
|
||||
}
|
||||
spinner.spin();
|
||||
}
|
||||
spells2daRow++;
|
||||
System.out.println("- Done");
|
||||
}
|
||||
|
||||
private static void getNextSpells2daRow() {
|
||||
spells2daRow++;
|
||||
if (spells2da.getEntry("Label", spells2daRow).equals(end_label)) {
|
||||
getFirstSpells2daRow();
|
||||
}
|
||||
}
|
||||
|
||||
private static void getFirstFeat2daRow() {
|
||||
System.out.print("Finding start of feat.2da ");
|
||||
while (!feat2da.getEntry("Label", feat2daRow).equals(start_label)) {
|
||||
feat2daRow++;
|
||||
if (feat2daRow > feat2da.getEntryCount()) {
|
||||
System.out.println("Feat.2da reached the end of the file.");
|
||||
System.exit(1);
|
||||
}
|
||||
spinner.spin();
|
||||
}
|
||||
feat2daRow++;
|
||||
System.out.println("- Done");
|
||||
}
|
||||
|
||||
private static void getNextFeat2daRow() {
|
||||
feat2daRow++;
|
||||
if (feat2da.getEntry("Label", feat2daRow).equals(end_label)) {
|
||||
getFirstFeat2daRow();
|
||||
}
|
||||
}
|
||||
|
||||
private static void getFirstIPRPFeats2daRow() {
|
||||
System.out.print("Finding start of iprp_spells.2da ");
|
||||
while (!iprp_feats2da.getEntry("Label", iprp_feats2daRow).equals(start_label)) {
|
||||
iprp_feats2daRow++;
|
||||
if (iprp_feats2daRow > iprp_feats2da.getEntryCount()) {
|
||||
System.out.println("iprp_feats.2da reached the end of the file.");
|
||||
System.exit(1);
|
||||
}
|
||||
spinner.spin();
|
||||
}
|
||||
iprp_feats2daRow++;
|
||||
System.out.println("- Done");
|
||||
}
|
||||
|
||||
private static void getNextIPRPFeats2daRow() {
|
||||
iprp_feats2daRow++;
|
||||
if (iprp_feats2da.getEntry("Label", iprp_feats2daRow).equals(end_label)) {
|
||||
getFirstIPRPFeats2daRow();
|
||||
}
|
||||
}
|
||||
|
||||
private static void getFirstClassFeat2daRow() {
|
||||
classFeatRow = 0;
|
||||
System.out.print("Finding start of cls_feat_*.2da ");
|
||||
while (!classFeat2da.getEntry("FeatLabel", classFeatRow).equals(start_label)) {
|
||||
classFeatRow++;
|
||||
if (classFeatRow >= classFeat2da.getEntryCount()) {
|
||||
System.out.println("cls_feat_*.2da reached the end of the file.");
|
||||
System.exit(1);
|
||||
}
|
||||
spinner.spin();
|
||||
}
|
||||
getNextClassFeat2daRow();
|
||||
System.out.println("- Done");
|
||||
}
|
||||
|
||||
private static void getNextClassFeat2daRow() {
|
||||
classFeatRow++;
|
||||
if (classFeat2da.getEntry("FeatLabel", classFeatRow).equals(end_label)) {
|
||||
classFeat2da.insertRow(classFeatRow);
|
||||
}
|
||||
}
|
||||
|
||||
private static void getFirstTlkRow() {
|
||||
System.out.print("Finding start of prc_consortium.tlk ");
|
||||
while (!customtlk.getEntry(tlkRow).equals(start_label)) {
|
||||
tlkRow++;
|
||||
spinner.spin();
|
||||
}
|
||||
tlkRow++;
|
||||
System.out.println("- Done");
|
||||
}
|
||||
|
||||
private static void getNextTlkRow() {
|
||||
tlkRow++;
|
||||
if (customtlk.getEntry(tlkRow).equals(end_label)) {
|
||||
getFirstTlkRow();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getCheckedTlkEntry(int entryNo) {
|
||||
if (entryNo > MAGIC_TLK) {
|
||||
return customtlk.getEntry(entryNo - MAGIC_TLK);
|
||||
}
|
||||
return dialogtlk.getEntry(entryNo);
|
||||
}
|
||||
|
||||
private static void readMe() {
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
System.out.println("Usage:\n" +
|
||||
" [--help]\n" +
|
||||
"\n" +
|
||||
" --help prints this text\n" +
|
||||
"\n" +
|
||||
" -tob Tome of Battle" +
|
||||
" -inv Invocations" +
|
||||
"\n" +
|
||||
"Creates and/or updates the new AMS spellbooks data. Assumes it's being run from\n" +
|
||||
"the root of the nwnprc cvs module. Looks for dialog.tlk under tlk/.\n" +
|
||||
"Reads the cls_??cr_*.2da files and updates cls_feat_*.2da, cls_????*.2da,\n" +
|
||||
"feat.2da, iprp_feats.2da and spells.2da."
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,197 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.Data_2da;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static prc.Main.err_pr;
|
||||
import static prc.Main.spinner;
|
||||
|
||||
|
||||
/**
|
||||
* This class is meant for updating the class feat lists with the entries common to all
|
||||
* base classes.
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class AllClassFeatUpdater {
|
||||
|
||||
private static boolean cropduplicates = false;
|
||||
|
||||
/**
|
||||
* Ye olde main method.
|
||||
* Takes as parameters the path of the 2da to use as update template and
|
||||
*
|
||||
* @param args [--help] | [-c] pathtoupdate2da targetpath+
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
if (args.length == 0) readMe();
|
||||
String cfabcPath = null;
|
||||
List<String> paths = new ArrayList<String>();
|
||||
|
||||
// parse args
|
||||
for (String param : args) {//[--help] | pathtoupdate2da targetpath+
|
||||
// Parameter parseage
|
||||
if (param.startsWith("-")) {
|
||||
if (param.equals("--help")) readMe();
|
||||
else {
|
||||
for (char c : param.substring(1).toCharArray()) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
cropduplicates = true;
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown parameter: " + c);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// It's a pathname
|
||||
if (cfabcPath == null)
|
||||
cfabcPath = param;
|
||||
else
|
||||
paths.add(param);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfabcPath == null) {
|
||||
err_pr.println("Error: You did not specify the location of cls_feat_allBaseClasses.2da\n");
|
||||
readMe();
|
||||
}
|
||||
if (paths.size() == 0) {
|
||||
err_pr.println("Error: You did not specify targets!\n");
|
||||
readMe();
|
||||
}
|
||||
spinner.disable();
|
||||
|
||||
// Load and crop the template 2da
|
||||
Data_2da source = Data_2da.load2da(cfabcPath);
|
||||
int i = source.getEntryCount();
|
||||
boolean passedEnd = false, passedBegin = false;
|
||||
while (--i >= 0) {
|
||||
//###cls_feat_allBaseClasses_BEGIN###
|
||||
//###cls_feat_allBaseClasses_END###
|
||||
if (!passedEnd) {
|
||||
if (source.getEntry("FeatLabel", i).equals("###cls_feat_allBaseClasses_END###")) {
|
||||
passedEnd = true;
|
||||
continue;
|
||||
} else
|
||||
source.removeRow(i);
|
||||
} else if (!passedBegin) {
|
||||
if (source.getEntry("FeatLabel", i).equals("###cls_feat_allBaseClasses_BEGIN###"))
|
||||
passedBegin = true;
|
||||
} else {
|
||||
source.removeRow(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the targets and update all files found
|
||||
for (String path : paths) {
|
||||
File target = new File(path);
|
||||
File[] cls_feat2da;
|
||||
|
||||
if (target.isDirectory()) {
|
||||
cls_feat2da = target.listFiles(new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
return file.getName().toLowerCase().startsWith("cls_feat_") &&
|
||||
file.getName().toLowerCase().endsWith(".2da");
|
||||
}
|
||||
});
|
||||
} else if (target.getName().toLowerCase().startsWith("cls_feat_") &&
|
||||
target.getName().toLowerCase().endsWith(".2da"))
|
||||
cls_feat2da = new File[]{target};
|
||||
else {
|
||||
err_pr.println("Error: Parameter \"" + path + "\" is not a valid target!");
|
||||
continue;
|
||||
}
|
||||
|
||||
Arrays.sort(cls_feat2da);
|
||||
|
||||
for (File file : cls_feat2da) {
|
||||
try {
|
||||
update2da(source, Data_2da.load2da(file.getCanonicalPath()), file.getParentFile().getCanonicalPath());
|
||||
} catch (Exception e) {
|
||||
err_pr.printException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void update2da(Data_2da updateSource, Data_2da target, String path) throws IOException {
|
||||
// Find the beginning of replaceable area
|
||||
int beginRow = -1, i = 0;
|
||||
while (beginRow == -1 && i < target.getEntryCount()) {
|
||||
if (target.getEntry("FeatLabel", i).equals("###cls_feat_allBaseClasses_BEGIN###"))
|
||||
beginRow = i;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (beginRow != -1) {
|
||||
// Strip the lines to be replaced
|
||||
while (beginRow < target.getEntryCount()) {
|
||||
if (target.getEntry("FeatLabel", beginRow).equals("###cls_feat_allBaseClasses_END###")) {
|
||||
target.removeRow(beginRow);
|
||||
break;
|
||||
} else
|
||||
target.removeRow(beginRow);
|
||||
}
|
||||
|
||||
// Handle cropping, if it is enabled
|
||||
if (cropduplicates) {
|
||||
// Make a copy of the update source, which can then be cropped
|
||||
updateSource = (Data_2da) updateSource.clone();
|
||||
cropDuplicates(updateSource, target);
|
||||
}
|
||||
|
||||
for (i = 0; i < updateSource.getEntryCount(); i++) {
|
||||
target.insertRow(beginRow + i, updateSource.getRow(i));
|
||||
}
|
||||
|
||||
//System.out.println(target); System.exit(0);
|
||||
target.save2da(path, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void cropDuplicates(Data_2da toCrop, Data_2da source) {
|
||||
// Load the featIDs from source to a hashset
|
||||
HashSet<Integer> featIDs = new HashSet<Integer>();
|
||||
|
||||
for (int i = 0; i < source.getEntryCount(); i++) {
|
||||
try {
|
||||
featIDs.add(Integer.parseInt(source.getEntry("FeatIndex", i)));
|
||||
} catch (NumberFormatException nfe) {/* Ignore empty rows */}
|
||||
}
|
||||
|
||||
// Loop over the crop target, removing rows whose FeatIndex is present in the source
|
||||
for (int i = toCrop.getEntryCount() - 1; i >= 0; i--) {
|
||||
try {
|
||||
if (featIDs.contains(Integer.parseInt(toCrop.getEntry("FeatIndex", i))))
|
||||
toCrop.removeRow(i);
|
||||
} catch (NumberFormatException nfe) {/* Ignore empty rows */}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void readMe() {
|
||||
System.out.println("Usage:\n" +
|
||||
" [--help] | [-c] pathtoupdate2da targetpath+\n" +
|
||||
"\n" +
|
||||
" pathtoupdate2da path of the cls_feat_allBaseClasses.2da\n" +
|
||||
" targetpath the path of a directory containing the cls_feat_*.2das to update\n" +
|
||||
" or directly the path of a cls_feat_*.2da\n" +
|
||||
"\n" +
|
||||
" -c crop rows from the update source that contain featIDs present elsewhere\n" +
|
||||
" in the target than in the updateable area\n" +
|
||||
"\n" +
|
||||
" --help prints this text\n"
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,116 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A tool for blanking ranges of 2da rows.
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class Blank2daRows {
|
||||
|
||||
/**
|
||||
* Ye olde maine methode.
|
||||
*
|
||||
* @param args The program arguments, as usual.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length == 0) readMe();
|
||||
String targetPath = null;
|
||||
List<int[]> ranges = new ArrayList<int[]>();
|
||||
|
||||
for (String param : args) {//target B-E ... | [--help]
|
||||
// Parameter parseage
|
||||
if (param.startsWith("-")) {
|
||||
if (param.equals("--help")) readMe();
|
||||
else {
|
||||
for (char c : param.substring(1).toCharArray()) {
|
||||
switch (c) {
|
||||
default:
|
||||
System.err.println("Unknown parameter: " + c);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
// If the target file hasn't been specified, assume this is it
|
||||
if (targetPath == null)
|
||||
targetPath = param;
|
||||
else {
|
||||
try {
|
||||
if (!param.contains("-")) throw new Exception(); // Missing -
|
||||
String[] rawNums = param.split("-");
|
||||
if (rawNums.length != 2) throw new Exception(); // More than two numbers(?) in the string
|
||||
int[] range = new int[]{Integer.parseInt(rawNums[0]), Integer.parseInt(rawNums[1])};
|
||||
ranges.add(range);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Malformed number pair:" + param);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load the 2da
|
||||
Data_2da target = Data_2da.load2da(targetPath);
|
||||
|
||||
// Bounds checks
|
||||
for (int[] range : ranges) {
|
||||
if (range[0] > range[1]) { // Lower bound > upper bound
|
||||
System.err.println("Lower bound > upper bound in pair: " + range[0] + "-" + range[1]);
|
||||
System.exit(1);
|
||||
}
|
||||
if (range[0] < 0 || range[1] < 0 ||
|
||||
range[0] >= target.getEntryCount() ||
|
||||
range[1] >= target.getEntryCount()) { // Bound out of range
|
||||
System.err.println("Bound out of range in pair: " + range[0] + "-" + range[1]);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Do blanking
|
||||
for (int[] range : ranges)
|
||||
blankRows(target, range[0], range[1]);
|
||||
|
||||
// Save 2da back out
|
||||
target.save2da(new File(targetPath).getParent(), true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the row blanking - replaces the contents of each column in the affected row range with whatever
|
||||
* is the default value in this 2da.
|
||||
*
|
||||
* @param target Data_2da to perform the operation on
|
||||
* @param begin Beginning of the range to blank, inclusive
|
||||
* @param end End of the range to blank, inclusive
|
||||
*/
|
||||
private static void blankRows(Data_2da target, int begin, int end) {
|
||||
for (int i = begin; i <= end; i++) {
|
||||
for (String label : target.getLabels())
|
||||
target.setEntry(label, i, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static void readMe() {
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
System.out.println("Usage:\n" +
|
||||
" target B-E ... | [--help]\n" +
|
||||
"\n" +
|
||||
" This tool blanks rows in a 2da file, replacing the contents of given rows with\n" +
|
||||
" either **** or the 2da-specific default value if such is specified.\n" +
|
||||
"\n" +
|
||||
" target Path to the 2da file to apply the blanking operation to\n" +
|
||||
" B-E Row number pair, specifying which rows in the file to blank. Inclusive,\n" +
|
||||
" for example 1000-1002 would blank rows 1000, 1001 and 1002. Multiple\n" +
|
||||
" ranges may be specified.\n" +
|
||||
"\n" +
|
||||
" --help prints this text\n"
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,87 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.Main.TLKStore;
|
||||
import prc.autodoc.Main.TwoDAStore;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A class that combines Scrollgen, UpdateDes and ScrollMerchantGen. For use during
|
||||
* the build process to avoid loading the same 2da files several times.
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class BuildScrollHack {
|
||||
|
||||
/**
|
||||
* Ye olde maine methode.
|
||||
*
|
||||
* @param args The arguments
|
||||
* @throws IOException Just toss any exceptions encountered
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
if (args.length == 0) readMe();
|
||||
String twoDAPath = null;
|
||||
String tlkPath = null;
|
||||
String outPath = null;
|
||||
|
||||
// parse args
|
||||
for (String param : args) {//2dadir tlkdir outpath| [--help]
|
||||
// Parameter parseage
|
||||
if (param.startsWith("-")) {
|
||||
if (param.equals("--help")) readMe();
|
||||
else {
|
||||
for (char c : param.substring(1).toCharArray()) {
|
||||
switch (c) {
|
||||
default:
|
||||
System.out.println("Unknown parameter: " + c);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// It's a pathname
|
||||
if (twoDAPath == null)
|
||||
twoDAPath = param;
|
||||
else if (tlkPath == null)
|
||||
tlkPath = param;
|
||||
else if (outPath == null)
|
||||
outPath = param;
|
||||
else {
|
||||
System.out.println("Unknown parameter: " + param);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load data
|
||||
TwoDAStore twoDA = new TwoDAStore(twoDAPath);
|
||||
TLKStore tlks = new TLKStore("dialog.tlk", "prc_consortium.tlk", tlkPath);
|
||||
|
||||
ScrollGen.doScrollGen(twoDA, twoDAPath, outPath);
|
||||
UpdateDes.doUpdateDes(twoDA, twoDAPath);
|
||||
ScrollMerchantGen.doScrollMerchantGen(twoDA, tlks, outPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the use instructions for this program and kills execution.
|
||||
*/
|
||||
private static void readMe() {
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
System.out.println("Usage:\n" +
|
||||
" java -jar prc.jar buildscrhack 2dadir tlkdir outpath| [--help]\n" +
|
||||
"\n" +
|
||||
"2dadir Path to a directory containing 2da files\n" +
|
||||
"tlkdir Path to a directory containing dialog.tlk and prc_consortium.tlk\n" +
|
||||
"outdir Path to the directory to save the new scroll xml files in\n" +
|
||||
"\n" +
|
||||
"--help prints this info you are reading\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"A tool for automatically updating parts of des_crft_scrolls.2da and\n" +
|
||||
"des_crft_spells.2da based on spells.2da\n"
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,128 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.Data_2da;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.util.Scanner;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class CodeGen {
|
||||
private CodeGen() {
|
||||
}
|
||||
|
||||
private static class Script implements Cloneable {
|
||||
public String text,
|
||||
name;
|
||||
|
||||
public Script(String text, String name) {
|
||||
this.text = text;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
return new Script(text, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static String prefix,
|
||||
suffix,
|
||||
template;
|
||||
private static Data_2da[] data;
|
||||
|
||||
/**
|
||||
* The main method, as usual.
|
||||
*
|
||||
* @param args do I really need to exapain this?
|
||||
* @throws Exception this is a simple tool, just let all failures blow up
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length == 0 || args[0].equals("--help") || args[0].equals("-?"))
|
||||
readMe();
|
||||
|
||||
prefix = args[0];
|
||||
suffix = args[1];
|
||||
template = readTemplate(args[2]);
|
||||
|
||||
data = new Data_2da[args.length - 3];
|
||||
for (int i = 0; i < data.length; i++)
|
||||
data[i] = Data_2da.load2da(args[i + 3]);
|
||||
|
||||
doCreation(new Script(template, prefix), 0);
|
||||
}
|
||||
|
||||
private static void readMe() {
|
||||
System.out.println("Usage:\n" +
|
||||
"\tjava CodeGen namePrefix nameSuffix templatePath 2daPaths...\n" +
|
||||
"\n" +
|
||||
"namePrefix\tprefix that all the resulting filenames will share\n" +
|
||||
"nameSuffix\tsuffix that all the resulting filenames will share\n" +
|
||||
"templatePath\tlocation of the template to use. May be absolute or relative\n" +
|
||||
"2daPaths\tone or more 2da files to use fill the template with\n" +
|
||||
"\n\n" +
|
||||
"Places to replace in the template are marked with ~~~Identifier~~~. This will\n" +
|
||||
"be replaced by entries from a column in one of the 2das labeled Identifier.\n" +
|
||||
"This is case-insensitive.\n" +
|
||||
"\n" +
|
||||
"The 2da files must contain two columns labeled Suffix and Value.\n" +
|
||||
"\n" +
|
||||
"One script file will be generated for each possible combination of values from\n" +
|
||||
"the 2das. They will automatically have file type identifier of .nss"
|
||||
);
|
||||
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
|
||||
private static String readTemplate(String filePath) throws Exception {
|
||||
Scanner reader = new Scanner(new File(filePath));
|
||||
StringBuffer temp = new StringBuffer();
|
||||
|
||||
while (reader.hasNextLine()) temp.append(reader.nextLine() + "\n");
|
||||
|
||||
return temp.toString();
|
||||
}
|
||||
|
||||
|
||||
private static void doCreation(Script script, int depth) throws Exception {
|
||||
if (depth == data.length) {
|
||||
printScript(script);
|
||||
return;
|
||||
}
|
||||
Script copy;
|
||||
|
||||
for (int i = 0; i < data[depth].getEntryCount(); i++) {
|
||||
copy = (Script) script.clone();
|
||||
for (String label : data[depth].getLabels())
|
||||
copy.text = Pattern.compile("~~~" + label + "~~~", Pattern.CASE_INSENSITIVE)
|
||||
.matcher(copy.text)
|
||||
.replaceAll(data[depth].getEntry(label, i));
|
||||
/*copy.text = script.text.replaceAll("~~~" + data[depth].getName() + "~~~",
|
||||
data[depth].getEntry("Value", i));*/
|
||||
copy.name += data[depth].getEntry("Suffix", i) != null ?
|
||||
data[depth].getEntry("Suffix", i) :
|
||||
"";
|
||||
|
||||
doCreation(copy, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void printScript(Script toPrint) throws Exception {
|
||||
File target = new File(toPrint.name + suffix);
|
||||
// Clean up old version if necessary
|
||||
if (target.exists()) {
|
||||
System.out.println("Deleting previous version of " + target.getName());
|
||||
target.delete();
|
||||
}
|
||||
target.createNewFile();
|
||||
|
||||
// Creater the writer and print
|
||||
FileWriter writer = new FileWriter(target, false);
|
||||
writer.write(toPrint.text);
|
||||
// Clean up
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,127 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.*;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public final class Data2daMerge {
|
||||
private Data2daMerge() {
|
||||
}
|
||||
|
||||
private static String source = "";
|
||||
private static String merge = "";
|
||||
private static String output = "";
|
||||
|
||||
/**
|
||||
* The main method, as usual.
|
||||
*
|
||||
* @param args do I really need to explain this?
|
||||
* @throws Exception this is a simple tool, just let all failures blow up
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length < 3 || args[0].equals("--help") || args[0].equals("-?"))
|
||||
readMe();
|
||||
|
||||
//check arguments for directories to use
|
||||
source = args[0];
|
||||
merge = args[1];
|
||||
output = args[2];
|
||||
|
||||
//assemble arrays of filenames
|
||||
File[] sourceFiles = new File(source).listFiles();
|
||||
File[] mergeFiles = new File(merge).listFiles();
|
||||
|
||||
//define some things for speed
|
||||
File sourceFile;
|
||||
File mergeFile;
|
||||
Data_2da sourceData;
|
||||
Data_2da mergeData;
|
||||
Data_2da outputData;
|
||||
|
||||
for (int i = 0; i < sourceFiles.length; i++) {
|
||||
sourceFile = sourceFiles[i];
|
||||
//ignore non-2da files
|
||||
if (sourceFile.getPath().endsWith(".2da")) {
|
||||
String sourceFilename = sourceFile.getName().substring(0, sourceFile.getName().length() - 4);
|
||||
//loop over the merge files to find one that matches the source
|
||||
boolean matchFound = false;
|
||||
for (int j = 0; j < mergeFiles.length; j++) {
|
||||
mergeFile = mergeFiles[j];
|
||||
//ignore non-2da files
|
||||
if (mergeFile.getPath().endsWith(".2da")) {
|
||||
String mergeFilename = mergeFile.getName().substring(0, mergeFile.getName().length() - 4);
|
||||
//its a match
|
||||
if (mergeFilename.equals(sourceFilename)) {
|
||||
matchFound = true;
|
||||
String sourcePath = sourceFile.getAbsolutePath();
|
||||
String mergePath = mergeFile.getAbsolutePath();
|
||||
sourceData = Data_2da.load2da(sourcePath, true);
|
||||
mergeData = Data_2da.load2da(mergePath, true);
|
||||
outputData = Data_2da.load2da(sourcePath, true);
|
||||
//Data_2da outputData = sourceData;
|
||||
//get the smallest number of rows
|
||||
int rowCount = sourceData.getEntryCount();
|
||||
if (rowCount > mergeData.getEntryCount())
|
||||
rowCount = mergeData.getEntryCount();
|
||||
|
||||
//check the columns match
|
||||
//or at least the number of them
|
||||
int colCount = sourceData.getLabels().length;
|
||||
if (mergeData.getLabels().length != colCount) {
|
||||
System.out.println("Number of columns does not match!");
|
||||
} else {
|
||||
//loop over the overlapping rows
|
||||
for (int row = 0; row < rowCount; row++) {
|
||||
for (int col = 0; col < colCount; col++) {
|
||||
String columnName = sourceData.getLabels()[col];
|
||||
String sourceEntry = sourceData.getEntry(columnName, row);
|
||||
String mergeEntry = mergeData.getEntry(columnName, row);
|
||||
if (!mergeEntry.equals("****")
|
||||
&& !mergeEntry.equals(sourceEntry)) {
|
||||
outputData.setEntry(columnName, row, mergeEntry);
|
||||
//made a change, log it
|
||||
System.out.println(sourceFilename + " : " + columnName + "," + row + " " + sourceEntry + " -> " + mergeEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
//check if merge has extra rows
|
||||
if (rowCount < mergeData.getEntryCount()) {
|
||||
for (int row = rowCount; row < mergeData.getEntryCount(); row++) {
|
||||
outputData.appendRow();
|
||||
//copy the extra rows to the output
|
||||
for (int col = 0; col < colCount; col++) {
|
||||
String columnName = sourceData.getLabels()[col];
|
||||
String mergeEntry = mergeData.getEntry(columnName, row);
|
||||
if (!mergeEntry.equals("****")) {
|
||||
outputData.setEntry(columnName, row, mergeEntry);
|
||||
//made a change, log it
|
||||
System.out.println(sourceFilename + " : " + columnName + "," + row + " null -> " + mergeEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//finished assembling the output file, write it
|
||||
//this overwrites the target file
|
||||
outputData.save2da(output, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
//end of file loop for
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void readMe() {
|
||||
System.out.println("Usage:\n" +
|
||||
"\tjava 2damerge source merge output\n" +
|
||||
"\n" +
|
||||
"This application is designed to take all the 2DA\n" +
|
||||
"files in the source directory, merge them with the\n" +
|
||||
"2DA files in the merge directory, and output the\n" +
|
||||
"edited versions to the output directory"
|
||||
);
|
||||
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,127 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static prc.Main.err_pr;
|
||||
|
||||
/**
|
||||
* Checks the given column in the given 2da for duplicate entries.
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class Duplicate2daEntryDetector {
|
||||
|
||||
private static boolean ignoreCase = false;
|
||||
private static boolean accountEmpty = false;
|
||||
|
||||
/**
|
||||
* Ye olde main.
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
if (args.length == 0) readMe();
|
||||
String filePath = null;
|
||||
ArrayList<String> labels = new ArrayList<String>();
|
||||
|
||||
// parse args
|
||||
for (String param : args) {//[--help] | [-i] pathof2da columnlabel+
|
||||
// Parameter parseage
|
||||
if (param.startsWith("-")) {
|
||||
if (param.equals("--help")) readMe();
|
||||
else {
|
||||
for (char c : param.substring(1).toCharArray()) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
ignoreCase = true;
|
||||
break;
|
||||
case 'e':
|
||||
accountEmpty = true;
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown parameter: " + c);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// It's a pathname
|
||||
if (filePath == null)
|
||||
filePath = param;
|
||||
else
|
||||
labels.add(param);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the 2da
|
||||
Data_2da file = Data_2da.load2da(filePath);
|
||||
|
||||
// Test the columns
|
||||
for (String label : labels) {
|
||||
TreeMap<String, ArrayList<Integer>> duplicates = new TreeMap<String, ArrayList<Integer>>();
|
||||
// Examine column
|
||||
HashMap<String, Integer> entries = new HashMap<String, Integer>();
|
||||
String value;
|
||||
for (int i = 0; i < file.getEntryCount(); i++) {
|
||||
value = accountForCase(file, label, i);
|
||||
// Do not account for empty entries unless requested
|
||||
if (value.equals("****") && !accountEmpty)
|
||||
continue;
|
||||
|
||||
if (!entries.containsKey(value))
|
||||
entries.put(value, i);
|
||||
else {
|
||||
// If no duplicates of this value have yet been found, init the arraylist for it
|
||||
if (!duplicates.containsKey(value)) {
|
||||
duplicates.put(value, new ArrayList<Integer>());
|
||||
duplicates.get(value).add(entries.get(value));
|
||||
}
|
||||
// Either way, add the current row to the list of duplicates
|
||||
duplicates.get(value).add(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (ArrayList<Integer> duprows : duplicates.values()) {
|
||||
StringBuffer toPrint = new StringBuffer(file.getName() + ": duplicate " + label + " on rows");
|
||||
boolean first = true;
|
||||
for (int row : duprows) {
|
||||
if (!first)
|
||||
toPrint.append(',');
|
||||
else
|
||||
first = false;
|
||||
|
||||
toPrint.append(" " + row);
|
||||
}
|
||||
|
||||
err_pr.println(toPrint.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String accountForCase(Data_2da data, String label, int index) {
|
||||
return ignoreCase ?
|
||||
data.getEntry(label, index).toLowerCase() :
|
||||
data.getEntry(label, index);
|
||||
}
|
||||
|
||||
private static void readMe() {
|
||||
System.out.println("Usage:\n" +
|
||||
" [--help] | [-ce] pathof2da columnlabel+\n" +
|
||||
"\n" +
|
||||
" pathof2da path of the 2da to check\n" +
|
||||
" columnlabel label of a column to test for duplicate entries\n" +
|
||||
"\n" +
|
||||
" -c ignores case of the entries testes for duplicacy\n" +
|
||||
" -e does not ignore empty entries. ie, ****\n" +
|
||||
"\n" +
|
||||
" --help prints this text\n" +
|
||||
"\n" +
|
||||
"Unless -e is specified, empty entries (****) do not count as duplicates\n"
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,200 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,278 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
|
||||
import static prc.Main.verbose;
|
||||
|
||||
public final class ItempropMaker {
|
||||
private ItempropMaker() {
|
||||
}
|
||||
|
||||
|
||||
private static Data_2da itempropdef2da;
|
||||
private static Data_2da costtable2da;
|
||||
private static Data_2da paramtable2da;
|
||||
private static Data_2da[] cost2daarray;
|
||||
private static Data_2da[] param12daarray;
|
||||
private static StringBuilder xml;
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
//load the 2das
|
||||
itempropdef2da = Data_2da.load2da("2das" + File.separator + "itempropdef.2da", true);
|
||||
costtable2da = Data_2da.load2da("2das" + File.separator + "iprp_costtable.2da", true);
|
||||
paramtable2da = Data_2da.load2da("2das" + File.separator + "iprp_paramtable.2da", true);
|
||||
cost2daarray = new Data_2da[costtable2da.getEntryCount()];
|
||||
param12daarray = new Data_2da[paramtable2da.getEntryCount()];
|
||||
for (int i = 0; i < cost2daarray.length; i++) {
|
||||
cost2daarray[i] = Data_2da.load2da("2das" + File.separator + costtable2da.getBiowareEntry("Name", i) + ".2da", true);
|
||||
}
|
||||
for (int i = 0; i < param12daarray.length; i++) {
|
||||
param12daarray[i] = Data_2da.load2da("2das" + File.separator + paramtable2da.getBiowareEntry("TableResRef", i) + ".2da", true);
|
||||
}
|
||||
//loop over each row
|
||||
for (int itempropdef2darow = 85;
|
||||
itempropdef2darow < itempropdef2da.getEntryCount();
|
||||
itempropdef2darow++) {
|
||||
if (itempropdef2da.getBiowareEntryAsInt("Name", itempropdef2darow) != 0) {
|
||||
int type = itempropdef2darow;
|
||||
int subtype;
|
||||
int cost;
|
||||
int param1;
|
||||
if (itempropdef2da.getBiowareEntry("SubTypeResRef", type) == "")
|
||||
subtype = 0;
|
||||
else
|
||||
subtype = 1;
|
||||
if (itempropdef2da.getBiowareEntryAsInt("CostTableResRef", type) == 0)
|
||||
cost = 0;
|
||||
else
|
||||
cost = 1;
|
||||
if (itempropdef2da.getBiowareEntry("Param1ResRef", type) == "")
|
||||
param1 = 0;
|
||||
else
|
||||
param1 = 1;
|
||||
//loop over each subtype
|
||||
if (subtype != 0) {
|
||||
Data_2da subtype2da = Data_2da.load2da("2das" + File.separator + itempropdef2da.getBiowareEntry("SubTypeResRef", type) + ".2da", true);
|
||||
|
||||
for (int subtypeID = 0; subtypeID < subtype2da.getEntryCount(); subtypeID++) {
|
||||
//loop over the param1s, if applicable
|
||||
//look if there is a column for it
|
||||
boolean subtypeparam1columnexists = false;
|
||||
String[] columnlabels = subtype2da.getLabels();
|
||||
for (int i = 0; i < columnlabels.length; i++) {
|
||||
if (columnlabels[i] == "Param1ResRef")
|
||||
subtypeparam1columnexists = true;
|
||||
}
|
||||
if (subtypeparam1columnexists
|
||||
&& subtype2da.getBiowareEntry("Param1ResRef", subtypeID) == "") {
|
||||
param1 = 1;
|
||||
} else {
|
||||
if (itempropdef2da.getBiowareEntry("Param1ResRef", type) == "")
|
||||
param1 = 0;
|
||||
else
|
||||
param1 = 2;
|
||||
}
|
||||
if (param1 != 0) {
|
||||
int param1tableid = 0;
|
||||
if (param1 == 2)
|
||||
param1tableid = itempropdef2da.getBiowareEntryAsInt("Param1ResRef", type);
|
||||
else if (param1 == 1)
|
||||
param1tableid = subtype2da.getBiowareEntryAsInt("Param1ResRef", subtypeID);
|
||||
Data_2da param12da = param12daarray[param1tableid];
|
||||
for (int param1ID = 0; param1ID < param12da.getEntryCount(); param1ID++) {
|
||||
if (cost != 0) {
|
||||
int costtable = itempropdef2da.getBiowareEntryAsInt("CostTableResRef", type);
|
||||
Data_2da cost2da = cost2daarray[costtable];
|
||||
//has type, subtype, param1, and cost
|
||||
write(type, subtypeID, param1tableid, param1ID, costtable, cost2da.getEntryCount());
|
||||
} else {
|
||||
//no cost
|
||||
//has type, subtype, and param1
|
||||
write(type, subtypeID, param1tableid, param1ID, -1, -1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//no param1
|
||||
if (cost != 0) {
|
||||
int costtable = itempropdef2da.getBiowareEntryAsInt("CostTableResRef", type);
|
||||
Data_2da cost2da = cost2daarray[costtable];
|
||||
//has type, subtype, and cost
|
||||
write(type, subtypeID, -1, -1, costtable, cost2da.getEntryCount());
|
||||
} else {
|
||||
//no cost
|
||||
//has type, and subtype
|
||||
write(type, subtypeID, -1, -1, -1, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//no subtype
|
||||
if (param1 != 0) {
|
||||
int param1tableid = itempropdef2da.getBiowareEntryAsInt("Param1ResRef", type);
|
||||
Data_2da param12da = param12daarray[param1tableid];
|
||||
for (int param1ID = 0; param1ID < param12da.getEntryCount(); param1ID++) {
|
||||
if (cost != 0) {
|
||||
int costtable = itempropdef2da.getBiowareEntryAsInt("CostTableResRef", type);
|
||||
Data_2da cost2da = cost2daarray[costtable];
|
||||
//has type, param1, and cost
|
||||
write(type, -1, param1tableid, param1ID, costtable, cost2da.getEntryCount());
|
||||
} else {
|
||||
//no cost
|
||||
//has type, and param1
|
||||
write(type, -1, param1tableid, param1ID, -1, -1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//no param1
|
||||
if (cost != 0) {
|
||||
int costtable = itempropdef2da.getBiowareEntryAsInt("CostTableResRef", type);
|
||||
Data_2da cost2da = cost2daarray[costtable];
|
||||
//has type, and cost
|
||||
write(type, -1, -1, -1, costtable, cost2da.getEntryCount());
|
||||
} else {
|
||||
//no cost
|
||||
//has type
|
||||
write(type, -1, -1, -1, -1, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
<!-- This file was generated by the NWNTools GFF to XML writer.
|
||||
http://nwntools.sf.net/
|
||||
** Do not hand edit unless you know what you are doing. **
|
||||
|
||||
-->
|
||||
- <gff name="master111.uti" type="UTI" version="V3.2">
|
||||
- <struct id="-1">
|
||||
<element name="TemplateResRef" type="11" value="master111" />
|
||||
<element name="BaseItem" type="5" value="111" />
|
||||
<element name="LocalizedName" type="12" value="83617" />
|
||||
<element name="Description" type="12" value="-1" />
|
||||
<element name="DescIdentified" type="12" value="-1" />
|
||||
<element name="Tag" type="10" value="master111" />
|
||||
<element name="Charges" type="0" value="0" />
|
||||
<element name="Cost" type="4" value="2" />
|
||||
<element name="Stolen" type="0" value="0" />
|
||||
<element name="StackSize" type="2" value="1" />
|
||||
<element name="Plot" type="0" value="0" />
|
||||
<element name="AddCost" type="4" value="0" />
|
||||
<element name="Identified" type="0" value="1" />
|
||||
<element name="Cursed" type="0" value="0" />
|
||||
<element name="ModelPart1" type="0" value="11" />
|
||||
<element name="ModelPart2" type="0" value="11" />
|
||||
<element name="ModelPart3" type="0" value="11" />
|
||||
- <element name="PropertiesList" type="15">
|
||||
<struct id="0" >
|
||||
<element name="PropertyName" type="2" value="85" />
|
||||
<element name="Subtype" type="2" value="6" />
|
||||
<element name="CostTable" type="0" value="28" />
|
||||
<element name="CostValue" type="2" value="0" />
|
||||
<element name="Param1" type="0" value="0" />
|
||||
<element name="Param1Value" type="0" value="0" />
|
||||
<element name="ChanceAppear" type="0" value="100" />
|
||||
</struct>
|
||||
- <struct id="0">
|
||||
<element name="PropertyName" type="2" value="12" />
|
||||
<element name="Subtype" type="2" value="37" />
|
||||
<element name="CostTable" type="0" value="0" />
|
||||
<element name="CostValue" type="2" value="0" />
|
||||
<element name="Param1" type="0" value="255" />
|
||||
<element name="Param1Value" type="0" value="0" />
|
||||
<element name="ChanceAppear" type="0" value="100" />
|
||||
</struct>
|
||||
</element>
|
||||
<element name="PaletteID" type="0" value="47" />
|
||||
<element name="Comment" type="10" value="" />
|
||||
</struct>
|
||||
</gff>
|
||||
*/
|
||||
private static void write(int type, int subtype, int param1table, int param1value, int costtable,
|
||||
int costmax) throws Exception {
|
||||
|
||||
xml = new StringBuilder(0xFFFFF);
|
||||
//assemble the resref/tag
|
||||
String resref = "prc_ip" + type;
|
||||
if (subtype != -1)
|
||||
resref += "_" + subtype;
|
||||
if (param1value != -1)
|
||||
resref += "_" + param1value;
|
||||
//sanity checks
|
||||
if (param1value == -1)
|
||||
param1value = 0;
|
||||
if (param1table == -1)
|
||||
param1table = 255;
|
||||
if (subtype == -1)
|
||||
subtype = 0;
|
||||
if (costtable == -1)
|
||||
costtable = 0;
|
||||
if (costmax == -1)
|
||||
costmax = 0;
|
||||
//output stuff
|
||||
//header things first
|
||||
xml.append("<gff name=\"" + resref + ".uti\" type=\"UTI \" version=\"V3.2\">\n");
|
||||
xml.append(" <struct id=\"-1\">\n");
|
||||
xml.append(" <element name=\"TemplateResRef\" type=\"11\" value=\"" + resref + "\" />\n");
|
||||
xml.append(" <element name=\"BaseItem\" type=\"5\" value=\"78\" />\n");
|
||||
xml.append(" <element name=\"LocalizedName\" type=\"12\" value=\"-1\" >\n");
|
||||
xml.append(" <localString languageId=\"0\" value=\"0\" />\n");
|
||||
xml.append(" </element>\n");
|
||||
xml.append(" <element name=\"Description\" type=\"12\" value=\"-1\" />\n");
|
||||
xml.append(" <element name=\"DescIdentified\" type=\"12\" value=\"-1\" />\n");
|
||||
xml.append(" <element name=\"Tag\" type=\"10\" value=\"" + resref + "\" />\n");
|
||||
xml.append(" <element name=\"Charges\" type=\"0\" value=\"0\" />\n");
|
||||
xml.append(" <element name=\"Cost\" type=\"4\" value=\"2\" />\n");
|
||||
xml.append(" <element name=\"Stolen\" type=\"0\" value=\"0\" />\n");
|
||||
xml.append(" <element name=\"StackSize\" type=\"2\" value=\"1\" />\n");
|
||||
xml.append(" <element name=\"Plot\" type=\"0\" value=\"0\" />\n");
|
||||
xml.append(" <element name=\"AddCost\" type=\"4\" value=\"0\" />\n");
|
||||
xml.append(" <element name=\"Identified\" type=\"0\" value=\"1\" />\n");
|
||||
xml.append(" <element name=\"Cursed\" type=\"0\" value=\"0\" />\n");
|
||||
xml.append(" <element name=\"ModelPart1\" type=\"0\" value=\"1\" />\n");
|
||||
xml.append(" <element name=\"PropertiesList\" type=\"15\">\n");
|
||||
//loop over the itemproperties
|
||||
for (int i = 0; i < costmax; i++) {
|
||||
xml.append(" <struct id=\"0\" >\n");
|
||||
xml.append(" <element name=\"PropertyName\" type=\"2\" value=\"" + type + "\" />\n");
|
||||
xml.append(" <element name=\"Subtype\" type=\"2\" value=\"" + subtype + "\" />\n");
|
||||
xml.append(" <element name=\"CostTable\" type=\"0\" value=\"" + costtable + "\" />\n");
|
||||
xml.append(" <element name=\"CostValue\" type=\"2\" value=\"" + i + "\" />\n");
|
||||
xml.append(" <element name=\"Param1\" type=\"0\" value=\"" + param1table + "\" />\n");
|
||||
xml.append(" <element name=\"Param1Value\" type=\"0\" value=\"" + param1value + "\" />\n");
|
||||
xml.append(" <element name=\"ChanceAppear\" type=\"0\" value=\"100\" />\n");
|
||||
xml.append(" </struct>\n");
|
||||
}
|
||||
//footer stuff
|
||||
xml.append(" </element>\n");
|
||||
//this is set to 99 so it will not appear in the palette :)
|
||||
xml.append(" <element name=\"PaletteID\" type=\"0\" value=\"99\" />\n");
|
||||
xml.append(" <element name=\"Comment\" type=\"10\" value=\"\" />\n");
|
||||
xml.append(" </struct>\n");
|
||||
xml.append("</gff>");
|
||||
|
||||
File target = new File("xml_temp" + File.separator + resref + ".uti.xml");
|
||||
// Clean up old version if necessary
|
||||
if (target.exists()) {
|
||||
if (verbose) System.out.println("Deleting previous version of " + target.getName());
|
||||
target.delete();
|
||||
}
|
||||
if (verbose) System.out.println("Writing brand new version of " + target.getName());
|
||||
target.createNewFile();
|
||||
|
||||
// Creater the writer and print
|
||||
FileWriter writer = new FileWriter(target, true);
|
||||
writer.write(xml.toString());
|
||||
// Clean up
|
||||
writer.flush();
|
||||
writer.close();
|
||||
// Force garbage collection
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,137 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.*;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static prc.Main.err_pr;
|
||||
|
||||
/**
|
||||
* A class for generating Leto XML files from 2da and TLK.
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public final class LetoListsGenerator {
|
||||
private final Data_TLK defaultTLK;
|
||||
private final Data_TLK userTLK;
|
||||
|
||||
private LetoListsGenerator(Data_TLK defaultTLK, Data_TLK userTLK) {
|
||||
this.defaultTLK = defaultTLK;
|
||||
this.userTLK = userTLK;
|
||||
}
|
||||
|
||||
private String getTLK(int num) {
|
||||
return num < 0x01000000 ? defaultTLK.getEntry(num) : userTLK.getEntry(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given 2da into a Leto XML file.
|
||||
*
|
||||
* @param toPrint Data_2da containing the 2da to print
|
||||
* @param nameColumn The name of the column that defines the name of the entry in TLK
|
||||
* @param os The outputstream to write the xml to
|
||||
*/
|
||||
public void printData2daAsLetoXML(Data_2da toPrint, String nameColumn, OutputStream os) {
|
||||
PrintStream ps = new PrintStream(os, true);
|
||||
StringBuilder sb;
|
||||
// Print header
|
||||
ps.println("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>");
|
||||
ps.println("<LetoList comment=\"Created with a Java-based tool\">");
|
||||
|
||||
// Print contents
|
||||
for (int i = 0; i < toPrint.getEntryCount(); i++) {
|
||||
if (!toPrint.getBiowareEntry(nameColumn, i).equals("")) {
|
||||
sb = new StringBuilder(" <item index=\"" + i + "\" ");
|
||||
for (String column : toPrint.getLabels()) {
|
||||
sb.append(column.toLowerCase() + "=\"" + toPrint.getBiowareEntry(column, i) + "\" ");
|
||||
}
|
||||
|
||||
if (!getTLK(Integer.parseInt(toPrint.getBiowareEntry(nameColumn, i))).equals(""))
|
||||
sb.append(">" + getTLK(Integer.parseInt(toPrint.getBiowareEntry(nameColumn, i))) + "</item>");
|
||||
else
|
||||
sb.append("/>");
|
||||
|
||||
ps.println(sb);
|
||||
}
|
||||
}
|
||||
|
||||
// Print closing tag
|
||||
ps.println("</LetoList>");
|
||||
|
||||
ps.flush();
|
||||
ps.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ye olde main methode.
|
||||
*
|
||||
* @param args The parameters
|
||||
* @throws Throwable
|
||||
*/
|
||||
public static void main(String[] args) throws Throwable {
|
||||
if (args.length == 0) readMe();
|
||||
String defaultTLKPath = null;
|
||||
String userTLKPath = null;
|
||||
ArrayList<String> twoDANames = new ArrayList<String>();
|
||||
ArrayList<String> columnNames = new ArrayList<String>();
|
||||
|
||||
for (String param : args) {//[-crmnqs] file... | -
|
||||
// Parameter parseage
|
||||
if (param.startsWith("-")) {
|
||||
if (param.equals("--help")) readMe();
|
||||
else {
|
||||
for (char c : param.substring(1).toCharArray()) {
|
||||
switch (c) {
|
||||
|
||||
default:
|
||||
err_pr.println("Error: Unknown parameter: " + c);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (defaultTLKPath == null)
|
||||
defaultTLKPath = param;
|
||||
else if (userTLKPath == null)
|
||||
userTLKPath = param;
|
||||
else {
|
||||
if (twoDANames.size() == columnNames.size())
|
||||
twoDANames.add(param);
|
||||
else
|
||||
columnNames.add(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultTLKPath == null || userTLKPath == null || twoDANames.size() != columnNames.size()) {
|
||||
System.err.println("Error! Missing parameters");
|
||||
readMe();
|
||||
}
|
||||
|
||||
LetoListsGenerator llg = new LetoListsGenerator(new Data_TLK(defaultTLKPath), new Data_TLK(userTLKPath));
|
||||
Data_2da twoDA;
|
||||
for (int i = 0; i < twoDANames.size(); i++) {
|
||||
twoDA = Data_2da.load2da(twoDANames.get(i));
|
||||
llg.printData2daAsLetoXML(twoDA, columnNames.get(i), new FileOutputStream("nwn-" + twoDA.getName().toLowerCase() + ".xml"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void readMe() {
|
||||
System.out.println("Usage:\n" +
|
||||
" pathToDefaultTLK pathToUserTLK [pathTo2da namecolumn]+\n" +
|
||||
"\n" +
|
||||
" --help prints this text\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"Creates xml files for use with Leto editor based on the given files.\n" +
|
||||
"Requires default.tlk, an user tlk and any numbers of 2da and column\n" +
|
||||
"name pairs. The column name is used for fetching the name of the line\n" +
|
||||
"from TLK.\n"
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,94 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.Main;
|
||||
import prc.autodoc.Data_2da;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A class that lists the unique entries found in the given column of the given 2da file.
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class List2daEntries {
|
||||
|
||||
/**
|
||||
* Ye olde main.
|
||||
*
|
||||
* @param args Program arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
if (args.length == 0) readMe();
|
||||
String filePath = null;
|
||||
ArrayList<String> labels = new ArrayList<String>();
|
||||
boolean quiet = false;
|
||||
|
||||
// parse args
|
||||
for (String param : args) {//[--help] | pathof2da columnlabel+
|
||||
// Parameter parseage
|
||||
if (param.startsWith("-")) {
|
||||
if (param.equals("--help")) readMe();
|
||||
else {
|
||||
for (char c : param.substring(1).toCharArray()) {
|
||||
switch (c) {
|
||||
case 'q':
|
||||
quiet = true;
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown parameter: " + c);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// It's a pathname
|
||||
if (filePath == null)
|
||||
filePath = param;
|
||||
else
|
||||
labels.add(param);
|
||||
}
|
||||
}
|
||||
|
||||
if (quiet) {
|
||||
Main.verbose = false;
|
||||
Main.spinner.disable();
|
||||
}
|
||||
|
||||
// Load the 2da
|
||||
Data_2da file = Data_2da.load2da(filePath);
|
||||
|
||||
// Loop over the columns
|
||||
for (String label : labels) {
|
||||
Set<String> entries = new HashSet<String>();
|
||||
String value;
|
||||
|
||||
for (int i = 0; i < file.getEntryCount(); i++) {
|
||||
value = file.getEntry(label, i);
|
||||
|
||||
entries.add(value);
|
||||
}
|
||||
|
||||
StringBuffer toPrint = new StringBuffer(quiet ? "" : (file.getName() + ": entries on column " + label + "\n"));
|
||||
for (String entry : entries) {
|
||||
toPrint.append(entry + "\n");
|
||||
}
|
||||
|
||||
System.out.println(toPrint.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void readMe() {
|
||||
System.out.println("Usage:\n" +
|
||||
" [--help] | [-q] pathof2da columnlabel+\n" +
|
||||
"\n" +
|
||||
" pathof2da path of the 2da to check\n" +
|
||||
" columnlabel label of a column to list entries of\n" +
|
||||
"\n" +
|
||||
" -q silent mode. Only prints the results" +
|
||||
" --help prints this text\n"
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,110 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.Data_2da;
|
||||
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* A class that parses spells.2da and lists used subradial feat ID ranges.
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class ListSubradials {
|
||||
|
||||
/**
|
||||
* Main method
|
||||
*
|
||||
* @param args The program arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
if (args.length == 0) readMe();
|
||||
String pathtospells2da = null;
|
||||
|
||||
// parse args
|
||||
for (String param : args) {//[--help] | pathtospells2da
|
||||
// Parameter parseage
|
||||
if (param.startsWith("-")) {
|
||||
if (param.equals("--help")) readMe();
|
||||
else {
|
||||
for (char c : param.substring(1).toCharArray()) {
|
||||
switch (c) {
|
||||
default:
|
||||
System.out.println("Unknown parameter: " + c);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// It's a pathname
|
||||
if (pathtospells2da == null)
|
||||
pathtospells2da = param;
|
||||
}
|
||||
}
|
||||
|
||||
// Load the 2da to memory
|
||||
Data_2da feats = Data_2da.load2da(pathtospells2da);
|
||||
TreeSet<Integer> subrads = new TreeSet<Integer>();
|
||||
String entry;
|
||||
int subnum;
|
||||
// Parse through the 2da, looking for FeatID references that contain a subradial ID
|
||||
for (int i = 0; i < feats.getEntryCount(); i++) {
|
||||
entry = feats.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;
|
||||
|
||||
subrads.add(subnum);
|
||||
}
|
||||
|
||||
// Print the results
|
||||
System.out.println("Subradial IDs used:");
|
||||
if (subrads.isEmpty())
|
||||
System.out.println("None");
|
||||
else {
|
||||
Integer prev = null;
|
||||
for (Integer subrad : subrads) {
|
||||
// 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() {
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
System.out.println("Usage:\n" +
|
||||
" [--help] | pathtospells2da\n" +
|
||||
"\n" +
|
||||
" pathtospells2da path of the spells.2da to check\n" +
|
||||
"\n" +
|
||||
" --help prints this text\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"Lists used subradial ID ranges in the FeatID column of the given spells.2da\n"
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,188 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.util.Random;
|
||||
|
||||
public final class NPCEvolve {
|
||||
private NPCEvolve() {
|
||||
}
|
||||
|
||||
private static final int countAreas = 5;
|
||||
private static final int countClasses = 11;
|
||||
private static final int countPackages = 10;
|
||||
public static Random rng = new Random();
|
||||
|
||||
/**
|
||||
* The main method, as usual.
|
||||
*
|
||||
* @param args do I really need to explain this?
|
||||
* @throws Exception this is a simple tool, just let all failures blow up
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length < 3 || args[0].equals("--help") || args[0].equals("-?"))
|
||||
readMe();
|
||||
|
||||
String logFilePath = args[0];
|
||||
String packageFilePath = args[1];
|
||||
String outputFilePath = args[2];
|
||||
|
||||
//this is the layout of the data string
|
||||
//## id class0pack1 class0pack2 ... class10pack9 class10pack10 ##
|
||||
//get the file
|
||||
File logFile = new File(logFilePath);
|
||||
BufferedReader reader = new BufferedReader(new FileReader(logFile));
|
||||
//parse it
|
||||
String line = reader.readLine();
|
||||
int[][][] dataset = new int[countAreas][countClasses][countPackages];
|
||||
int classID = 0;
|
||||
int packageID = 0;
|
||||
int areaID = 0;
|
||||
int score = 0;
|
||||
int countArea = 0;
|
||||
while (line != null) {
|
||||
if (line.matches("## ([0-9]*) [0-9 ]* ##")) {
|
||||
areaID = new Integer(line.substring(4, 6));
|
||||
//remove the +1 offset
|
||||
areaID--;
|
||||
//store highest area value
|
||||
if (areaID > countArea)
|
||||
countArea = areaID;
|
||||
classID = 0;
|
||||
packageID = 0;
|
||||
line = line.substring(7, line.length() - 3);
|
||||
String[] splitline = line.split(" ");
|
||||
for (int i = 0; i < splitline.length; i++) {
|
||||
score = new Integer(splitline[i]);
|
||||
dataset[areaID][classID][packageID] = new Integer(splitline[i]);
|
||||
//System.out.println("dataset["+areaID+"]["+classID+"]["+packageID+"] = "+dataset[areaID][classID][packageID]);
|
||||
//move to next slot
|
||||
packageID++;
|
||||
if (packageID >= countPackages) {
|
||||
packageID -= countPackages;
|
||||
classID++;
|
||||
if (classID >= countClasses)
|
||||
classID -= countClasses;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
line = reader.readLine();
|
||||
}
|
||||
//At this point, we have a big dataset with the most recent
|
||||
//scores for each area for each class/package combination
|
||||
//First step is to consolidate this to an average
|
||||
int[][] data = new int[countClasses][countPackages];
|
||||
for (classID = 0; classID < countClasses; classID++) {
|
||||
for (packageID = 0; packageID < countPackages; packageID++) {
|
||||
//reset score to zero
|
||||
score = 0;
|
||||
for (areaID = 0; areaID < countArea; areaID++) {
|
||||
score += dataset[areaID][classID][packageID];
|
||||
}
|
||||
data[classID][packageID] = score / countArea;
|
||||
System.out.println("data[" + classID + "][" + packageID + "] = " + data[classID][packageID]);
|
||||
}
|
||||
}
|
||||
|
||||
//now we know what each packageset scored, go through each class and cross the best 2 to
|
||||
//make the next generation
|
||||
for (classID = 0; classID < countClasses; classID++) {
|
||||
int packageMother = 0;
|
||||
int packageFather = 0;
|
||||
int scoreMother = 0;
|
||||
int scoreFather = 0;
|
||||
for (packageID = 0; packageID < countPackages; packageID++) {
|
||||
score = data[classID][packageID];
|
||||
if (score > scoreMother) {
|
||||
scoreFather = scoreMother;
|
||||
scoreMother = score;
|
||||
packageFather = packageMother;
|
||||
packageMother = packageID;
|
||||
} else if (score > scoreFather) {
|
||||
scoreFather = score;
|
||||
packageFather = packageID;
|
||||
}
|
||||
}
|
||||
//now we have a mother and a father packageset
|
||||
//remember, these are sets of packages, not the actual packages themselves
|
||||
//load the 2das
|
||||
String filename = "";
|
||||
filename = "evopset_" + classID + "_";
|
||||
//if(packageMother<10)
|
||||
// filename += "0";
|
||||
filename += "" + packageMother;
|
||||
Data_2da motherpackset2da = Data_2da.load2da(packageFilePath + File.separator + filename + ".2da");
|
||||
filename = "evopset_" + classID + "_";
|
||||
//if(packageFather<10)
|
||||
// filename += "0";
|
||||
filename += "" + packageFather;
|
||||
Data_2da fatherpackset2da = Data_2da.load2da(packageFilePath + File.separator + filename + ".2da");
|
||||
//create the output 2das
|
||||
for (int i = 0; i < countPackages; i++) {
|
||||
filename = "evopset_" + classID + "_";
|
||||
//if(i<10)
|
||||
// filename += "0";
|
||||
filename += i;
|
||||
Data_2da offspringpackset2da = new Data_2da(filename);
|
||||
offspringpackset2da.addColumn("PackOffset");
|
||||
int parentToUse = 1;
|
||||
for (int row = 0; row < 40; row++) {
|
||||
offspringpackset2da.appendRow();
|
||||
//1 in 10 chance to flip between parents
|
||||
if (rng.nextInt(10) == 0) {
|
||||
if (parentToUse == 1)
|
||||
parentToUse = 2;
|
||||
else if (parentToUse == 2)
|
||||
parentToUse = 1;
|
||||
}
|
||||
if (parentToUse == 1) {
|
||||
//copy from mother
|
||||
String value = motherpackset2da.getEntry("PackOffset", row);
|
||||
//mutation chance
|
||||
if (rng.nextInt(10) == 0) {
|
||||
value = "" + (rng.nextInt(10) + 1);
|
||||
}
|
||||
offspringpackset2da.setEntry("PackOffset", row, value);
|
||||
} else if (parentToUse == 2) {
|
||||
//copy from father
|
||||
String value = fatherpackset2da.getEntry("PackOffset", row);
|
||||
//mutation chance
|
||||
if (rng.nextInt(10) == 0) {
|
||||
value = "" + (rng.nextInt(10) + 1);
|
||||
}
|
||||
offspringpackset2da.setEntry("PackOffset", row, value);
|
||||
}
|
||||
}
|
||||
//now write it to the disk
|
||||
offspringpackset2da.save2da(outputFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
//pastebin for later ;)
|
||||
//first thing is load the overall packages.2da file
|
||||
//Data_2da packages2da = Data_2da.load2da(packageFilePath+File.separator+"packages.2da");
|
||||
/*
|
||||
//get the real package IDs
|
||||
packageMother += (countPackages*classID);
|
||||
packageFather += (countPackages*classID);
|
||||
//EvoPSP
|
||||
//EvoPFTBard01
|
||||
//EvoPSP*/
|
||||
|
||||
private static void readMe() {
|
||||
System.out.println("Usage:\n" +
|
||||
"\tjava npcevol logfile packages\n" +
|
||||
"\n" +
|
||||
"This application is designed to take a logfile \n" +
|
||||
"and parse it to extract relevant data.\n" +
|
||||
"Then it will take some package 2da files\n" +
|
||||
"and mutate them appropriately"
|
||||
);
|
||||
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user