diff --git a/src/engine/parsers/objects/wpak/CurveRamp.java b/src/engine/parsers/objects/wpak/CurveRamp.java new file mode 100644 index 00000000..8d97954c --- /dev/null +++ b/src/engine/parsers/objects/wpak/CurveRamp.java @@ -0,0 +1,83 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2026 +// https://www.magicbane.com + +package engine.parsers.objects.wpak; + +import org.pmw.tinylog.Logger; + +// A CompoundCurve in the server's (ramp, add) form, as stored in the DB ramp/useRampAdd and ramp/useAddFormula columns. +// Mapping checked against every static_power_effectmod and static_power_action row (JSON-Refactor-Plan/scripts/p41.py). + +public class CurveRamp { + + private static final int RAMP_RANGE = 100; + + public final float ramp; + public final boolean useAdd; + + private CurveRamp(float ramp, boolean useAdd) { + this.ramp = ramp; + this.useAdd = useAdd; + } + + // Null when the curve is unknown or has no ramp form (multi-segment, or a range other than 100). + public static CurveRamp fromCurve(String curveName) { + + CompoundCurveTemplate curve = CompoundCurveTemplate._curves.get(curveName); + CompoundCurveTemplate.Segment segment; + + if (curve == null || curve.segments.size() != 1) + return null; + + segment = curve.segments.get(0); + + if (segment.down_per_range != RAMP_RANGE) + return null; + + switch (segment.simple_curve) { + case "FlatLine": + return new CurveRamp(0, true); + case "SlopedLine": + return new CurveRamp(segment.params[0], true); + case "SlopedInitValLine": + return new CurveRamp(segment.params[0], false); + default: + return null; + } + } + + // Boot check against known DB effectmod rows, one per curve kind, then a list of curves with no ramp form. + public static void verifyRampForms() { + + int noRampCount = 0; + + verify("SL0083Up", 0.83f, true); // 1AX-001A MeleeDamageModifier + verify("SL0100Down", -1f, true); // ACM-003A MeleeDamageModifier + verify("DefaultFlat", 0f, true); // 1AX-003A DCV + verify("SIVL0014", 0.014f, false); // ANM-002A Health + verify("SL0050Down", -0.5f, true); // CON-100A Health + + for (CompoundCurveTemplate curve : CompoundCurveTemplate._curves.values()) + if (fromCurve(curve.name) == null) { + Logger.warn("Compound curve " + curve.name + " has no ramp form"); + noRampCount++; + } + + Logger.info("Compound curves with a ramp form: " + (CompoundCurveTemplate._curves.size() - noRampCount) + + " of " + CompoundCurveTemplate._curves.size()); + } + + private static void verify(String curveName, float ramp, boolean useAdd) { + + CurveRamp curveRamp = fromCurve(curveName); + + if (curveRamp == null || Math.abs(curveRamp.ramp - ramp) > 0.0001f || curveRamp.useAdd != useAdd) + Logger.error("Curve ramp check failed for " + curveName + ": expected (" + ramp + ", " + useAdd + ")" + + (curveRamp == null ? " got none" : " got (" + curveRamp.ramp + ", " + curveRamp.useAdd + ")")); + } +} diff --git a/src/engine/server/world/WorldServer.java b/src/engine/server/world/WorldServer.java index 5eeddf99..dee3c224 100644 --- a/src/engine/server/world/WorldServer.java +++ b/src/engine/server/world/WorldServer.java @@ -41,6 +41,7 @@ import engine.parsers.objects.ItemTemplate; import engine.parsers.objects.RuneTemplate; import engine.parsers.objects.wpak.CharCreateRuneList; import engine.parsers.objects.wpak.CompoundCurveTemplate; +import engine.parsers.objects.wpak.CurveRamp; import engine.parsers.objects.wpak.EffectTemplate; import engine.parsers.objects.wpak.ModTypeTemplate; import engine.parsers.objects.wpak.PowActionCostTemplate; @@ -306,6 +307,8 @@ public class WorldServer { exit(1); } + CurveRamp.verifyRampForms(); + Logger.info("Loading Mod Types"); ModTypeTemplate._modTypes = ModTypeParser.parseModTypesFile();