Load Effects.cfg, ModTypes.cfg and CompoundCurves.cfg at world boot
CompoundCurveParser keeps every curve segment (the CompoundCurveType enum holds one value per curve). ModTypeParser keeps each mod type's Behavior, which decides the argument layout of a MODS line. EffectParser loads Effects.cfg into EffectTemplate._effects: header, the four flag keys (case-insensitive, as in the client), SOURCE lines, every MODS line in order, and CONDITION lines. Mod layouts follow the client's ArcMod*_Parse functions; curve names in effects and power actions must exist in CompoundCurves.cfg. Boot order: curves, mod types, power actions, effects. No consumers change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6c820940d3
commit
623f7c4ae6
9 files changed
+584
-3
No files matched your search
@@ -0,0 +1,31 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.objects.wpak;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
// One row of CompoundCurves.cfg: <name> then segments of <DownperRange> <SimpleCurveName> <params>.
|
||||
// Most curves are one SlopedLine segment; DefaultCurveUp/Down have two, which the
|
||||
// CompoundCurveType enum (one value per curve) can't hold.
|
||||
|
||||
public class CompoundCurveTemplate {
|
||||
|
||||
public static HashMap<String, CompoundCurveTemplate> _curves = new HashMap<>();
|
||||
|
||||
public String name;
|
||||
public final ArrayList<Segment> segments = new ArrayList<>();
|
||||
|
||||
public static class Segment {
|
||||
|
||||
public int down_per_range;
|
||||
public String simple_curve;
|
||||
public float[] params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.objects.wpak;
|
||||
|
||||
import engine.mbEnums;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
// One EFFECTBEGIN block of Effects.cfg (client ArcEffect_ParseBlock 0x555540).
|
||||
// Header: <effect_id> <effect_name> <icon>. Keys are flags; SOURCE, MODS and
|
||||
// CONDITION are nested blocks, kept in file order.
|
||||
//
|
||||
// Read only once loaded.
|
||||
|
||||
public class EffectTemplate {
|
||||
|
||||
public static HashMap<String, EffectTemplate> _effects = new HashMap<>();
|
||||
|
||||
public String effect_id;
|
||||
public String effect_name;
|
||||
public int icon;
|
||||
|
||||
public boolean isitemeffect;
|
||||
public boolean dontsave;
|
||||
public boolean ignorenomod;
|
||||
public boolean isspireeffect;
|
||||
|
||||
public final ArrayList<String> sources = new ArrayList<>();
|
||||
public final ArrayList<ModEntry> mods = new ArrayList<>();
|
||||
public final ArrayList<ConditionEntry> conditions = new ArrayList<>();
|
||||
|
||||
// One MODS line. Which fields are set depends on the mod type's behavior in ModTypes.cfg;
|
||||
// the layouts are from the client's ArcMod*_Parse functions. args keeps the line as written.
|
||||
|
||||
public static class ModEntry {
|
||||
|
||||
public mbEnums.ModType mod_type;
|
||||
public String behavior;
|
||||
public final ArrayList<String> args = new ArrayList<>();
|
||||
|
||||
public float min_mod;
|
||||
public float max_mod;
|
||||
|
||||
// Standard and FPSubType*: the client reads this with String::ToInt, so 16.8 acts as 16 (0x55A6C0)
|
||||
public float percent_mod;
|
||||
public String curve;
|
||||
|
||||
// The behavior's subtype: attribute, skill, damage type, source type, power type, mod type or monster type
|
||||
public String type;
|
||||
|
||||
// SubTypeSourceType/SubTypePowerType display text, or the two ItemName strings
|
||||
public String string1;
|
||||
public String string2;
|
||||
|
||||
public String proc_power_id;
|
||||
public int map_key;
|
||||
public final ArrayList<Integer> map_values = new ArrayList<>();
|
||||
}
|
||||
|
||||
// One CONDITION line: <condition> <amount> [curve] [damage type ...] (0x588320)
|
||||
|
||||
public static class ConditionEntry {
|
||||
|
||||
public mbEnums.PowerFailCondition condition;
|
||||
public float amount;
|
||||
public String curve;
|
||||
public final ArrayList<mbEnums.DamageType> damage_types = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.objects.wpak;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
// One row of ModTypes.cfg: <Type> <Behavior> <DisplayCategory> <DisplayString>.
|
||||
// Behavior names the client ArcMod class that parses the mod's arguments in Effects.cfg.
|
||||
// Types are kept as strings: the cfg has types the ModType enum doesn't (AttrReq, BulkFactor, ...).
|
||||
|
||||
public class ModTypeTemplate {
|
||||
|
||||
public static HashMap<String, ModTypeTemplate> _modTypes = new HashMap<>();
|
||||
|
||||
public String type;
|
||||
public String behavior;
|
||||
public String display_category;
|
||||
public String display_string;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.wpak;
|
||||
|
||||
import engine.parsers.objects.wpak.CompoundCurveTemplate;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
// Loads CompoundCurves.cfg.
|
||||
|
||||
public class CompoundCurveParser {
|
||||
|
||||
private static final String fileName = "CompoundCurves.cfg";
|
||||
|
||||
// Segments run back to back on one line, so the param count per simple curve
|
||||
// is what tells where the next segment starts.
|
||||
private static final HashMap<String, Integer> paramCounts = new HashMap<>();
|
||||
|
||||
static {
|
||||
paramCounts.put("FlatLine", 0);
|
||||
paramCounts.put("SlopedLine", 1);
|
||||
paramCounts.put("SlopedInitValLine", 1);
|
||||
}
|
||||
|
||||
public static HashMap<String, CompoundCurveTemplate> parseCompoundCurvesFile() {
|
||||
|
||||
HashMap<String, CompoundCurveTemplate> curves = new HashMap<>();
|
||||
ArrayList<WpakLine> lines;
|
||||
CompoundCurveTemplate curve;
|
||||
int failedCount = 0;
|
||||
|
||||
try {
|
||||
lines = WpakFileReader.readLines(fileName);
|
||||
} catch (Exception e) {
|
||||
Logger.error(fileName + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
for (WpakLine line : lines) {
|
||||
try {
|
||||
curve = parseCurveLine(line);
|
||||
|
||||
if (curves.containsKey(curve.name))
|
||||
throw line.error("duplicate curve " + curve.name);
|
||||
|
||||
curves.put(curve.name, curve);
|
||||
} catch (WpakFormatException e) {
|
||||
Logger.error(e.getMessage());
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info("Loaded " + curves.size() + " of " + lines.size() + " compound curves");
|
||||
|
||||
if (failedCount > 0)
|
||||
return null;
|
||||
|
||||
return curves;
|
||||
}
|
||||
|
||||
private static CompoundCurveTemplate parseCurveLine(WpakLine line) {
|
||||
|
||||
CompoundCurveTemplate curve = new CompoundCurveTemplate();
|
||||
CompoundCurveTemplate.Segment segment;
|
||||
Integer paramCount;
|
||||
int index = 1;
|
||||
|
||||
curve.name = line.token(0);
|
||||
|
||||
while (line.has(index)) {
|
||||
segment = new CompoundCurveTemplate.Segment();
|
||||
segment.down_per_range = line.intToken(index);
|
||||
segment.simple_curve = line.token(index + 1);
|
||||
paramCount = paramCounts.get(segment.simple_curve);
|
||||
|
||||
if (paramCount == null)
|
||||
throw line.error("unknown simple curve " + segment.simple_curve);
|
||||
|
||||
segment.params = new float[paramCount];
|
||||
|
||||
for (int i = 0; i < paramCount; i++)
|
||||
segment.params[i] = line.floatToken(index + 2 + i);
|
||||
|
||||
curve.segments.add(segment);
|
||||
index += 2 + paramCount;
|
||||
}
|
||||
|
||||
if (curve.segments.isEmpty())
|
||||
throw line.error("curve " + curve.name + " has no segments");
|
||||
|
||||
return curve;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.wpak;
|
||||
|
||||
import engine.mbEnums;
|
||||
import engine.parsers.objects.wpak.EffectTemplate;
|
||||
import engine.parsers.objects.wpak.ModTypeTemplate;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
// Loads Effects.cfg. ModTypes.cfg and CompoundCurves.cfg must be loaded first:
|
||||
// a mod's argument layout comes from its behavior, and curve names are checked.
|
||||
|
||||
public class EffectParser {
|
||||
|
||||
private static final String fileName = "Effects.cfg";
|
||||
|
||||
public static HashMap<String, EffectTemplate> parseEffectsFile() {
|
||||
|
||||
HashMap<String, EffectTemplate> effects = new HashMap<>();
|
||||
WpakBlock root;
|
||||
EffectTemplate effect;
|
||||
int blockCount = 0;
|
||||
int failedCount = 0;
|
||||
|
||||
try {
|
||||
root = WpakFileReader.readBlocks(fileName);
|
||||
} catch (Exception e) {
|
||||
Logger.error(fileName + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
for (WpakLine line : root.lines()) {
|
||||
Logger.error(line.location() + ": line outside EFFECTBEGIN/END");
|
||||
failedCount++;
|
||||
}
|
||||
|
||||
for (WpakBlock block : root.blocks()) {
|
||||
try {
|
||||
if (!block.name.equals("EFFECT"))
|
||||
throw block.beginLine.error("unexpected " + block.name + "BEGIN");
|
||||
|
||||
blockCount++;
|
||||
effect = parseEffectBlock(block);
|
||||
|
||||
if (effects.containsKey(effect.effect_id))
|
||||
Logger.warn(block.location() + ": duplicate effect " + effect.effect_id + "; the later entry wins");
|
||||
|
||||
effects.put(effect.effect_id, effect);
|
||||
} catch (WpakFormatException e) {
|
||||
Logger.error(e.getMessage());
|
||||
failedCount++;
|
||||
} catch (Exception e) {
|
||||
Logger.error(block.location() + ": " + e);
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info("Loaded " + effects.size() + " of " + blockCount + " effects");
|
||||
|
||||
if (failedCount > 0)
|
||||
return null;
|
||||
|
||||
return effects;
|
||||
}
|
||||
|
||||
private static EffectTemplate parseEffectBlock(WpakBlock block) {
|
||||
|
||||
EffectTemplate effect = new EffectTemplate();
|
||||
ArrayList<WpakLine> lines = block.lines();
|
||||
WpakLine header;
|
||||
|
||||
if (lines.isEmpty())
|
||||
throw block.beginLine.error("effect has no header line");
|
||||
|
||||
header = lines.get(0);
|
||||
effect.effect_id = header.token(0);
|
||||
effect.effect_name = header.token(1);
|
||||
effect.icon = header.optionalIntToken(2);
|
||||
|
||||
for (int i = 1; i < lines.size(); i++)
|
||||
parseKey(effect, lines.get(i));
|
||||
|
||||
for (WpakBlock child : block.blocks()) {
|
||||
switch (child.name) {
|
||||
case "SOURCE":
|
||||
for (WpakLine line : child.lines())
|
||||
effect.sources.add(line.token(0));
|
||||
break;
|
||||
case "MODS":
|
||||
for (WpakLine line : child.lines())
|
||||
effect.mods.add(parseMod(line));
|
||||
break;
|
||||
case "CONDITION":
|
||||
for (WpakLine line : child.lines())
|
||||
effect.conditions.add(parseCondition(line));
|
||||
break;
|
||||
default:
|
||||
throw child.beginLine.error("unexpected " + child.name + "BEGIN in an effect");
|
||||
}
|
||||
|
||||
if (!child.blocks().isEmpty())
|
||||
throw child.blocks().get(0).beginLine.error("nested block in " + child.name);
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
// The client compares these case-insensitively (cfg has IsItemEffect, client ISITEMEFFECT)
|
||||
|
||||
private static void parseKey(EffectTemplate effect, WpakLine line) {
|
||||
|
||||
switch (line.token(0).toUpperCase()) {
|
||||
case "ISITEMEFFECT":
|
||||
effect.isitemeffect = true;
|
||||
break;
|
||||
case "DONTSAVE":
|
||||
effect.dontsave = true;
|
||||
break;
|
||||
case "IGNORENOMOD":
|
||||
effect.ignorenomod = true;
|
||||
break;
|
||||
case "ISSPIREEFFECT":
|
||||
effect.isspireeffect = true;
|
||||
break;
|
||||
default:
|
||||
throw line.error("unknown effect key " + line.token(0));
|
||||
}
|
||||
}
|
||||
|
||||
private static EffectTemplate.ModEntry parseMod(WpakLine line) {
|
||||
|
||||
EffectTemplate.ModEntry mod = new EffectTemplate.ModEntry();
|
||||
ModTypeTemplate modType = ModTypeTemplate._modTypes.get(line.token(0));
|
||||
|
||||
if (modType == null)
|
||||
throw line.error("mod type " + line.token(0) + " is not in ModTypes.cfg");
|
||||
|
||||
mod.mod_type = line.enumToken(mbEnums.ModType.class, 0);
|
||||
mod.behavior = modType.behavior;
|
||||
mod.args.addAll(line.tokens.subList(1, line.size()));
|
||||
|
||||
switch (mod.behavior) {
|
||||
case "Flag":
|
||||
break;
|
||||
case "Standard":
|
||||
parseStandard(mod, line);
|
||||
break;
|
||||
case "FPSubTypeAttr":
|
||||
case "FPSubTypeSkill":
|
||||
case "FPSubTypeDmg":
|
||||
case "FPSubTypeMonster":
|
||||
parseStandard(mod, line);
|
||||
mod.type = line.token(4);
|
||||
break;
|
||||
case "DD":
|
||||
mod.min_mod = line.floatToken(1);
|
||||
mod.max_mod = line.floatToken(2);
|
||||
mod.percent_mod = line.floatToken(3);
|
||||
mod.curve = WpakParserUtil.curveToken(line, 5);
|
||||
mod.type = line.token(6);
|
||||
break;
|
||||
case "ProcInfo":
|
||||
mod.min_mod = line.floatToken(1);
|
||||
mod.proc_power_id = line.token(2);
|
||||
mod.percent_mod = line.floatToken(3);
|
||||
break;
|
||||
case "SubTypeSourceType":
|
||||
case "SubTypePowerType":
|
||||
mod.type = line.token(1);
|
||||
mod.string1 = line.has(2) ? String.join(" ", line.tokens.subList(2, line.size())) : null;
|
||||
break;
|
||||
case "SubTypeSkill":
|
||||
case "SubTypeDmg":
|
||||
case "SubTypeMod":
|
||||
case "SubTypePower":
|
||||
mod.type = line.token(1);
|
||||
break;
|
||||
case "MapIntToInts":
|
||||
mod.map_key = line.intToken(1);
|
||||
mod.map_values.addAll(line.intTokensFrom(2));
|
||||
break;
|
||||
case "String":
|
||||
mod.string1 = line.token(1);
|
||||
mod.string2 = line.token(2);
|
||||
break;
|
||||
default:
|
||||
throw line.error("unknown mod behavior " + mod.behavior + " for " + line.token(0));
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
// Tokens after the curve are ignored by the client (some lines end in "Unknown")
|
||||
|
||||
private static void parseStandard(EffectTemplate.ModEntry mod, WpakLine line) {
|
||||
|
||||
mod.min_mod = line.floatToken(1);
|
||||
mod.percent_mod = line.floatToken(2);
|
||||
mod.curve = WpakParserUtil.curveToken(line, 3);
|
||||
}
|
||||
|
||||
private static EffectTemplate.ConditionEntry parseCondition(WpakLine line) {
|
||||
|
||||
EffectTemplate.ConditionEntry condition = new EffectTemplate.ConditionEntry();
|
||||
|
||||
condition.condition = line.enumToken(mbEnums.PowerFailCondition.class, 0);
|
||||
condition.amount = line.floatToken(1);
|
||||
condition.curve = line.has(2) ? WpakParserUtil.curveToken(line, 2) : null;
|
||||
|
||||
for (int i = 3; i < line.size(); i++)
|
||||
condition.damage_types.add(line.enumToken(mbEnums.DamageType.class, i));
|
||||
|
||||
return condition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.wpak;
|
||||
|
||||
import engine.parsers.objects.wpak.ModTypeTemplate;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
// Loads ModTypes.cfg. Must load before Effects.cfg, whose mod arguments depend on the behavior.
|
||||
|
||||
public class ModTypeParser {
|
||||
|
||||
private static final String fileName = "ModTypes.cfg";
|
||||
|
||||
public static HashMap<String, ModTypeTemplate> parseModTypesFile() {
|
||||
|
||||
HashMap<String, ModTypeTemplate> modTypes = new HashMap<>();
|
||||
ArrayList<WpakLine> lines;
|
||||
ModTypeTemplate modType;
|
||||
int failedCount = 0;
|
||||
|
||||
try {
|
||||
lines = WpakFileReader.readLines(fileName);
|
||||
} catch (Exception e) {
|
||||
Logger.error(fileName + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
for (WpakLine line : lines) {
|
||||
try {
|
||||
if (line.size() != 4)
|
||||
throw line.error("expected 4 tokens, found " + line.size());
|
||||
|
||||
modType = new ModTypeTemplate();
|
||||
modType.type = line.token(0);
|
||||
modType.behavior = line.token(1);
|
||||
modType.display_category = line.token(2);
|
||||
modType.display_string = line.token(3);
|
||||
|
||||
if (modTypes.containsKey(modType.type))
|
||||
throw line.error("duplicate mod type " + modType.type);
|
||||
|
||||
modTypes.put(modType.type, modType);
|
||||
} catch (WpakFormatException e) {
|
||||
Logger.error(e.getMessage());
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info("Loaded " + modTypes.size() + " of " + lines.size() + " mod types");
|
||||
|
||||
if (failedCount > 0)
|
||||
return null;
|
||||
|
||||
return modTypes;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
// Loads PowerActions.cfg (client loader PowerActions_LoadCfg 0x578EC0).
|
||||
// CompoundCurves.cfg must be loaded first.
|
||||
|
||||
public class PowerActionParser {
|
||||
|
||||
@@ -162,9 +163,9 @@ public class PowerActionParser {
|
||||
powerAction.transfer_from_type = header.enumToken(mbEnums.CostType.class, 2);
|
||||
powerAction.transfer_to_type = header.enumToken(mbEnums.CostType.class, 3);
|
||||
powerAction.transfer_amount = header.floatToken(4);
|
||||
powerAction.transfer_amount_curve = header.token(5);
|
||||
powerAction.transfer_amount_curve = WpakParserUtil.curveToken(header, 5);
|
||||
powerAction.transfer_efficiency = header.floatToken(6);
|
||||
powerAction.transfer_efficiency_curve = header.token(7);
|
||||
powerAction.transfer_efficiency_curve = WpakParserUtil.curveToken(header, 7);
|
||||
powerAction.isaggressive = header.optionalIntToken(9) != 0;
|
||||
}
|
||||
|
||||
@@ -230,7 +231,7 @@ public class PowerActionParser {
|
||||
break;
|
||||
case "LEVELCAP=":
|
||||
powerAction.levelcap = line.intToken(1);
|
||||
powerAction.levelcap_curve = line.has(2) ? line.token(2) : null;
|
||||
powerAction.levelcap_curve = line.has(2) ? WpakParserUtil.curveToken(line, 2) : null;
|
||||
break;
|
||||
case "CLEARAGGRO=":
|
||||
powerAction.clearaggro = line.optionalBoolToken(1);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.wpak;
|
||||
|
||||
import engine.parsers.objects.wpak.CompoundCurveTemplate;
|
||||
|
||||
// Lookups shared by the wpak parsers that need other cfg files loaded first.
|
||||
|
||||
public class WpakParserUtil {
|
||||
|
||||
// CompoundCurves.cfg must be loaded before any file that names a curve
|
||||
|
||||
public static String curveToken(WpakLine line, int index) {
|
||||
|
||||
String curveName = line.token(index);
|
||||
|
||||
if (!CompoundCurveTemplate._curves.containsKey(curveName))
|
||||
throw line.error("curve " + curveName + " is not in CompoundCurves.cfg");
|
||||
|
||||
return curveName;
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,13 @@ import engine.parsers.cache.RuneParser;
|
||||
import engine.parsers.objects.DeedTemplate;
|
||||
import engine.parsers.objects.ItemTemplate;
|
||||
import engine.parsers.objects.RuneTemplate;
|
||||
import engine.parsers.objects.wpak.CompoundCurveTemplate;
|
||||
import engine.parsers.objects.wpak.EffectTemplate;
|
||||
import engine.parsers.objects.wpak.ModTypeTemplate;
|
||||
import engine.parsers.objects.wpak.PowerActionTemplate;
|
||||
import engine.parsers.wpak.CompoundCurveParser;
|
||||
import engine.parsers.wpak.EffectParser;
|
||||
import engine.parsers.wpak.ModTypeParser;
|
||||
import engine.parsers.wpak.PowerActionParser;
|
||||
import engine.powers.RunePowerEntry;
|
||||
import engine.powers.RuneSkillAdjustEntry;
|
||||
@@ -336,6 +342,22 @@ public class WorldServer {
|
||||
Logger.info("Indexing Cache Templates");
|
||||
CObjectIndex.build();
|
||||
|
||||
Logger.info("Loading Compound Curves");
|
||||
CompoundCurveTemplate._curves = CompoundCurveParser.parseCompoundCurvesFile();
|
||||
|
||||
if (CompoundCurveTemplate._curves == null || CompoundCurveTemplate._curves.isEmpty()) {
|
||||
Logger.error("ABORT! Compound curves failed to load!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Logger.info("Loading Mod Types");
|
||||
ModTypeTemplate._modTypes = ModTypeParser.parseModTypesFile();
|
||||
|
||||
if (ModTypeTemplate._modTypes == null || ModTypeTemplate._modTypes.isEmpty()) {
|
||||
Logger.error("ABORT! Mod types failed to load!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Logger.info("Loading Power Actions");
|
||||
PowerActionTemplate._powerActions = PowerActionParser.parsePowerActionsFile();
|
||||
|
||||
@@ -344,6 +366,14 @@ public class WorldServer {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Logger.info("Loading Effects");
|
||||
EffectTemplate._effects = EffectParser.parseEffectsFile();
|
||||
|
||||
if (EffectTemplate._effects == null || EffectTemplate._effects.isEmpty()) {
|
||||
Logger.error("ABORT! Effects failed to load!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Logger.info("Loading PromotionClasses");
|
||||
PromotionClass.LoadAllPromotions();
|
||||
|
||||
|
||||
Reference in new issue
Block a user