From 7717707518e593109ab4d610a051910568e904b5 Mon Sep 17 00:00:00 2001 From: MagicBot Date: Fri, 9 Jan 2026 13:12:40 -0500 Subject: [PATCH] wpak parser added to project --- src/engine/wpak/EffectsParser.java | 286 +++++++++++++++++++ src/engine/wpak/PowerActionParser.java | 310 +++++++++++++++++++++ src/engine/wpak/PowersParser.java | 321 ++++++++++++++++++++++ src/engine/wpak/data/ActionEntry.java | 24 ++ src/engine/wpak/data/ConditionEntry.java | 21 ++ src/engine/wpak/data/Effect.java | 51 ++++ src/engine/wpak/data/EquipmentPreReq.java | 19 ++ src/engine/wpak/data/ModifierEntry.java | 23 ++ src/engine/wpak/data/Power.java | 96 +++++++ src/engine/wpak/data/PowerAction.java | 68 +++++ src/engine/wpak/data/PowerEntry.java | 17 ++ src/engine/wpak/data/StatTransfer.java | 24 ++ src/engine/wpak/data/TrackEntry.java | 21 ++ 13 files changed, 1281 insertions(+) create mode 100644 src/engine/wpak/EffectsParser.java create mode 100644 src/engine/wpak/PowerActionParser.java create mode 100644 src/engine/wpak/PowersParser.java create mode 100644 src/engine/wpak/data/ActionEntry.java create mode 100644 src/engine/wpak/data/ConditionEntry.java create mode 100644 src/engine/wpak/data/Effect.java create mode 100644 src/engine/wpak/data/EquipmentPreReq.java create mode 100644 src/engine/wpak/data/ModifierEntry.java create mode 100644 src/engine/wpak/data/Power.java create mode 100644 src/engine/wpak/data/PowerAction.java create mode 100644 src/engine/wpak/data/PowerEntry.java create mode 100644 src/engine/wpak/data/StatTransfer.java create mode 100644 src/engine/wpak/data/TrackEntry.java diff --git a/src/engine/wpak/EffectsParser.java b/src/engine/wpak/EffectsParser.java new file mode 100644 index 00000000..e1d0a1fd --- /dev/null +++ b/src/engine/wpak/EffectsParser.java @@ -0,0 +1,286 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com + +package engine.wpak; + +import engine.gameManager.ConfigManager; +import engine.mbEnums; +import engine.wpak.data.ConditionEntry; +import engine.wpak.data.Effect; +import engine.wpak.data.ModifierEntry; +import engine.wpakpowers.WpakPowerManager; +import org.pmw.tinylog.Logger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class EffectsParser { + + public static String effectsPath = ConfigManager.DEFAULT_DATA_DIR + "wpak/Effects.cfg"; + private static final Pattern EFFECT_REGEX = Pattern.compile("(?<=EFFECTBEGIN)(.+?)(?=EFFECTEND)", Pattern.DOTALL); + private static final Pattern SOURCE_REGEX = Pattern.compile("(?<=SOURCEBEGIN)(.+?)(?=SOURCEEND)", Pattern.DOTALL); + private static final Pattern MODS_REGEX = Pattern.compile("(?<=MODSBEGIN)(.+?)(?=MODSEND)", Pattern.DOTALL); + private static final Pattern CONDITIONS_REGEX = Pattern.compile("(?<=CONDITIONBEGIN)(.+?)(?=CONDITIONEND)", Pattern.DOTALL); + private static final Pattern STRSPLIT_REGEX = Pattern.compile("([^\"]\\S*|\"[^\"]*\")\\s*"); // Regex ignores spaces within quotes + + public static void parseWpakFile() { + + // Read .wpak file from disk + + byte[] fileData; + + try { + fileData = Files.readAllBytes(Paths.get(effectsPath)); + } catch (IOException e) { + throw new RuntimeException(e); + } + + String fileContents = new String(fileData); + + // Iterate over effect entries from .wpak data + + Matcher matcher = EFFECT_REGEX.matcher(fileContents); + + while (matcher.find()) { + try { + Effect effect = parseEffectEntry(matcher.group()); + WpakPowerManager._effectsLookup.put(effect.effect_id, effect); + } catch (Exception e) { + Logger.error("EFFECT PARSE FAILED: " + e); + } + } + } + + private static Effect parseEffectEntry(String effectData) { + + Effect effect = new Effect(); + + // Parse fields that lie outside the other tags + + effect.isItemEffect = effectData.contains("IsItemEffect"); + effect.isSpireEffect = effectData.contains("IsSpireEffect"); + effect.ignoreNoMod = effectData.contains("IgnoreNoMod"); + effect.dontSave = effectData.contains("DontSave"); + + // Remove all lines that contain a # and leading/trailing blank lines + + effectData = effectData.replaceAll("(?m)^(\\s*#.*|\\s*)\r?\n?", ""); + effectData = effectData.trim(); + + // Parse effect entry header + + String firstLine; + ArrayList effectHeader = new ArrayList<>(); + + // Some effects exist without sources/mods or conditions + // (ACID "MOB" 0) + + if (effectData.indexOf('\n') > 0) + firstLine = effectData.substring(0, effectData.indexOf('\n')); + else + firstLine = effectData; + + Matcher matcher = STRSPLIT_REGEX.matcher(firstLine); + + while (matcher.find()) + effectHeader.add(matcher.group().trim()); + + effect.effect_id = effectHeader.get(0); + effect.effect_name = effectHeader.get(1); + effect.effect_name = effect.effect_name.replaceAll("\"", ""); + + // Some effect mods have no icon + // (SEEINVIS-SHADE "See Invis") + + if (effectHeader.size() == 3) + effect.icon = Integer.parseInt(effectHeader.get(2)); + else + effect.icon = 0; + + // Parse source entries + + matcher = SOURCE_REGEX.matcher(effectData); + + while (matcher.find()) + effect.sources.add(matcher.group().trim()); + + // Parse modifier entries + + matcher = MODS_REGEX.matcher(effectData); + + // Iterate effect entries from .wpak config data + + while (matcher.find()) { + ModifierEntry modifierEntry = parseModEntry(matcher.group()); + effect.mods.add(modifierEntry); + } + + // Parse Conditions + + matcher = CONDITIONS_REGEX.matcher(effectData); + + while (matcher.find()) { + String[] conditions = matcher.group().trim().split("\n"); + + for (String condition : conditions) { + List parameters = Arrays.asList(condition.trim().split("\\s+")); + Iterator iterator = parameters.iterator(); + + ConditionEntry conditionEntry = new ConditionEntry(); + conditionEntry.condition = iterator.next(); + conditionEntry.arg = Integer.parseInt(iterator.next()); + + if (iterator.hasNext()) + conditionEntry.curveType = mbEnums.CompoundCurveType.valueOf(iterator.next()); + + while (iterator.hasNext()) + conditionEntry.damageTypes.add(mbEnums.DamageType.valueOf(iterator.next().toUpperCase())); + + effect.conditions.add(conditionEntry); + } + } + + return effect; + } + + private static ModifierEntry parseModEntry(String modData) { + + ModifierEntry modifierEntry = new ModifierEntry(); + + String[] modEntries = modData.trim().split("\n"); + + for (String modEntry : modEntries) { + + ArrayList modValues = new ArrayList<>(); + Matcher matcher = STRSPLIT_REGEX.matcher(modEntry.trim()); + + while (matcher.find()) + modValues.add(matcher.group().trim()); + + modifierEntry.type = mbEnums.ModType.valueOf(modValues.get(0).trim()); + + switch (modifierEntry.type) { + case AnimOverride: + modifierEntry.min = Float.parseFloat(modValues.get(1).trim()); + modifierEntry.max = Float.parseFloat(modValues.get(2).trim()); + break; + case Health: + case Mana: + case Stamina: + modifierEntry.min = Float.parseFloat(modValues.get(1).trim()); + modifierEntry.max = Float.parseFloat(modValues.get(2).trim()); + modifierEntry.percentage = Float.parseFloat(modValues.get(3).trim()); + modifierEntry.value = Float.parseFloat(modValues.get(4).trim()); // Always zero + modifierEntry.compoundCurveType = mbEnums.CompoundCurveType.valueOf(modValues.get(5).trim()); + modifierEntry.arg1 = modValues.get(6).trim(); + break; + case Attr: + case Resistance: + case Skill: + case HealthRecoverRate: + case ManaRecoverRate: + case StaminaRecoverRate: + case DamageShield: + case HealthFull: + case ManaFull: + case StaminaFull: + case Slay: + case Fade: + case Durability: + modifierEntry.min = Float.parseFloat(modValues.get(1).trim()); + modifierEntry.max = Float.parseFloat(modValues.get(2).trim()); + modifierEntry.compoundCurveType = mbEnums.CompoundCurveType.valueOf(modValues.get(3).trim()); + + if (modValues.size() > 4) + modifierEntry.arg1 = modValues.get(4).trim(); // Some HeathFull entries do not have an argument + break; + case MeleeDamageModifier: + case OCV: + case DCV: + case AttackDelay: + case AdjustAboveDmgCap: + case DamageCap: + case ArmorPiercing: + case Speed: + case PowerDamageModifier: + case DR: + case PassiveDefense: + case MaxDamage: + case Value: + case WeaponSpeed: + case MinDamage: + case PowerCost: + case Block: + case Parry: + case Dodge: + case WeaponRange: + case ScanRange: + case ScaleHeight: + case ScaleWidth: + modifierEntry.min = Float.parseFloat(modValues.get(1).trim()); + modifierEntry.max = Float.parseFloat(modValues.get(2).trim()); + modifierEntry.compoundCurveType = mbEnums.CompoundCurveType.valueOf(modValues.get(3).trim()); + break; + case ItemName: + case BlockedPowerType: + case ImmuneTo: + case BlackMantle: + modifierEntry.arg1 = modValues.get(1).trim(); + + // Some BlockedPowerType entries have only one argument + + if (modValues.size() > 2) + modifierEntry.arg2 = modValues.get(2).trim(); + break; + case NoMod: + case ConstrainedAmbidexterity: + case ProtectionFrom: + case ExclusiveDamageCap: + case IgnoreDamageCap: + modifierEntry.arg1 = modValues.get(1).trim(); + break; + case WeaponProc: + modifierEntry.min = Float.parseFloat(modValues.get(1).trim()); + modifierEntry.arg1 = modValues.get(2).trim(); + modifierEntry.max = Float.parseFloat(modValues.get(3).trim()); + break; + case BladeTrails: // These tags have no parms or are not parsed + case ImmuneToAttack: + case ImmuneToPowers: + case Ambidexterity: + case Silenced: + case IgnorePassiveDefense: + case Stunned: + case PowerCostHealth: + case Charmed: + case Fly: + case CannotMove: + case CannotTrack: + case CannotAttack: + case CannotCast: + case SpireBlock: + case Invisible: + case SeeInvisible: + break; + default: + Logger.error("Unhandled type: " + modifierEntry.type); + break; + } + } + + return modifierEntry; + } + +} diff --git a/src/engine/wpak/PowerActionParser.java b/src/engine/wpak/PowerActionParser.java new file mode 100644 index 00000000..d2017efb --- /dev/null +++ b/src/engine/wpak/PowerActionParser.java @@ -0,0 +1,310 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com + +package engine.wpak; + +import engine.gameManager.ConfigManager; +import engine.mbEnums; +import engine.util.Hasher; +import engine.wpak.data.Effect; +import engine.wpak.data.PowerAction; +import engine.wpak.data.StatTransfer; +import engine.wpak.data.TrackEntry; +import engine.wpakpowers.WpakPowerManager; +import org.pmw.tinylog.Logger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PowerActionParser { + private static final Pattern STRSPLIT_REGEX = Pattern.compile("([^\"]\\S*|\"[^\"]*\")\\s*"); + private static final Pattern POWER_ACTION_REGEX = Pattern.compile("(?<=POWERACTIONBEGIN)(.+?)(?=POWERACTIONEND)", Pattern.DOTALL); + private static final String powerActionPath = ConfigManager.DEFAULT_DATA_DIR + "wpak/PowerActions.cfg"; + + public static void parseWpakFile() { + + // Read .wpak file from disk + + byte[] fileData; + + try { + fileData = Files.readAllBytes(Paths.get(powerActionPath)); + } catch (IOException e) { + throw new RuntimeException(e); + } + + String fileContents = new String(fileData); + + // Iterate over power entries from .wpak data + + Matcher matcher = POWER_ACTION_REGEX.matcher(fileContents); + + while (matcher.find()) { + + PowerAction powerAction = parsePowerActionEntry(matcher.group().trim()); + WpakPowerManager._powerActionLookup.put(Hasher.SBStringHash(powerAction.action_id), powerAction); + } + } + + private static PowerAction parsePowerActionEntry(String powerActionData) { + + PowerAction powerAction = new PowerAction(); + Effect effect; + StatTransfer statTransfer; + TrackEntry trackEntry; + + // Remove all lines that contain a # and leading/trailing blank lines + + powerActionData = powerActionData.replaceAll("(?m)^(\\s*#.*|\\s*)\r?\n?", "").trim(); + + List lineData = Arrays.asList(powerActionData.split("\n")); + + // Parse effect entry header + + Iterator entryIterator = lineData.iterator(); + String headerLine = entryIterator.next(); + List headerData = new ArrayList<>(); + + Matcher matcher = STRSPLIT_REGEX.matcher(headerLine.trim()); + + while (matcher.find()) + headerData.add(matcher.group().trim()); + + Iterator headerIterator = headerData.iterator(); + powerAction.action_id = headerIterator.next(); + powerAction.action_type = mbEnums.PowerActionType.valueOf(headerIterator.next()); + + switch (powerAction.action_type) { + case RemoveEffect: + effect = new Effect(); + effect.effect_id = headerIterator.next(); + powerAction.effects.add(effect); + break; + case CreateMob: + powerAction.petRace = Integer.parseInt(headerIterator.next()); + powerAction.petLevel = Integer.parseInt(headerIterator.next()); + break; + case DamageOverTime: + effect = new Effect(); + effect.effect_id = headerIterator.next(); + effect.cycleDuration = Integer.parseInt(headerIterator.next()); + effect.cycleDelay = Integer.parseInt(headerIterator.next()); + powerAction.effects.add(effect); + break; + case ApplyEffects: + int level = Integer.parseInt(headerIterator.next()); + + while (headerIterator.hasNext()) { + effect = new Effect(); + effect.level = level; + effect.effect_id = headerIterator.next(); + powerAction.effects.add(effect); + } + break; + case Transform: + case Invis: + case ApplyEffect: + case DeferredPower: + case DirectDamage: + case SpireDisable: + while (headerIterator.hasNext()) { + effect = new Effect(); + effect.effect_id = headerIterator.next(); + + // Some applyEffect entries are naked withot a level + + if (headerData.size() > 3) + effect.level = Integer.parseInt(headerIterator.next()); + + powerAction.effects.add(effect); + } + break; + case TransferStat: + statTransfer = new StatTransfer(); + statTransfer.fromStat = mbEnums.CostType.valueOf(headerIterator.next()); + statTransfer.toStat = mbEnums.CostType.valueOf(headerIterator.next()); + statTransfer.ramp = Float.parseFloat(headerIterator.next()); + statTransfer.rampCurve = mbEnums.CompoundCurveType.valueOf(headerIterator.next()); + statTransfer.efficiency = Float.parseFloat(headerIterator.next()); + statTransfer.efficiencyCurve = mbEnums.CompoundCurveType.valueOf(headerIterator.next()); + statTransfer.fromStatBool = Boolean.parseBoolean(headerIterator.next()); + statTransfer.isDrain = Boolean.parseBoolean(headerIterator.next()); + powerAction.statTransfer = statTransfer; + break; + case TransferStatOT: + statTransfer = new StatTransfer(); + statTransfer.fromStat = mbEnums.CostType.valueOf(headerIterator.next()); + statTransfer.toStat = mbEnums.CostType.valueOf(headerIterator.next()); + statTransfer.ramp = Float.parseFloat(headerIterator.next()); + statTransfer.rampCurve = mbEnums.CompoundCurveType.valueOf(headerIterator.next()); + statTransfer.efficiency = Float.parseFloat(headerIterator.next()); + statTransfer.efficiencyCurve = mbEnums.CompoundCurveType.valueOf(headerIterator.next()); + statTransfer.fromStatBool = Boolean.parseBoolean(headerIterator.next()); + statTransfer.isDrain = Boolean.parseBoolean(headerIterator.next()); + statTransfer.transfer_action = headerIterator.next(); + statTransfer.transfer_ticks = Integer.parseInt(headerIterator.next()); + powerAction.statTransfer = statTransfer; + break; + case Charm: + effect = new Effect(); + effect.effect_id = headerIterator.next(); + effect.level = Integer.parseInt(headerIterator.next()); + effect.type = headerIterator.next(); + powerAction.effects.add(effect); + break; + case Block: + effect = new Effect(); + effect.effect_id = headerIterator.next(); + effect.level = Integer.parseInt(headerIterator.next()); + powerAction.effects.add(effect); + break; + case Resurrect: + powerAction.levelCap = Integer.parseInt(headerIterator.next()); + break; + case SetItemFlag: + powerAction.itemFlag = mbEnums.ItemFlags.valueOf(headerIterator.next()); + break; + case Track: + trackEntry = new TrackEntry(); + trackEntry.action_id = headerIterator.next(); + trackEntry.trackPlayer = Boolean.parseBoolean(headerIterator.next()); + trackEntry.trackCorpse = Boolean.parseBoolean(headerIterator.next()); + trackEntry.filter = mbEnums.MonsterType.valueOf(headerIterator.next()); + trackEntry.min = Integer.parseInt(headerIterator.next()); + trackEntry.max = Integer.parseInt(headerIterator.next()); + powerAction.trackEntry = trackEntry; + break; + case Teleport: + if (headerIterator.hasNext()) + powerAction.ignoreNoTeleSpire = Boolean.parseBoolean(headerIterator.next()); + break; + case Recall: // No arguments for these tags or not parsed + case Summon: + case TreeChoke: + case SimpleDamage: + case MobRecall: // One argument always zero + case ClearAggro: + case ClearNearbyAggro: + case Peek: + case ClaimMine: + case RunegateTeleport: + case Steal: + break; + default: + Logger.error("Unhandled type " + powerAction.action_type + " for Pow4erAction: " + powerAction.action_id); + break; + } + + // Process key value pairs after header + + while (entryIterator.hasNext()) { + String lineValue = entryIterator.next(); + List lineValues = Arrays.asList(lineValue.split("=")); + String key = lineValues.get(0).trim(); + List arguments; + + switch (key) { + case "BODYPARTS": + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + + for (String bodyPart : arguments) + powerAction.bodyParts.add(Integer.parseInt(bodyPart)); + break; + case "FEMALEBODYPARTS": + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + + for (String bodyPart : arguments) + powerAction.femaleBodyParts.add(Integer.parseInt(bodyPart)); + break; + case "SCALEFACTOR": + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + + for (String scaleFactor : arguments) + powerAction.scaleFactor.add(Float.parseFloat(scaleFactor)); + break; + case "ISRESISTABLE": + powerAction.isResistible = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "ISAGGRESSIVE": + powerAction.isAggressive = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "BLADETRAILS": + powerAction.bladeTrails = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "SHOULDSHOWWEAPONS": + powerAction.shouldShowWeapons = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "SHOULDSHOWARMOR": + powerAction.shouldShowArmor = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "APPLYEFFECTBLANK": + powerAction.applyEffectBlank = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "WEAROFFEFFECTBLANK": + powerAction.wearOffEffectBlank = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "ATTACKANIMS": + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + + for (String animation : arguments) + powerAction.attackAnimations.add(Integer.parseInt(animation)); + break; + case "REMOVEALL": + powerAction.removeAll = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "EFFECTID": + effect = new Effect(); + effect.effect_id = lineValues.get(1).trim(); + powerAction.effects.add(effect); + break; + case "LEVELCAP": + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + powerAction.levelCap = Integer.parseInt(arguments.get(0)); + + if (arguments.size() > 1) // Not all level caps have a curve + powerAction.levelCapCurve = mbEnums.CompoundCurveType.valueOf(arguments.get(1)); + break; + case "CLEARAGGRO": + powerAction.clearAggro = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "TARGETBECOMESPET": + powerAction.targetBecomesPet = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "DESTROYOLDPET": + powerAction.destroyOldPet = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "DAMAGETYPE": + powerAction.damageType = mbEnums.DamageType.valueOf(lineValues.get(1).trim().toUpperCase()); + break; + case "ROOTFSMID": + powerAction.rootFsmID = mbEnums.MobBehaviourType.valueOf(lineValues.get(1).trim()); + break; + case "SPLASHDAMAGE": + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + powerAction.splashDamageMin = Integer.parseInt(arguments.get(0)); + powerAction.splashDamageMax = Integer.parseInt(arguments.get(1)); + break; + case "APPLYEFFECTOTHER": + case "APPLYEFFECTSELF": + case "WEAROFFEFFECTOTHER": // Keys not parsed go here. + case "WEAROFFEFFECTSELF": + break; + default: + Logger.error("Unhandled variable type:" + key + " for powerAction: " + powerAction.action_id); + } + } + return powerAction; + } +} diff --git a/src/engine/wpak/PowersParser.java b/src/engine/wpak/PowersParser.java new file mode 100644 index 00000000..65e1cc3b --- /dev/null +++ b/src/engine/wpak/PowersParser.java @@ -0,0 +1,321 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com + +package engine.wpak; + +import engine.gameManager.ConfigManager; +import engine.mbEnums; +import engine.util.Hasher; +import engine.wpak.data.*; +import engine.wpakpowers.WpakPowerManager; +import org.pmw.tinylog.Logger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PowersParser { + + private static final Pattern POWER_REGEX = Pattern.compile("(?<=POWERBEGIN)(.+?)(?=POWEREND)", Pattern.DOTALL); + private static final Pattern STRSPLIT_REGEX = Pattern.compile("([^\"]\\S*|\"[^\"]*\")\\s*"); + private static final Pattern CONDITION_REGEX = Pattern.compile("(?<=CONDITIONBEGIN)(.+?)(?=CONDITIONEND)", Pattern.DOTALL); + private static final String powersPath = ConfigManager.DEFAULT_DATA_DIR + "wpak/Powers.cfg"; + + public static void parseWpakFile() { + + // Read .wpak file from disk + + byte[] fileData; + + try { + fileData = Files.readAllBytes(Paths.get(powersPath)); + } catch (IOException e) { + throw new RuntimeException(e); + } + + String fileContents = new String(fileData); + + // Iterate over power entries from .wpak data + + Matcher matcher = POWER_REGEX.matcher(fileContents); + + while (matcher.find()) { + + Power power = parsePowerEntry(matcher.group().trim()); + WpakPowerManager._powersLookup.put(Hasher.SBStringHash(power.power_id), power); + } + } + + private static Power parsePowerEntry(String powerData) { + + Power powerEntry = new Power(); + StringBuilder conditionBuilder = new StringBuilder(); + StringBuilder powerBuilder = new StringBuilder(); + String conditionString; + String powerString; + java.util.Iterator iterator; + java.util.Iterator argumentIterator; + int endPos = 0; + + // Separate out any conditions from the power data + + Matcher matcher = CONDITION_REGEX.matcher(powerData); + + while (matcher.find()) { + conditionBuilder.append(matcher.group().trim()); + powerBuilder.append(powerData, endPos, matcher.start()); + endPos = matcher.end(); + } + + powerBuilder.append(powerData.substring(endPos)); + + // Cleanup dangling tags and lines that contain a # and leading/trailing blank lines + + powerString = powerBuilder.toString().replaceAll("CONDITIONBEGINCONDITIONEND", "") + .replaceAll("(?m)^(\\s*#.*|\\s*)\r?\n?", ""); + conditionString = conditionBuilder.toString().replaceAll("(?m)^(\\s*#.*|\\s*)\r?\n?", ""); + + // Parse header line in power data + + List lineData = Arrays.asList(powerString.trim().split("\n")); + List powerHeader = new ArrayList<>(); + + String headerString = lineData.get(0); + headerString = headerString.replace("\n", " "); + + matcher = STRSPLIT_REGEX.matcher(headerString); + + while (matcher.find()) + powerHeader.add(matcher.group().trim()); + + iterator = powerHeader.iterator(); + + powerEntry.power_id = iterator.next(); + powerEntry.power = iterator.next().replaceAll("\"", ""); + + PowerEntry power = new PowerEntry(); + power.power_type = mbEnums.PowerType.valueOf(iterator.next()); + power.icon = Integer.parseInt(iterator.next()); + power.focusLine = iterator.next().replaceAll("\"", ""); + powerEntry.powers.add(power); + + String nextValue = iterator.next(); + + // Account for second definition + + if (nextValue.equals("SPELL") || nextValue.equals("SKILL")) { + power = new PowerEntry(); + power.power_type = mbEnums.PowerType.valueOf(nextValue); + power.icon = Integer.parseInt(iterator.next()); + power.focusLine = iterator.next().replaceAll("\"", ""); + powerEntry.powers.add(power); + powerEntry.target_type = mbEnums.PowerTargetType.valueOf(iterator.next()); + } else + powerEntry.target_type = mbEnums.PowerTargetType.valueOf(nextValue); + + powerEntry.range = Integer.parseInt(iterator.next()); + powerEntry.areaType = mbEnums.AreaType.valueOf(iterator.next()); + powerEntry.areaRange = Integer.parseInt(iterator.next()); + powerEntry.excludeType = mbEnums.ExcludeType.valueOf(iterator.next()); + powerEntry.costType = mbEnums.CostType.valueOf(iterator.next()); + powerEntry.cost = Float.parseFloat(iterator.next()); + powerEntry.difficulty = Float.parseFloat(iterator.next()); + powerEntry.precision = Float.parseFloat(iterator.next()); + // Cleanup init_time in client data which is 0.35.1 or some such + powerEntry.init_time = Float.parseFloat(iterator.next().replaceAll("(\\.0)+$", "")); + powerEntry.release_time = Float.parseFloat(iterator.next()); + powerEntry.recycle_time = Float.parseFloat(iterator.next()); + powerEntry.hitRollYN = Integer.parseInt(iterator.next()); + powerEntry.castingMode = mbEnums.CastingModeType.valueOf(iterator.next()); + powerEntry.initAmin = Integer.parseInt(iterator.next()); + powerEntry.releaseAnim = Integer.parseInt(iterator.next()); + powerEntry.targetSelect = mbEnums.TargetSelectType.valueOf(iterator.next()); + + // Process key value pairs after header + + iterator = lineData.iterator(); + iterator.next(); // Ignore header + + while (iterator.hasNext()) { + + String lineValue = iterator.next(); + List lineValues = Arrays.asList(lineValue.split("=")); + String key = lineValues.get(0).trim(); + ActionEntry actionEntry; + List arguments; + Matcher argumentMatcher; + + switch (key) { + case "ACTION": + actionEntry = new ActionEntry(); + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + actionEntry.action_id = arguments.get(0); + actionEntry.minTrains = Integer.parseInt(arguments.get(1)); + actionEntry.maxTrains = Integer.parseInt(arguments.get(2)); + actionEntry.duration = Float.parseFloat(arguments.get(3)); + actionEntry.curve = mbEnums.CompoundCurveType.valueOf(arguments.get(4)); + actionEntry.stackingCategory = arguments.get(5); + actionEntry.stackingPriority = Integer.parseInt(arguments.get(6)); + actionEntry.categoryToPower = mbEnums.CategoryToPowerType.valueOf(arguments.get(7)); + powerEntry.actionEntries.add(actionEntry); + break; + case "MaxLevel": + powerEntry.maxLevel = Integer.parseInt(lineValues.get(1).trim()); + break; + case "HateValue": + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + powerEntry.hateValue = Integer.parseInt(arguments.get(0)); + + // Not all entries have a curve. Defaults to DefaultFlat; + + if (arguments.size() > 1) + powerEntry.hateCurve = mbEnums.CompoundCurveType.valueOf(arguments.get(1)); + break; + case "LOOPANIMID": + powerEntry.loopAnimID = Integer.parseInt(lineValues.get(1).trim()); + break; + case "GRANTOVERRIDEVAR": + powerEntry.grantOverrideVar = lineValues.get(1).trim(); + break; + case "DESCRIPTION": + powerEntry.description.add(lineValues.get(1).trim()); + break; + case "CATEGORY": + powerEntry.category = mbEnums.PowerCategoryType.valueOf(lineValues.get(1).trim()); + break; + case "CURVE": + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + powerEntry.curves.put(arguments.get(0), mbEnums.CompoundCurveType.valueOf(arguments.get(1))); + break; + case "EQPREREQ": + argumentMatcher = STRSPLIT_REGEX.matcher(lineValues.get(1).trim()); + arguments = new ArrayList<>(); + + while (argumentMatcher.find()) + arguments.add(argumentMatcher.group().trim()); + + argumentIterator = arguments.iterator(); + + while (argumentIterator.hasNext()) { + EquipmentPreReq equipmentPreReq = new EquipmentPreReq(); + equipmentPreReq.slot = mbEnums.EquipSlotType.valueOf(argumentIterator.next()); + equipmentPreReq.skill = argumentIterator.next().replaceAll("\"", ""); + + if (argumentIterator.hasNext()) + equipmentPreReq.required = Integer.parseInt(argumentIterator.next()); + else + equipmentPreReq.required = 0; + + powerEntry.equipmentPreReq.add(equipmentPreReq); + } + break; + case "CANCASTWHILEMOVING": + powerEntry.canCastWhileMoving = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "CANCASTWHILEFLYING": + powerEntry.canCastWhileFlying = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "BLADETRAILS": + powerEntry.bladeTrails = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "EFFECTPREREQ": + Effect effectPreReq = new Effect(); + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + effectPreReq.effect_id = arguments.get(9); + effectPreReq.level = Integer.parseInt(arguments.get(1)); + effectPreReq.message = arguments.get(2); + powerEntry.effectPreReqs.add(effectPreReq); + break; + case "MONSTERTYPERESTRICTS": + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + + for (String restriction : arguments) + powerEntry.monsterRestricts.add(mbEnums.MonsterType.valueOf(restriction.trim())); + break; + case "MONSTERTYPEPREREQS": + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + + for (String restriction : arguments) + powerEntry.monsterPrereqs.add(mbEnums.MonsterType.valueOf(restriction.trim())); + break; + case "SHOULDCHECKPATH": + powerEntry.shouldCheckPath = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "STICKY": + powerEntry.sticky = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "PULSEINFO": + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + powerEntry.pulseCycle = Integer.parseInt(arguments.get(0)); + powerEntry.pulseDuration = Integer.parseInt(arguments.get(1)); + break; + case "MAXNUMMOBTARGETS": + powerEntry.maxMobTargets = Integer.parseInt(lineValues.get(1).trim()); + break; + case "MAXNUMPLAYERTARGETS": + powerEntry.maxPlayerTargets = Integer.parseInt(lineValues.get(1).trim()); + break; + case "ISADMINPOWER": + powerEntry.isAdminPower = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "ISPROJECTILE": + powerEntry.isProjectile = Boolean.parseBoolean(lineValues.get(1).trim()); + break; + case "CASTERSPULSEPARTICLE": + powerEntry.casterPulseParticle = Integer.parseInt(lineValues.get(1).trim()); + break; + case "TARGETEFFECTPREREQS_ORED": + Effect preReq = new Effect(); + arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+")); + preReq.effect_id = arguments.get(0); + preReq.level = Integer.parseInt(arguments.get(1)); + powerEntry.targetEffectPrereqs.add(preReq); + break; + case "SOUNDS": // Values not parsed + case "APPLYDAMAGESELF": + case "APPLYDAMAGECASTER": + case "APPLYDAMAGEOTHER": + case "APPLYDAMAGETARGET": + case "APPLYEFFECTSELF": + case "APPLYEFFECTOTHER": + case "APPLYEFFECTCASTER": + case "APPLYEFFECTTARGET": + case "FIZZLEOTHER": + case "FIZZLESELF": + case "INITSTRING": + case "SUCCESSOTHER": + case "SUCCESSSELF": + case "WEAROFFEFFECTOTHER": + case "WEAROFFEFFECTSELF": + break; + default: + Logger.error("Unhandled variable type:" + key + " for power: " + powerEntry.power_id); + } + } + + // Parse power conditions + + if (conditionString.isEmpty() == false) { + + List conditions = Arrays.asList(conditionString.split("\n")); + + for (String condition : conditions) { + List parameters = Arrays.asList(condition.trim().split("\\s+")); + powerEntry.conditions.put(parameters.get(0), Float.parseFloat(parameters.get(1))); + } + } + return powerEntry; + } + +} + diff --git a/src/engine/wpak/data/ActionEntry.java b/src/engine/wpak/data/ActionEntry.java new file mode 100644 index 00000000..8a997d1d --- /dev/null +++ b/src/engine/wpak/data/ActionEntry.java @@ -0,0 +1,24 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com + +package engine.wpak.data; + +import engine.mbEnums; + +public class ActionEntry { + + public String action_id; + public int minTrains; + public int maxTrains; + public float duration; + public String stackingCategory; + public mbEnums.CompoundCurveType curve; + public int stackingPriority; + public mbEnums.CategoryToPowerType categoryToPower; + +} diff --git a/src/engine/wpak/data/ConditionEntry.java b/src/engine/wpak/data/ConditionEntry.java new file mode 100644 index 00000000..0c3eda2c --- /dev/null +++ b/src/engine/wpak/data/ConditionEntry.java @@ -0,0 +1,21 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com +// +package engine.wpak.data; + +import engine.mbEnums; + +import java.util.EnumSet; + +public class ConditionEntry { + public String condition; + public int arg; + public mbEnums.CompoundCurveType curveType; + public EnumSet damageTypes = EnumSet.noneOf(mbEnums.DamageType.class); + +} diff --git a/src/engine/wpak/data/Effect.java b/src/engine/wpak/data/Effect.java new file mode 100644 index 00000000..fdfd71f4 --- /dev/null +++ b/src/engine/wpak/data/Effect.java @@ -0,0 +1,51 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com + +package engine.wpak.data; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Objects; + +public class Effect { + public String effect_id; + public String effect_name; + public int icon; + public HashSet sources = new HashSet<>(); + public ArrayList mods = new ArrayList<>(); + public ArrayList conditions = new ArrayList<>(); + + // Additional variables outside of tags or parsed + // elsewhere from Effects.cfg + + public boolean isItemEffect; + public boolean isSpireEffect; + public boolean ignoreNoMod; + public boolean dontSave; + + public String type; + public int level; + public String message; + public int cycleDuration; + public int cycleDelay; + + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + Effect effect = (Effect) o; + return Objects.equals(effect_id, effect.effect_id); + } + + @Override + public int hashCode() { + return effect_id.hashCode(); // Use only the id field for hashCode + } +} diff --git a/src/engine/wpak/data/EquipmentPreReq.java b/src/engine/wpak/data/EquipmentPreReq.java new file mode 100644 index 00000000..443a1633 --- /dev/null +++ b/src/engine/wpak/data/EquipmentPreReq.java @@ -0,0 +1,19 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com + +package engine.wpak.data; + +import engine.mbEnums; + +public class EquipmentPreReq { + + public mbEnums.EquipSlotType slot; + public String skill; + public int required; + +} diff --git a/src/engine/wpak/data/ModifierEntry.java b/src/engine/wpak/data/ModifierEntry.java new file mode 100644 index 00000000..890cb6a6 --- /dev/null +++ b/src/engine/wpak/data/ModifierEntry.java @@ -0,0 +1,23 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com + +package engine.wpak.data; + +import engine.mbEnums; + +public class ModifierEntry { + public mbEnums.ModType type; + public float min; + public float max; + public float percentage; + public float value; + public mbEnums.CompoundCurveType compoundCurveType; + public String arg1; // ItemName "Masterwork" "" + public String arg2; // ItemName "" "of the Defender" + +} diff --git a/src/engine/wpak/data/Power.java b/src/engine/wpak/data/Power.java new file mode 100644 index 00000000..b71dc250 --- /dev/null +++ b/src/engine/wpak/data/Power.java @@ -0,0 +1,96 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com + +package engine.wpak.data; + +import engine.mbEnums; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Objects; + +public class Power { + public String power_id; + public String power; + public ArrayList powers = new ArrayList<>(); + public mbEnums.PowerTargetType target_type; + public int range; + public mbEnums.AreaType areaType; + public int areaRange; + public mbEnums.ExcludeType excludeType; + public mbEnums.CostType costType; + public float cost; + public float difficulty; + public float precision; + public float init_time; + public float release_time; + public float recycle_time; + public int hitRollYN; + public mbEnums.CastingModeType castingMode; + public int initAmin; + public int releaseAnim; + public mbEnums.TargetSelectType targetSelect; + + // Additional key/value type power entries + + public ArrayList actionEntries = new ArrayList<>(); + public int maxLevel; + public int hateValue; + public mbEnums.CompoundCurveType hateCurve = mbEnums.CompoundCurveType.DefaultFlat; + public int loopAnimID; + public String grantOverrideVar; + public ArrayList description = new ArrayList<>(); + public HashMap curves = new HashMap<>(); + public mbEnums.PowerCategoryType category; + public boolean canCastWhileMoving = false; + public boolean bladeTrails = false; + public ArrayList effectPreReqs = new ArrayList<>(); + public ArrayList equipmentPreReq = new ArrayList<>(); + public EnumSet monsterRestricts = EnumSet.noneOf(mbEnums.MonsterType.class); + public EnumSet monsterPrereqs = EnumSet.noneOf(mbEnums.MonsterType.class); + public boolean shouldCheckPath = false; + public boolean sticky = false; + public int pulseCycle; + public int pulseDuration; + public int maxMobTargets; + public int maxPlayerTargets; + public boolean isAdminPower = false; + public int casterPulseParticle; + public ArrayList targetEffectPrereqs = new ArrayList<>(); + public boolean canCastWhileFlying = false; + public boolean isProjectile = false; + public HashMap conditions = new HashMap<>(); + + public boolean isSpell() { + return true; + } + + public boolean isSkill() { + return true; + } + + public boolean isChant() { + return true; + } + + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + Power power = (Power) o; + return Objects.equals(power_id, power.power_id); + } + + @Override + public int hashCode() { + return power_id.hashCode(); // Use only the id field for hashCode + } +} diff --git a/src/engine/wpak/data/PowerAction.java b/src/engine/wpak/data/PowerAction.java new file mode 100644 index 00000000..17faf0df --- /dev/null +++ b/src/engine/wpak/data/PowerAction.java @@ -0,0 +1,68 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com + +package engine.wpak.data; + +import engine.mbEnums; + +import java.util.ArrayList; +import java.util.Objects; + +public class PowerAction { + + // Header values + + public String action_id; + public mbEnums.PowerActionType action_type; + public ArrayList effects = new ArrayList<>(); + public int petLevel; + public int petRace; + public StatTransfer statTransfer; + public int levelCap; + public mbEnums.CompoundCurveType levelCapCurve; + public TrackEntry trackEntry; + + // Additional variables after header go here. + + public ArrayList bodyParts = new ArrayList<>(); + public ArrayList femaleBodyParts = new ArrayList<>(); + public boolean shouldShowWeapons = false; + public boolean shouldShowArmor = false; + public boolean bladeTrails = false; + public boolean isResistible = false; + public ArrayList scaleFactor = new ArrayList<>(); + public ArrayList attackAnimations = new ArrayList<>(); + public boolean isAggressive; + public mbEnums.DamageType damageType; + public boolean applyEffectBlank = false; + public boolean wearOffEffectBlank = false; + public boolean removeAll = false; + public boolean clearAggro = false; + public boolean targetBecomesPet = false; + public boolean destroyOldPet = false; + public mbEnums.ItemFlags itemFlag; + public mbEnums.MobBehaviourType rootFsmID; + public int splashDamageMin; + public int splashDamageMax; + public boolean ignoreNoTeleSpire = false; + + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + PowerAction powerAction = (PowerAction) o; + return Objects.equals(action_id, powerAction.action_id); + } + + @Override + public int hashCode() { + return action_id.hashCode(); // Use only the id field for hashCode + } +} diff --git a/src/engine/wpak/data/PowerEntry.java b/src/engine/wpak/data/PowerEntry.java new file mode 100644 index 00000000..364822a5 --- /dev/null +++ b/src/engine/wpak/data/PowerEntry.java @@ -0,0 +1,17 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com + +package engine.wpak.data; + +import engine.mbEnums; + +public class PowerEntry { + public mbEnums.PowerType power_type; + public int icon; + public String focusLine; +} diff --git a/src/engine/wpak/data/StatTransfer.java b/src/engine/wpak/data/StatTransfer.java new file mode 100644 index 00000000..85a95235 --- /dev/null +++ b/src/engine/wpak/data/StatTransfer.java @@ -0,0 +1,24 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2024 +// www.magicbane.com + +package engine.wpak.data; + +import engine.mbEnums; + +public class StatTransfer { + public mbEnums.CostType fromStat; + public float ramp; + public mbEnums.CompoundCurveType rampCurve; + public mbEnums.CostType toStat; + public float efficiency; + public mbEnums.CompoundCurveType efficiencyCurve; + public boolean fromStatBool; + public boolean isDrain; + public String transfer_action; + public int transfer_ticks; +} diff --git a/src/engine/wpak/data/TrackEntry.java b/src/engine/wpak/data/TrackEntry.java new file mode 100644 index 00000000..0502d384 --- /dev/null +++ b/src/engine/wpak/data/TrackEntry.java @@ -0,0 +1,21 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2022 +// www.magicbane.com + +package engine.wpak.data; + +import engine.mbEnums; + +public class TrackEntry { + + public String action_id; + public Boolean trackPlayer; + public Boolean trackCorpse; + public mbEnums.MonsterType filter; + public int min; + public int max; +}