Load Powers.cfg at world boot

PowerParser loads Powers.cfg into PowerTemplate._powers. The 22 header
fields are named after the client loader's error messages (0x56E410);
ACTION= lines keep trains, duration, curve and stack fields; prereqs,
curves, flags, messages and CONDITION blocks are kept. Keys compare
case-insensitively, as in the client. Four keys the client ignores
(APPLYDAMAGESELF=, APPLYEFFECTCASTER=, APPLYEFFECTTARGET= and a
POWEREND= typo) are skipped; any other unknown key fails the load.

Numbers are read like the client's atoi/atof with a warning when a
token isn't clean: PRL-033 init time "2.9.0" -> 2.9 and SGE-001
precision "10.0" -> 10, which matches the DB. Ten EQPREREQ lines end
without a required flag, which the client reads as 0.

Needs the fixed Powers.cfg (SRDX-DB header had "SPELL 15 Unknown"
pasted twice; fixed in MBDATA, findings section 6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MagicBotandClaude Opus 5.5 committed 2026-10-22 11:19:14 -04:00
1 parent 623f7c4ae6
commit bd145b1e55
5 files changed
+497 -3

No files matched your search

+24 -2
View File
@@ -9,14 +9,22 @@
package engine.parsers.wpak;
import engine.parsers.cache.CacheParserUtil;
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// One non-comment line of a wpak cfg file, split into tokens.
// Every accessor that fails names the file and line.
public class WpakLine {
// The client reads numbers like C atoi/atof: the leading number counts, the rest is dropped
// (Powers.cfg has "2.9.0" for a float and "10.0" for an int)
private static final Pattern intPrefix = Pattern.compile("[-+]?\\d+");
private static final Pattern floatPrefix = Pattern.compile("[-+]?(\\d+\\.?\\d*|\\.\\d+)");
public final String fileName;
public final int lineNumber;
public final String text;
@@ -56,23 +64,37 @@ public class WpakLine {
public int intToken(int index) {
String value = token(index);
Matcher prefix;
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw error("token " + index + " '" + value + "' is not an integer");
prefix = intPrefix.matcher(value);
}
if (!prefix.lookingAt())
throw error("token " + index + " '" + value + "' is not an integer");
Logger.warn(location() + ": token " + index + " '" + value + "' read as " + prefix.group() + ", as the client does");
return Integer.parseInt(prefix.group());
}
public float floatToken(int index) {
String value = token(index);
Matcher prefix;
try {
return Float.parseFloat(value);
} catch (NumberFormatException e) {
throw error("token " + index + " '" + value + "' is not a number");
prefix = floatPrefix.matcher(value);
}
if (!prefix.lookingAt())
throw error("token " + index + " '" + value + "' is not a number");
Logger.warn(location() + ": token " + index + " '" + value + "' read as " + prefix.group() + ", as the client does");
return Float.parseFloat(prefix.group());
}
// The client reads a missing trailing number as 0 (String::ToInt on an empty token)