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:
339
nwn/nwnprc/DocGen/trunk/prc/utils/ScrollGen.java
Normal file
339
nwn/nwnprc/DocGen/trunk/prc/utils/ScrollGen.java
Normal file
@@ -0,0 +1,339 @@
|
||||
package prc.utils;
|
||||
|
||||
import prc.autodoc.*;
|
||||
import prc.autodoc.Main.TwoDAStore;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static prc.Main.err_pr;
|
||||
import static prc.Main.verbose;
|
||||
|
||||
/**
|
||||
* Creates scrolls based on iprp_spells.2da and spells.2da.
|
||||
*
|
||||
* @author Ornedan
|
||||
*/
|
||||
public class ScrollGen {
|
||||
|
||||
/**
|
||||
* 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 outPath = null;
|
||||
|
||||
// parse args
|
||||
for (String param : args) {//2dadir outdir | [--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 (outPath == null)
|
||||
outPath = param;
|
||||
else {
|
||||
System.out.println("Unknown parameter: " + param);
|
||||
readMe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load data
|
||||
TwoDAStore twoDA = new TwoDAStore(twoDAPath);
|
||||
|
||||
doScrollGen(twoDA, twoDAPath, outPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual scroll generation. Made public for the purposes of BuildScrollHack.
|
||||
*
|
||||
* @param twoDA A TwoDAStore for loading 2da data from
|
||||
* @param twoDAPath Path where the 2da files are located. For resaving
|
||||
* @param outPath Path to directory to store the xml files in
|
||||
* @throws IOException Just tossed back up
|
||||
*/
|
||||
public static void doScrollGen(TwoDAStore twoDA, String twoDAPath, String outPath) throws IOException {
|
||||
Data_2da spells = twoDA.get("spells"),
|
||||
des_crft_scroll = twoDA.get("des_crft_scroll"),
|
||||
des_crft_spells = twoDA.get("des_crft_spells"),
|
||||
iprp_spells = twoDA.get("iprp_spells");
|
||||
|
||||
|
||||
// For each spells.2da entry, find the iprp_spells.2da entry with lowest CasterLvl value
|
||||
Map<Integer, Tuple<Integer, Integer>> lowestIndex = new HashMap<Integer, Tuple<Integer, Integer>>(); // Map of spells.2da index -> (iprp_spells.2da index, CasterLvl value)
|
||||
int spellID, casterLvl;
|
||||
for (int i = 0; i < iprp_spells.getEntryCount(); i++) {
|
||||
if (!iprp_spells.getEntry("SpellIndex", i).equals("****")) { // Only lines that are connected to spells.2da are scanned
|
||||
spellID = Integer.parseInt(iprp_spells.getEntry("SpellIndex", i));
|
||||
casterLvl = Integer.parseInt(iprp_spells.getEntry("CasterLvl", i));
|
||||
|
||||
if (lowestIndex.get(spellID) == null || lowestIndex.get(spellID).e2 > casterLvl)
|
||||
lowestIndex.put(spellID, new Tuple<Integer, Integer>(i, casterLvl));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// For each scroll to make, find which spellcasting classes should be able to use that scroll
|
||||
// Map of spells.2da index -> (iprp_spells.2da index, list of classes.2da index)
|
||||
Map<Integer, Tuple<Integer, Set<Integer>>> scrolls = new HashMap<Integer, Tuple<Integer, Set<Integer>>>();
|
||||
|
||||
for (int spellsIndex : lowestIndex.keySet()) {
|
||||
int iprpIndex = lowestIndex.get(spellsIndex).e1;
|
||||
Set<Integer> classList = getClassesForSpell(twoDA, spellsIndex).keySet();
|
||||
|
||||
if (classList.size() > 0)
|
||||
scrolls.put(spellsIndex, new Tuple<Integer, Set<Integer>>(iprpIndex, classList));
|
||||
}
|
||||
|
||||
// Do the scrolls
|
||||
for (int spellsIndex : scrolls.keySet()) {
|
||||
String scrollName = "prc_scr_" + scrolls.get(spellsIndex).e1.toString();
|
||||
String scrollXml = doScroll(spells, scrollName, spellsIndex, scrolls.get(spellsIndex).e1, scrolls.get(spellsIndex).e2);
|
||||
|
||||
// Print the scroll
|
||||
printScroll(outPath, scrollName, scrollXml);
|
||||
|
||||
// Update des_crft_scrolls accordingly
|
||||
Set<Integer> classList = scrolls.get(spellsIndex).e2;
|
||||
if (classList.contains(1))
|
||||
setScroll(des_crft_scroll, spells, spellsIndex, "Bard", scrollName);
|
||||
if (classList.contains(9) || classList.contains(10))
|
||||
setScroll(des_crft_scroll, spells, spellsIndex, "Wiz_Sorc", scrollName);
|
||||
if (classList.contains(2))
|
||||
setScroll(des_crft_scroll, spells, spellsIndex, "Cleric", scrollName);
|
||||
if (classList.contains(3))
|
||||
setScroll(des_crft_scroll, spells, spellsIndex, "Druid", scrollName);
|
||||
if (classList.contains(6))
|
||||
setScroll(des_crft_scroll, spells, spellsIndex, "Paladin", scrollName);
|
||||
if (classList.contains(7))
|
||||
setScroll(des_crft_scroll, spells, spellsIndex, "Ranger", scrollName);
|
||||
}
|
||||
|
||||
// Save updated des_crft_scrolls.2da
|
||||
des_crft_scroll.save2da(twoDAPath, true, true);
|
||||
}
|
||||
|
||||
public static Map<Integer, Integer> getClassesForSpell(TwoDAStore twoDA, int spellsIndex)
|
||||
{
|
||||
Data_2da spells = twoDA.get("spells");
|
||||
Map<Integer, Integer> classList = new TreeMap<Integer, Integer>();
|
||||
|
||||
// BAD
|
||||
// Hardcoded classes.2da indexes
|
||||
String bardSpell = spells.getEntry("Bard", spellsIndex);
|
||||
String clericSpell = spells.getEntry("Cleric", spellsIndex);
|
||||
String druidSpell = spells.getEntry("Druid", spellsIndex);
|
||||
String paladinSpell = spells.getEntry("Paladin", spellsIndex);
|
||||
String rangerSpell = spells.getEntry("Ranger", spellsIndex);
|
||||
String wizSpell = spells.getEntry("Wiz_Sorc", spellsIndex);
|
||||
if (!bardSpell.equals("****"))
|
||||
classList.put(1, Integer.parseInt(bardSpell));
|
||||
if (!clericSpell.equals("****"))
|
||||
classList.put(2, Integer.parseInt(clericSpell));
|
||||
if (!druidSpell.equals("****"))
|
||||
classList.put(3, Integer.parseInt(druidSpell));
|
||||
if (!paladinSpell.equals("****"))
|
||||
classList.put(6, Integer.parseInt(paladinSpell));
|
||||
if (!rangerSpell.equals("****"))
|
||||
classList.put(7, Integer.parseInt(rangerSpell));
|
||||
if (!wizSpell.equals("****")) {
|
||||
classList.put(9, Integer.parseInt(wizSpell));
|
||||
classList.put(10, Integer.parseInt(wizSpell));
|
||||
}
|
||||
/// For each spell, find which new spellbooks have that spell
|
||||
// Map of spells.2da index -> (map of classes.2da index -> spell level)
|
||||
Map<Integer, Map<Integer, Integer>> newSpellBooks = getNewSpellbooksClasses(twoDA, spells);
|
||||
|
||||
// New spellbooks
|
||||
Map<Integer, Integer> newSpellBookEntries = newSpellBooks.get(spellsIndex);
|
||||
if (newSpellBookEntries != null)
|
||||
for(Integer classId : newSpellBookEntries.keySet()) {
|
||||
classList.put(classId, newSpellBookEntries.get(classId));
|
||||
}
|
||||
|
||||
return classList;
|
||||
|
||||
}
|
||||
|
||||
private static Map<Integer, Map<Integer, Integer>> newSpellbookCache = null;
|
||||
|
||||
private static Map<Integer, Map<Integer, Integer>> getNewSpellbooksClasses(TwoDAStore twoDA, Data_2da spells) {
|
||||
if (newSpellbookCache != null) return newSpellbookCache;
|
||||
// Map of spells.2da index -> list of classes.2da index
|
||||
HashMap<Integer, Map<Integer, Integer>> toReturn = new HashMap<Integer, Map<Integer, Integer>>();
|
||||
String classAbrev = null;
|
||||
Data_2da classes = twoDA.get("classes"),
|
||||
spellList = null;
|
||||
Integer spellId;
|
||||
|
||||
for (int classId = 0; classId < classes.getEntryCount(); classId++) {
|
||||
if (!classes.getEntry("PlayerClass", classId).equals("1")) continue;
|
||||
|
||||
// Extract the class abbreviation
|
||||
classAbrev = classes.getEntry("FeatsTable", classId).toLowerCase().substring(9);
|
||||
|
||||
// Attempt to load the spellbook 2da
|
||||
try {
|
||||
spellList = twoDA.get("cls_spcr_" + classAbrev);
|
||||
} catch (TwoDAReadException e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < spellList.getEntryCount(); i++) {
|
||||
String spellEntry = spellList.getEntry("SpellID", i);
|
||||
String spellLevelEntry = spellList.getEntry("Level", i);
|
||||
if (!spellEntry.equals("****")) {
|
||||
spellId = Integer.parseInt(spellEntry);
|
||||
int spellLevel = Integer.parseInt(spellLevelEntry);
|
||||
if (toReturn.get(spellId) == null) {
|
||||
toReturn.put(spellId, new TreeMap<Integer, Integer>());
|
||||
}
|
||||
toReturn.get(spellId).put(classId, spellLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
newSpellbookCache = toReturn;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
private static void setScroll(Data_2da des_crft_scroll, Data_2da spells, int spellsIndex, String column, String scrollName) {
|
||||
// Set the main entry
|
||||
des_crft_scroll.setEntry(column, spellsIndex, scrollName);
|
||||
|
||||
// Set each subradial's entry
|
||||
for (int i = 1; i <= 5; i++)
|
||||
if (!spells.getEntry("SubRadSpell" + i, spellsIndex).equals("****")) {
|
||||
des_crft_scroll.setEntry(column, Integer.parseInt(spells.getEntry("SubRadSpell" + i, spellsIndex)), scrollName);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String xmlPrefix =
|
||||
"<gff name=\"~~~Name~~~.uti\" type=\"UTI \" version=\"V3.2\" >" + "\n" +
|
||||
" <struct id=\"-1\" >" + "\n" +
|
||||
" <element name=\"TemplateResRef\" type=\"11\" value=\"~~~Name~~~\" />" + "\n" +
|
||||
" <element name=\"BaseItem\" type=\"5\" value=\"75\" />" + "\n" +
|
||||
" <element name=\"LocalizedName\" type=\"12\" value=\"~~~TLKName~~~\" />" + "\n" +
|
||||
" <element name=\"Description\" type=\"12\" value=\"-1\" />" + "\n" +
|
||||
" <element name=\"DescIdentified\" type=\"12\" value=\"~~~TLKDesc~~~\" />" + "\n" +
|
||||
" <element name=\"Tag\" type=\"10\" value=\"~~~Tag~~~\" />" + "\n" +
|
||||
" <element name=\"Charges\" type=\"0\" value=\"0\" />" + "\n" +
|
||||
" <element name=\"Cost\" type=\"4\" value=\"0\" />" + "\n" +
|
||||
" <element name=\"Stolen\" type=\"0\" value=\"0\" />" + "\n" +
|
||||
" <element name=\"StackSize\" type=\"2\" value=\"1\" />" + "\n" +
|
||||
" <element name=\"Plot\" type=\"0\" value=\"0\" />" + "\n" +
|
||||
" <element name=\"AddCost\" type=\"4\" value=\"0\" />" + "\n" +
|
||||
" <element name=\"Identified\" type=\"0\" value=\"1\" />" + "\n" +
|
||||
" <element name=\"Cursed\" type=\"0\" value=\"0\" />" + "\n" +
|
||||
" <element name=\"ModelPart1\" type=\"0\" value=\"1\" />" + "\n" +
|
||||
" <element name=\"PropertiesList\" type=\"15\" >" + "\n" +
|
||||
" <struct id=\"0\" >" + "\n" +
|
||||
" <element name=\"PropertyName\" type=\"2\" value=\"15\" />" + "\n" +
|
||||
" <element name=\"Subtype\" type=\"2\" value=\"~~~IPIndex~~~\" />" + "\n" +
|
||||
" <element name=\"CostTable\" type=\"0\" value=\"3\" />" + "\n" +
|
||||
" <element name=\"CostValue\" type=\"2\" value=\"1\" />" + "\n" +
|
||||
" <element name=\"Param1\" type=\"0\" value=\"255\" />" + "\n" +
|
||||
" <element name=\"Param1Value\" type=\"0\" value=\"0\" />" + "\n" +
|
||||
" <element name=\"ChanceAppear\" type=\"0\" value=\"100\" />" + "\n" +
|
||||
" </struct>" + "\n";
|
||||
private static final String xmlClass =
|
||||
" <struct id=\"0\" >" + "\n" +
|
||||
" <element name=\"PropertyName\" type=\"2\" value=\"63\" />" + "\n" +
|
||||
" <element name=\"Subtype\" type=\"2\" value=\"~~~Class~~~\" />" + "\n" +
|
||||
" <element name=\"CostTable\" type=\"0\" value=\"0\" />" + "\n" +
|
||||
" <element name=\"CostValue\" type=\"2\" value=\"0\" />" + "\n" +
|
||||
" <element name=\"Param1\" type=\"0\" value=\"255\" />" + "\n" +
|
||||
" <element name=\"Param1Value\" type=\"0\" value=\"0\" />" + "\n" +
|
||||
" <element name=\"ChanceAppear\" type=\"0\" value=\"100\" />" + "\n" +
|
||||
" </struct>" + "\n";
|
||||
private static final String xmlSuffix =
|
||||
" </element>" + "\n" +
|
||||
" <element name=\"PaletteID\" type=\"0\" value=\"26\" />" + "\n" +
|
||||
" <element name=\"Comment\" type=\"10\" value=\"1\" />" + "\n" +
|
||||
" </struct>" + "\n" +
|
||||
"</gff>";
|
||||
|
||||
private static String doScroll(Data_2da spells, String name, int spellsIndex, int iprpIndex, Set<Integer> classes) {
|
||||
// Determine TLK references
|
||||
int tlkName = Integer.parseInt(spells.getEntry("Name", spellsIndex));
|
||||
int tlkDesc = Integer.parseInt(spells.getEntry("SpellDesc", spellsIndex));
|
||||
|
||||
// Build the string
|
||||
String toReturn = xmlPrefix.replaceAll("~~~Name~~~", name)
|
||||
.replaceAll("~~~Tag~~~", name.toUpperCase())
|
||||
.replaceAll("~~~IPIndex~~~", "" + iprpIndex)
|
||||
.replaceAll("~~~TLKName~~~", "" + tlkName)
|
||||
.replaceAll("~~~TLKDesc~~~", "" + tlkDesc);
|
||||
|
||||
for (Integer classIndex : classes)
|
||||
toReturn += xmlClass.replaceAll("~~~Class~~~", classIndex.toString());
|
||||
|
||||
toReturn += xmlSuffix;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
private static void printScroll(String outDir, String scrollName, String scrollXml) {
|
||||
String path = outDir + File.separator + scrollName + ".uti.xml";
|
||||
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(scrollXml);
|
||||
// Clean up
|
||||
writer.flush();
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
err_pr.println("Error: IOException when printing " + path + ":\n" + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 scrollgen 2dadir outdir | [--help]\n" +
|
||||
"\n" +
|
||||
"2dadir Path to a directory containing 2da files\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 creating spell scrolls based on iprp_spells.2da\n" +
|
||||
"and spells.2da. Generates pspeed's modpacker -compatible XML\n" +
|
||||
"Also updates des_crft_scrolls with the new scroll resrefs.\n"
|
||||
);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user