diff --git a/src/engine/gameManager/BuildingManager.java b/src/engine/gameManager/BuildingManager.java
index 8907339a..6292c457 100644
--- a/src/engine/gameManager/BuildingManager.java
+++ b/src/engine/gameManager/BuildingManager.java
@@ -798,7 +798,7 @@ public enum BuildingManager {
         // Attempt to write to database or delete the building
         // if we are destroying it.
 
-        if (rank == -1)
+        if (rank < 0)
             success = DbManager.BuildingQueries.DELETE_FROM_DATABASE(building);
         else
             success = DbManager.BuildingQueries.updateBuildingRank(building, rank);
diff --git a/src/engine/gameManager/PowersManager.java b/src/engine/gameManager/PowersManager.java
index 4f70aedb..da6fb5c4 100644
--- a/src/engine/gameManager/PowersManager.java
+++ b/src/engine/gameManager/PowersManager.java
@@ -32,7 +32,7 @@ import engine.server.MBServerStatics;
 import engine.wpak.EffectsParser;
 import engine.wpak.PowerActionParser;
 import engine.wpak.PowersParser;
-import engine.wpak.data.EffectEntry;
+import engine.wpak.data.Effect;
 import org.pmw.tinylog.Logger;
 
 import java.sql.SQLException;
@@ -118,7 +118,7 @@ public enum PowersManager {
         // Add EffectsBase
         ArrayList<EffectsBase> effectList = new ArrayList<>();
 
-        for (EffectEntry entry : EffectsParser.effect_data.values()) {
+        for (Effect entry : EffectsParser.effect_data.values()) {
             EffectsBase effectBase = new EffectsBase(entry);
             effectList.add(effectBase);
             PowersManager.effectsBaseByToken.put(effectBase.getToken(), effectBase);
@@ -950,7 +950,7 @@ public enum PowersManager {
                 //				if (!stackType.equals("IgnoreStack")) {
                 if (target.getEffects().containsKey(stackType)) {
                     // remove any existing power that overrides
-                    Effect ef = target.getEffects().get(stackType);
+                    engine.objects.Effect ef = target.getEffects().get(stackType);
                     AbstractEffectJob effect = null;
                     if (ef != null) {
                         JobContainer jc = ef.getJobContainer();
@@ -1122,7 +1122,7 @@ public enum PowersManager {
                 //				if (!stackType.equals("IgnoreStack")) {
                 if (target.getEffects().containsKey(stackType)) {
                     // remove any existing power that overrides
-                    Effect ef = target.getEffects().get(stackType);
+                    engine.objects.Effect ef = target.getEffects().get(stackType);
                     AbstractEffectJob effect = null;
                     if (ef != null) {
                         JobContainer jc = ef.getJobContainer();
@@ -1436,7 +1436,7 @@ public enum PowersManager {
             stackType = (stackType.equals("IgnoreStack")) ? Integer.toString(ab.getUUID()) : stackType;
             if (target.getEffects().containsKey(stackType)) {
                 // remove any existing power that overrides
-                Effect ef = target.getEffects().get(stackType);
+                engine.objects.Effect ef = target.getEffects().get(stackType);
                 AbstractEffectJob effect = null;
                 if (ef != null) {
                     JobContainer jc = ef.getJobContainer();
@@ -1883,7 +1883,7 @@ public enum PowersManager {
         stackType = (stackType.equals("IgnoreStack")) ? Integer
                 .toString(toRemove.getUUID()) : stackType;
         if (fromChant) {
-            Effect eff = awo.getEffects().get(stackType);
+            engine.objects.Effect eff = awo.getEffects().get(stackType);
             if (eff != null)
                 eff.cancelJob(true);
         } else
diff --git a/src/engine/mbEnums.java b/src/engine/mbEnums.java
index bf2fca29..bedcc087 100644
--- a/src/engine/mbEnums.java
+++ b/src/engine/mbEnums.java
@@ -2732,7 +2732,7 @@ public class mbEnums {
         DIAMOND(1580010, 1540225085, -1730704107, 2000, 20),
         GALVOR(1580017, -1683992404, -1596311545, 2000, 5),
         IRON(1580002, -1673518119, 2504297, 2000, 20),
-        LUMBER(1580004, 1628412684, -1603256692, 10000, 100),
+        LUMBER(1580004, -1628412684, -1603256692, 10000, 100),
         MANDRAKE(1580007, 1519910613, 1191391799, 1000, 10),
         MITHRIL(1580021, 626743397, -1761257186, 500, 5),
         OAK(1580005, -1653034775, 74767, 3000, 30),
diff --git a/src/engine/objects/Building.java b/src/engine/objects/Building.java
index 5367c8f7..0a356546 100644
--- a/src/engine/objects/Building.java
+++ b/src/engine/objects/Building.java
@@ -561,7 +561,7 @@ public class Building extends AbstractWorldObject {
                 BuildingManager.setRank(barracksBuilding, -1);
         }
 
-        // If the tree is R8 and deranking, we need to update it's
+        // If the tree is R8 and deranking, we need to update the
         // mesh along with buildings losing their health bonus
 
         if (this.rank == 8) {
diff --git a/src/engine/objects/City.java b/src/engine/objects/City.java
index 8f674de8..a9fae4b6 100644
--- a/src/engine/objects/City.java
+++ b/src/engine/objects/City.java
@@ -41,6 +41,7 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 public class City extends AbstractWorldObject {
@@ -80,6 +81,7 @@ public class City extends AbstractWorldObject {
     private String hash;
     public Warehouse warehouse;
     public Realm realm;
+    public AtomicBoolean isDestroyed = new AtomicBoolean(false);
 
     /**
      * ResultSet Constructor
@@ -306,6 +308,21 @@ public class City extends AbstractWorldObject {
             if (city.parentZone == null)
                 continue;
 
+            // Can't teleport to something without a tree
+
+            if (city.getTOL() == null)
+                continue;
+
+            // No abandoned cities
+
+            if (city.getTOL().getGuild().isEmptyGuild())
+                continue;
+
+            // No destroyed cities
+
+            if (city.getTOL().getRank() == -1)
+                continue;
+
             //can't repledge to a guild you're already part of
 
             if (repledge && city.getGuild().equals(playerCharacter.guild))
@@ -1102,17 +1119,21 @@ public class City extends AbstractWorldObject {
 
     public final void destroy() {
 
-        Thread destroyCityThread = new Thread(new DestroyCityThread(this));
+        if (this.isDestroyed.compareAndSet(false, true)) {
 
-        destroyCityThread.setName("destroyCity:" + this.getName());
-        destroyCityThread.start();
+            Thread destroyCityThread = new Thread(new DestroyCityThread(this));
+
+            destroyCityThread.setName("destroyCity:" + this.getParent().zoneName);
+            destroyCityThread.start();
+        } else
+            Logger.error("Attempt to destroy destroyed city");
     }
 
     public final void transfer(AbstractCharacter newOwner) {
 
         Thread transferCityThread = new Thread(new TransferCityThread(this, newOwner));
 
-        transferCityThread.setName("TransferCity:" + this.getName());
+        transferCityThread.setName("TransferCity:" + this.getParent().zoneName);
         transferCityThread.start();
     }
 
diff --git a/src/engine/objects/Mine.java b/src/engine/objects/Mine.java
index dabfb557..553c1036 100644
--- a/src/engine/objects/Mine.java
+++ b/src/engine/objects/Mine.java
@@ -220,8 +220,7 @@ public class Mine extends AbstractGameObject {
         // Only inactive mines are returned.
 
         for (Mine mine : Mine.mineMap.keySet()) {
-            if (mine.owningGuild.getObjectUUID() == guildID &&
-                    mine.isActive == false)
+            if (mine.owningGuild.getObjectUUID() == guildID)
                 mineList.add(mine);
         }
         return mineList;
diff --git a/src/engine/workthreads/DestroyCityThread.java b/src/engine/workthreads/DestroyCityThread.java
index 9c5b2050..77453c71 100644
--- a/src/engine/workthreads/DestroyCityThread.java
+++ b/src/engine/workthreads/DestroyCityThread.java
@@ -53,123 +53,117 @@ public class DestroyCityThread implements Runnable {
 
         // Member variable assignment
 
-        cityZone = city.getParent();
-        newParent = cityZone.parent;
-        formerGuild = city.getTOL().getGuild();
+        try {
+            cityZone = city.getParent();
+            newParent = cityZone.parent;
+            formerGuild = city.getTOL().getGuild();
 
-        // Former guild loses it's tree!
+            Logger.info("Destroy city thread started for: " + cityZone.zoneName);
 
-        if (DbManager.GuildQueries.SET_GUILD_OWNED_CITY(formerGuild.getObjectUUID(), 0)) {
+            // Former guild loses tree!
 
-            //Successful Update of guild
+            if (DbManager.GuildQueries.SET_GUILD_OWNED_CITY(formerGuild.getObjectUUID(), 0)) {
 
-            formerGuild.setGuildState(mbEnums.GuildState.Errant);
-            formerGuild.setNation(null);
-            formerGuild.setCityUUID(0);
-            GuildManager.updateAllGuildTags(formerGuild);
-            GuildManager.updateAllGuildBinds(formerGuild, null);
-        }
+                //Successful Update of guild
+
+                formerGuild.setGuildState(mbEnums.GuildState.Errant);
+                formerGuild.setNation(null);
+                formerGuild.setCityUUID(0);
+                GuildManager.updateAllGuildTags(formerGuild);
+                GuildManager.updateAllGuildBinds(formerGuild, null);
+            }
 
-        // By losing the tree, the former owners lose all of their subguilds.
+            // By losing the tree, the former owners lose all of their subguilds.
 
-        if (!formerGuild.getSubGuildList().isEmpty()) {
+            if (!formerGuild.getSubGuildList().isEmpty()) {
 
-            subGuildList = new ArrayList<>();
+                subGuildList = new ArrayList<>();
 
-            subGuildList.addAll(formerGuild.getSubGuildList());
+                subGuildList.addAll(formerGuild.getSubGuildList());
 
-            for (Guild subGuild : subGuildList) {
-                formerGuild.removeSubGuild(subGuild);
+                for (Guild subGuild : subGuildList) {
+                    formerGuild.removeSubGuild(subGuild);
+                }
             }
-        }
 
-        Building tol = null;
+            // Build list of buildings within this parent zone
 
-        // Build list of buildings within this parent zone
+            ArrayList<Building> destroySet = new ArrayList<>();
 
-        for (Building cityBuilding : cityZone.zoneBuildingSet) {
+            for (Building cityBuilding : cityZone.zoneBuildingSet) {
 
-            // Sanity Check in case player deletes the building
-            // before this thread can get to it
+                // Sanity Check in case player deletes the building
+                // before this thread can get to it
 
-            if (cityBuilding == null)
-                continue;
+                if (cityBuilding == null)
+                    continue;
 
-            // Do nothing with the banestone.  It will be removed elsewhere
+                // Do nothing with the banestone.  It will be removed elsewhere
 
-            if (cityBuilding.getBlueprint().getBuildingGroup().equals(mbEnums.BuildingGroup.BANESTONE))
-                continue;
+                if (cityBuilding.getBlueprint().getBuildingGroup().equals(mbEnums.BuildingGroup.BANESTONE))
+                    continue;
 
-            // TOL is processed after all other structures in the city zone
+                // All buildings are moved to a location relative
+                // to their new parent zone
 
-            if (cityBuilding.getBlueprint().getBuildingGroup().equals(mbEnums.BuildingGroup.TOL)) {
-                tol = cityBuilding;
-                continue;
-            }
+                localCoords = ZoneManager.worldToLocal(cityBuilding.getLoc(), newParent);
 
-            // All buildings are moved to a location relative
-            // to their new parent zone
+                DbManager.BuildingQueries.MOVE_BUILDING(cityBuilding.getObjectUUID(), newParent.getObjectUUID(), localCoords.x, localCoords.y, localCoords.z);
 
-            localCoords = ZoneManager.worldToLocal(cityBuilding.getLoc(), newParent);
+                // All buildings are re-parented to a zone one node
+                // higher in the tree (continent) as we will be
+                // deleting the city zone very shortly.
 
-            DbManager.BuildingQueries.MOVE_BUILDING(cityBuilding.getObjectUUID(), newParent.getObjectUUID(), localCoords.x, localCoords.y, localCoords.z);
+                if (cityBuilding.getParentZoneID() != newParent.getParentZoneID())
+                    cityBuilding.setParentZone(newParent);
 
-            // All buildings are re-parented to a zone one node
-            // higher in the tree (continent) as we will be
-            // deleting the city zone very shortly.
+                // No longer a tree, no longer any protection contract!
 
-            if (cityBuilding.getParentZoneID() != newParent.getParentZoneID())
-                cityBuilding.setParentZone(newParent);
+                cityBuilding.setProtectionState(mbEnums.ProtectionState.NONE);
 
-            // No longer a tree, no longer any protection contract!
+                // Remove warehouse entry if one exists.
 
-            cityBuilding.setProtectionState(mbEnums.ProtectionState.NONE);
+                if (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.WAREHOUSE) {
+                    DbManager.WarehouseQueries.DELETE_WAREHOUSE(city.warehouse);
+                    city.warehouse = null;
+                }
 
-            // Remove warehouse entry if one exists.
+                // Mark all auto protected buildings for destruction
 
-            if (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.WAREHOUSE) {
-                DbManager.WarehouseQueries.DELETE_WAREHOUSE(city.warehouse);
-                city.warehouse = null;
+                if ((cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.BARRACK) || (cityBuilding.getBlueprint().isWallPiece()) || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.SHRINE) || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.TOL) || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.SPIRE) || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.WAREHOUSE))
+                    destroySet.add(cityBuilding);
             }
 
-            // Destroy all remaining city assets
+            // Destroy set of auto-protected buildings
 
-            if ((cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.BARRACK)
-                    || (cityBuilding.getBlueprint().isWallPiece())
-                    || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.SHRINE)
-                    || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.TOL)
-                    || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.SPIRE)
-                    || (cityBuilding.getBlueprint().getBuildingGroup() == mbEnums.BuildingGroup.WAREHOUSE)) {
+            for (Building building : destroySet)
+                if (building.getRank() != -1)
+                    BuildingManager.setRank(building, -1);
 
-                if (cityBuilding.getRank() != -1)
-                    BuildingManager.setRank(cityBuilding, -1);
+            if (city.realm != null) {
+                city.realm.removeCity(city.getObjectUUID());
+                city.realm = null;
             }
-        }
-
-        // Destroy the tol
 
-        if (tol != null)
-            BuildingManager.setRank(tol, -1);
+            // It's now safe to delete the city zone from the database
+            // which will cause a cascade delete of everything else
 
-        if (city.realm != null)
-            city.realm.removeCity(city.getObjectUUID());
+            if (!DbManager.ZoneQueries.DELETE_ZONE(cityZone)) {
+                Logger.error("DestroyCityThread", "Database error when deleting city zone: " + cityZone.getObjectUUID());
+                return;
+            }
 
-        // It's now safe to delete the city zone from the database
-        // which will cause a cascade delete of everything else
+            // Refresh the city for map requests
 
+            City.lastCityUpdate = System.currentTimeMillis();
 
-        if (DbManager.ZoneQueries.DELETE_ZONE(cityZone) == false) {
-            Logger.error("DestroyCityThread", "Database error when deleting city zone: " + cityZone.getObjectUUID());
-            return;
+        } catch (Exception e) {
+            Logger.error(e);
         }
 
-        // Refresh the city for map requests
-
-        City.lastCityUpdate = System.currentTimeMillis();
-
         // Zone and city should vanish upon next reboot
         // if the codebase reaches here.
 
-        Logger.info(city.getParent().zoneName + " uuid:" + city.getObjectUUID() + "has been destroyed!");
+        Logger.info(city.getParent().zoneName + " uuid: " + city.getObjectUUID() + " has been destroyed!");
     }
 }
diff --git a/src/engine/wpak/EffectsParser.java b/src/engine/wpak/EffectsParser.java
index 9c653c70..0d7999d7 100644
--- a/src/engine/wpak/EffectsParser.java
+++ b/src/engine/wpak/EffectsParser.java
@@ -11,8 +11,8 @@ package engine.wpak;
 import engine.gameManager.ConfigManager;
 import engine.mbEnums;
 import engine.wpak.data.ConditionEntry;
-import engine.wpak.data.EffectEntry;
-import engine.wpak.data.EffectModifier;
+import engine.wpak.data.Effect;
+import engine.wpak.data.ModifierEntry;
 import org.pmw.tinylog.Logger;
 
 import java.io.IOException;
@@ -25,7 +25,7 @@ import java.util.regex.Pattern;
 public class EffectsParser {
 
     public static String effectsPath = ConfigManager.DEFAULT_DATA_DIR + "wpak/Effects.cfg";
-    public static HashMap<String, EffectEntry> effect_data = new HashMap<>();
+    public static HashMap<String, Effect> effect_data = new HashMap<>();
     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);
@@ -51,21 +51,21 @@ public class EffectsParser {
         Matcher matcher = EFFECT_REGEX.matcher(fileContents);
 
         while (matcher.find()) {
-            EffectEntry effectEntry = parseEffectEntry(matcher.group());
-            effect_data.put(effectEntry.effect_id, effectEntry);
+            Effect effect = parseEffectEntry(matcher.group());
+            effect_data.put(effect.effect_id, effect);
         }
     }
 
-    private static EffectEntry parseEffectEntry(String effectData) {
+    private static Effect parseEffectEntry(String effectData) {
 
-        EffectEntry effectEntry = new EffectEntry();
+        Effect effect = new Effect();
 
         // Parse fields that lie outside the other tags
 
-        effectEntry.isItemEffect = effectData.contains("IsItemEffect");
-        effectEntry.isSpireEffect = effectData.contains("IsSpireEffect");
-        effectEntry.ignoreNoMod = effectData.contains("IgnoreNoMod");
-        effectEntry.dontSave = effectData.contains("DontSave");
+        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
 
@@ -90,24 +90,24 @@ public class EffectsParser {
         while (matcher.find())
             effectHeader.add(matcher.group().trim());
 
-        effectEntry.effect_id = effectHeader.get(0);
-        effectEntry.effect_name = effectHeader.get(1);
-        effectEntry.effect_name = effectEntry.effect_name.replaceAll("\"", "");
+        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)
-            effectEntry.icon = Integer.parseInt(effectHeader.get(2));
+            effect.icon = Integer.parseInt(effectHeader.get(2));
         else
-            effectEntry.icon = 0;
+            effect.icon = 0;
 
         // Parse source entries
 
         matcher = SOURCE_REGEX.matcher(effectData);
 
         while (matcher.find())
-            effectEntry.sources.add(matcher.group().trim());
+            effect.sources.add(matcher.group().trim());
 
         // Parse modifier entries
 
@@ -116,8 +116,8 @@ public class EffectsParser {
         // Iterate effect entries from .wpak config data
 
         while (matcher.find()) {
-            EffectModifier effectModifier = parseModEntry(matcher.group());
-            effectEntry.mods.add(effectModifier);
+            ModifierEntry modifierEntry = parseModEntry(matcher.group());
+            effect.mods.add(modifierEntry);
         }
 
         // Parse Conditions
@@ -141,16 +141,16 @@ public class EffectsParser {
                 while (iterator.hasNext())
                     conditionEntry.damageTypes.add(mbEnums.DamageType.valueOf(iterator.next().toUpperCase()));
 
-                effectEntry.conditions.add(conditionEntry);
+                effect.conditions.add(conditionEntry);
             }
         }
 
-        return effectEntry;
+        return effect;
     }
 
-    private static EffectModifier parseModEntry(String modData) {
+    private static ModifierEntry parseModEntry(String modData) {
 
-        EffectModifier effectModifier = new EffectModifier();
+        ModifierEntry modifierEntry = new ModifierEntry();
 
         String[] modEntries = modData.trim().split("\n");
 
@@ -162,40 +162,22 @@ public class EffectsParser {
             while (matcher.find())
                 modValues.add(matcher.group().trim());
 
-            effectModifier.type = mbEnums.ModType.valueOf(modValues.get(0).trim());
+            modifierEntry.type = mbEnums.ModType.valueOf(modValues.get(0).trim());
 
-            switch (effectModifier.type) {
-                case BladeTrails:  // No parm modifiers
-                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;
+            switch (modifierEntry.type) {
                 case AnimOverride:
-                    effectModifier.min = Float.parseFloat(modValues.get(1).trim());
-                    effectModifier.max = Float.parseFloat(modValues.get(2).trim());
+                    modifierEntry.min = Float.parseFloat(modValues.get(1).trim());
+                    modifierEntry.max = Float.parseFloat(modValues.get(2).trim());
                     break;
                 case Health:
                 case Mana:
                 case Stamina:
-                    effectModifier.min = Float.parseFloat(modValues.get(1).trim());
-                    effectModifier.max = Float.parseFloat(modValues.get(2).trim());
-                    effectModifier.scale = Float.parseFloat(modValues.get(3).trim());
+                    modifierEntry.min = Float.parseFloat(modValues.get(1).trim());
+                    modifierEntry.max = Float.parseFloat(modValues.get(2).trim());
+                    modifierEntry.value = Float.parseFloat(modValues.get(3).trim());
                     // Parameter 4 is always 0.
-                    effectModifier.compoundCurveType = mbEnums.CompoundCurveType.valueOf(modValues.get(5).trim());
-                    effectModifier.arg1 = modValues.get(6).trim();
+                    modifierEntry.compoundCurveType = mbEnums.CompoundCurveType.valueOf(modValues.get(5).trim());
+                    modifierEntry.arg1 = modValues.get(6).trim();
                     break;
                 case Attr:
                 case Resistance:
@@ -210,12 +192,12 @@ public class EffectsParser {
                 case Slay:
                 case Fade:
                 case Durability:
-                    effectModifier.min = Float.parseFloat(modValues.get(1).trim());
-                    effectModifier.scale = Float.parseFloat(modValues.get(2).trim());
-                    effectModifier.compoundCurveType = mbEnums.CompoundCurveType.valueOf(modValues.get(3).trim());
+                    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)
-                        effectModifier.arg1 = modValues.get(4).trim();   // Some HeathFull entries do not have an argument
+                        modifierEntry.arg1 = modValues.get(4).trim();   // Some HeathFull entries do not have an argument
                     break;
                 case MeleeDamageModifier:
                 case OCV:
@@ -236,44 +218,62 @@ public class EffectsParser {
                 case Block:
                 case Parry:
                 case Dodge:
+                case WeaponRange:
                 case ScanRange:
                 case ScaleHeight:
                 case ScaleWidth:
-                case WeaponRange:
-                    effectModifier.min = Float.parseFloat(modValues.get(1).trim());
-                    effectModifier.scale = Float.parseFloat(modValues.get(2).trim());
-                    effectModifier.compoundCurveType = mbEnums.CompoundCurveType.valueOf(modValues.get(3).trim());
+                    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:
-                    effectModifier.arg1 = modValues.get(1).trim();
+                    modifierEntry.arg1 = modValues.get(1).trim();
 
                     // Some BlockedPowerType entries have only one argument
 
                     if (modValues.size() > 2)
-                        effectModifier.arg2 = modValues.get(2).trim();
+                        modifierEntry.arg2 = modValues.get(2).trim();
                     break;
                 case NoMod:
                 case ConstrainedAmbidexterity:
                 case ProtectionFrom:
                 case ExclusiveDamageCap:
                 case IgnoreDamageCap:
-                    effectModifier.arg1 = modValues.get(1).trim();
+                    modifierEntry.arg1 = modValues.get(1).trim();
                     break;
                 case WeaponProc:
-                    effectModifier.min = Float.parseFloat(modValues.get(1).trim());
-                    effectModifier.arg1 = modValues.get(2).trim();
-                    effectModifier.scale = Float.parseFloat(modValues.get(3).trim());
+                    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: " + effectModifier.type);
+                    Logger.error("Unhandled type: " + modifierEntry.type);
                     break;
             }
         }
 
-        return effectModifier;
+        return modifierEntry;
     }
 
 }
diff --git a/src/engine/wpak/PowerActionParser.java b/src/engine/wpak/PowerActionParser.java
index 6b669532..0815dd3b 100644
--- a/src/engine/wpak/PowerActionParser.java
+++ b/src/engine/wpak/PowerActionParser.java
@@ -10,8 +10,8 @@ package engine.wpak;
 
 import engine.gameManager.ConfigManager;
 import engine.mbEnums;
-import engine.wpak.data.EffectDescription;
-import engine.wpak.data.PowerActionEntry;
+import engine.wpak.data.Effect;
+import engine.wpak.data.PowerAction;
 import engine.wpak.data.StatTransfer;
 import engine.wpak.data.TrackEntry;
 import org.pmw.tinylog.Logger;
@@ -51,15 +51,15 @@ public class PowerActionParser {
 
         while (matcher.find()) {
 
-            PowerActionEntry powerActionEntry = parsePowerActionEntry(matcher.group().trim());
+            PowerAction powerAction = parsePowerActionEntry(matcher.group().trim());
 
         }
     }
 
-    private static PowerActionEntry parsePowerActionEntry(String powerActionData) {
+    private static PowerAction parsePowerActionEntry(String powerActionData) {
 
-        PowerActionEntry powerActionEntry = new PowerActionEntry();
-        EffectDescription effectDescription;
+        PowerAction powerAction = new PowerAction();
+        Effect effect;
         StatTransfer statTransfer;
         TrackEntry trackEntry;
 
@@ -81,34 +81,34 @@ public class PowerActionParser {
             headerData.add(matcher.group().trim());
 
         Iterator<String> headerIterator = headerData.iterator();
-        powerActionEntry.action_id = headerIterator.next();
-        powerActionEntry.action_type = headerIterator.next();
+        powerAction.action_id = headerIterator.next();
+        powerAction.action_type = headerIterator.next();
 
-        switch (powerActionEntry.action_type) {
+        switch (powerAction.action_type) {
             case "RemoveEffect":
-                effectDescription = new EffectDescription();
-                effectDescription.effect_id = headerIterator.next();
-                powerActionEntry.effects.add(effectDescription);
+                effect = new Effect();
+                effect.effect_id = headerIterator.next();
+                powerAction.effects.add(effect);
                 break;
             case "CreateMob":
-                powerActionEntry.petLevel = Integer.parseInt(headerIterator.next());
-                powerActionEntry.petRace = Integer.parseInt(headerIterator.next());
+                powerAction.petLevel = Integer.parseInt(headerIterator.next());
+                powerAction.petRace = Integer.parseInt(headerIterator.next());
                 break;
             case "DamageOverTime":
-                effectDescription = new EffectDescription();
-                effectDescription.effect_id = headerIterator.next();
-                effectDescription.cycleDuration = Integer.parseInt(headerIterator.next());
-                effectDescription.cycleDelay = Integer.parseInt(headerIterator.next());
-                powerActionEntry.effects.add(effectDescription);
+                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()) {
-                    effectDescription = new EffectDescription();
-                    effectDescription.level = level;
-                    effectDescription.effect_id = headerIterator.next();
-                    powerActionEntry.effects.add(effectDescription);
+                    effect = new Effect();
+                    effect.level = level;
+                    effect.effect_id = headerIterator.next();
+                    powerAction.effects.add(effect);
                 }
                 break;
             case "Transform":
@@ -118,15 +118,15 @@ public class PowerActionParser {
             case "DirectDamage":
             case "SpireDisable":
                 while (headerIterator.hasNext()) {
-                    effectDescription = new EffectDescription();
-                    effectDescription.effect_id = headerIterator.next();
+                    effect = new Effect();
+                    effect.effect_id = headerIterator.next();
 
                     // Some applyEffect entries are naked withot a level
 
                     if (headerData.size() > 3)
-                        effectDescription.level = Integer.parseInt(headerIterator.next());
+                        effect.level = Integer.parseInt(headerIterator.next());
 
-                    powerActionEntry.effects.add(effectDescription);
+                    powerAction.effects.add(effect);
                 }
                 break;
             case "TransferStat":
@@ -139,7 +139,7 @@ public class PowerActionParser {
                 statTransfer.toCurve = mbEnums.CompoundCurveType.valueOf(headerIterator.next());
                 statTransfer.fromStatBool = Boolean.parseBoolean(headerIterator.next());
                 statTransfer.toStatBool = Boolean.parseBoolean(headerIterator.next());
-                powerActionEntry.statTransfer = statTransfer;
+                powerAction.statTransfer = statTransfer;
                 break;
             case "TransferStatOT":
                 statTransfer = new StatTransfer();
@@ -153,26 +153,26 @@ public class PowerActionParser {
                 statTransfer.toStatBool = Boolean.parseBoolean(headerIterator.next());
                 statTransfer.transfer_action = headerIterator.next();
                 statTransfer.transfer_ticks = Integer.parseInt(headerIterator.next());
-                powerActionEntry.statTransfer = statTransfer;
+                powerAction.statTransfer = statTransfer;
                 break;
             case "Charm":
-                effectDescription = new EffectDescription();
-                effectDescription.effect_id = headerIterator.next();
-                effectDescription.level = Integer.parseInt(headerIterator.next());
-                effectDescription.type = headerIterator.next();
-                powerActionEntry.effects.add(effectDescription);
+                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":
-                effectDescription = new EffectDescription();
-                effectDescription.effect_id = headerIterator.next();
-                effectDescription.level = Integer.parseInt(headerIterator.next());
-                powerActionEntry.effects.add(effectDescription);
+                effect = new Effect();
+                effect.effect_id = headerIterator.next();
+                effect.level = Integer.parseInt(headerIterator.next());
+                powerAction.effects.add(effect);
                 break;
             case "Resurrect":
-                powerActionEntry.levelCap = Integer.parseInt(headerIterator.next());
+                powerAction.levelCap = Integer.parseInt(headerIterator.next());
                 break;
             case "SetItemFlag":
-                powerActionEntry.itemFlag = mbEnums.ItemFlags.valueOf(headerIterator.next());
+                powerAction.itemFlag = mbEnums.ItemFlags.valueOf(headerIterator.next());
                 break;
             case "Track":
                 trackEntry = new TrackEntry();
@@ -182,7 +182,7 @@ public class PowerActionParser {
                 trackEntry.type = headerIterator.next();
                 trackEntry.min = Integer.parseInt(headerIterator.next());
                 trackEntry.max = Integer.parseInt(headerIterator.next());
-                powerActionEntry.trackEntry = trackEntry;
+                powerAction.trackEntry = trackEntry;
                 break;
             case "Recall": // No arguments for these tags or not parsed
             case "Summon":
@@ -198,7 +198,7 @@ public class PowerActionParser {
             case "Steal":
                 break;
             default:
-                Logger.error("Unhandled type " + powerActionEntry.action_type + " for Pow4erAction: " + powerActionEntry.action_id);
+                Logger.error("Unhandled type " + powerAction.action_type + " for Pow4erAction: " + powerAction.action_id);
                 break;
         }
 
@@ -215,81 +215,81 @@ public class PowerActionParser {
                     arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+"));
 
                     for (String bodyPart : arguments)
-                        powerActionEntry.bodyparts.add(Integer.parseInt(bodyPart));
+                        powerAction.bodyparts.add(Integer.parseInt(bodyPart));
                     break;
                 case "FEMALEBODYPARTS":
                     arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+"));
 
                     for (String bodyPart : arguments)
-                        powerActionEntry.femaleBodyParts.add(Integer.parseInt(bodyPart));
+                        powerAction.femaleBodyParts.add(Integer.parseInt(bodyPart));
                     break;
                 case "SCALEFACTOR":
                     arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+"));
 
                     for (String scaleFactor : arguments)
-                        powerActionEntry.scaleFactor.add(Float.parseFloat(scaleFactor));
+                        powerAction.scaleFactor.add(Float.parseFloat(scaleFactor));
                     break;
                 case "ISRESISTABLE":
-                    powerActionEntry.isResistible = Boolean.parseBoolean(lineValues.get(1).trim());
+                    powerAction.isResistible = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "ISAGGRESSIVE":
-                    powerActionEntry.isAggressive = Boolean.parseBoolean(lineValues.get(1).trim());
+                    powerAction.isAggressive = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "BLADETRAILS":
-                    powerActionEntry.bladeTrails = Boolean.parseBoolean(lineValues.get(1).trim());
+                    powerAction.bladeTrails = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "SHOULDSHOWWEAPONS":
-                    powerActionEntry.shouldShowWeapons = Boolean.parseBoolean(lineValues.get(1).trim());
+                    powerAction.shouldShowWeapons = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "SHOULDSHOWARMOR":
-                    powerActionEntry.shouldShowArmor = Boolean.parseBoolean(lineValues.get(1).trim());
+                    powerAction.shouldShowArmor = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "APPLYEFFECTBLANK":
-                    powerActionEntry.applyEffectBlank = Boolean.parseBoolean(lineValues.get(1).trim());
+                    powerAction.applyEffectBlank = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "WEAROFFEFFECTBLANK":
-                    powerActionEntry.wearOffEffectBlank = Boolean.parseBoolean(lineValues.get(1).trim());
+                    powerAction.wearOffEffectBlank = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "ATTACKANIMS":
                     arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+"));
 
                     for (String animation : arguments)
-                        powerActionEntry.attackAnimations.add(Integer.parseInt(animation));
+                        powerAction.attackAnimations.add(Integer.parseInt(animation));
                     break;
                 case "REMOVEALL":
-                    powerActionEntry.removeAll = Boolean.parseBoolean(lineValues.get(1).trim());
+                    powerAction.removeAll = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "EFFECTID":
-                    effectDescription = new EffectDescription();
-                    effectDescription.effect_id = lineValues.get(1).trim();
-                    powerActionEntry.effects.add(effectDescription);
+                    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+"));
-                    powerActionEntry.levelCap = Integer.parseInt(arguments.get(0));
+                    powerAction.levelCap = Integer.parseInt(arguments.get(0));
 
                     if (arguments.size() > 1)  // Not all level caps have a curve
-                        powerActionEntry.levelCurve = mbEnums.CompoundCurveType.valueOf(arguments.get(1));
+                        powerAction.levelCurve = mbEnums.CompoundCurveType.valueOf(arguments.get(1));
                     break;
                 case "CLEARAGGRO":
-                    powerActionEntry.clearAggro = Boolean.parseBoolean(lineValues.get(1).trim());
+                    powerAction.clearAggro = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "TARGETBECOMESPET":
-                    powerActionEntry.targetBecomesPet = Boolean.parseBoolean(lineValues.get(1).trim());
+                    powerAction.targetBecomesPet = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "DESTROYOLDPET":
-                    powerActionEntry.destroyOldPet = Boolean.parseBoolean(lineValues.get(1).trim());
+                    powerAction.destroyOldPet = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "DAMAGETYPE":
-                    powerActionEntry.damageType = mbEnums.DamageType.valueOf(lineValues.get(1).trim().toUpperCase());
+                    powerAction.damageType = mbEnums.DamageType.valueOf(lineValues.get(1).trim().toUpperCase());
                     break;
                 case "ROOTFSMID":
-                    powerActionEntry.rootFsmID = mbEnums.MobBehaviourType.valueOf(lineValues.get(1).trim());
+                    powerAction.rootFsmID = mbEnums.MobBehaviourType.valueOf(lineValues.get(1).trim());
                     break;
                 case "SPLASHDAMAGE":
                     arguments = Arrays.asList(lineValues.get(1).trim().split("\\s+"));
-                    powerActionEntry.splashDamageMin = Integer.parseInt(arguments.get(0));
-                    powerActionEntry.splashDamageMax = Integer.parseInt(arguments.get(1));
+                    powerAction.splashDamageMin = Integer.parseInt(arguments.get(0));
+                    powerAction.splashDamageMax = Integer.parseInt(arguments.get(1));
                     break;
                 case "APPLYEFFECTOTHER":
                 case "APPLYEFFECTSELF":
@@ -297,9 +297,9 @@ public class PowerActionParser {
                 case "WEAROFFEFFECTSELF":
                     break;
                 default:
-                    Logger.error("Unhandled variable type:" + key + " for powerAction: " + powerActionEntry.action_id);
+                    Logger.error("Unhandled variable type:" + key + " for powerAction: " + powerAction.action_id);
             }
         }
-        return powerActionEntry;
+        return powerAction;
     }
 }
diff --git a/src/engine/wpak/PowersParser.java b/src/engine/wpak/PowersParser.java
index 15e6656b..b722de3b 100644
--- a/src/engine/wpak/PowersParser.java
+++ b/src/engine/wpak/PowersParser.java
@@ -49,14 +49,14 @@ public class PowersParser {
 
         while (matcher.find()) {
 
-            PowerEntry powerEntry = parsePowerEntry(matcher.group().trim());
+            Power power = parsePowerEntry(matcher.group().trim());
 
         }
     }
 
-    private static PowerEntry parsePowerEntry(String powerData) {
+    private static Power parsePowerEntry(String powerData) {
 
-        PowerEntry powerEntry = new PowerEntry();
+        Power powerEntry = new Power();
         StringBuilder conditionBuilder = new StringBuilder();
         StringBuilder powerBuilder = new StringBuilder();
         String conditionString;
@@ -101,7 +101,7 @@ public class PowersParser {
         powerEntry.power_id = iterator.next();
         powerEntry.power = iterator.next().replaceAll("\"", "");
 
-        PowerData power = new PowerData();
+        PowerEntry power = new PowerEntry();
         power.power_type = mbEnums.PowerType.valueOf(iterator.next());
         power.icon = Integer.parseInt(iterator.next());
         power.powerBase = iterator.next().replaceAll("\"", "");
@@ -112,7 +112,7 @@ public class PowersParser {
         // Account for second definition
 
         if (nextValue.equals("SPELL") || nextValue.equals("SKILL")) {
-            power = new PowerData();
+            power = new PowerEntry();
             power.power_type = mbEnums.PowerType.valueOf(nextValue);
             power.icon = Integer.parseInt(iterator.next());
             power.powerBase = iterator.next().replaceAll("\"", "");
@@ -222,7 +222,7 @@ public class PowersParser {
                     powerEntry.bladeTrails = Boolean.parseBoolean(lineValues.get(1).trim());
                     break;
                 case "EFFECTPREREQ":
-                    EffectDescription effectPreReq = new EffectDescription();
+                    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));
@@ -268,7 +268,7 @@ public class PowersParser {
                     powerEntry.casterPulseParticle = Integer.parseInt(lineValues.get(1).trim());
                     break;
                 case "TARGETEFFECTPREREQS_ORED":
-                    EffectDescription preReq = new EffectDescription();
+                    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));
diff --git a/src/engine/wpak/data/EffectEntry.java b/src/engine/wpak/data/Effect.java
similarity index 80%
rename from src/engine/wpak/data/EffectEntry.java
rename to src/engine/wpak/data/Effect.java
index 188340ae..8fa8170a 100644
--- a/src/engine/wpak/data/EffectEntry.java
+++ b/src/engine/wpak/data/Effect.java
@@ -13,16 +13,25 @@ import engine.powers.effectmodifiers.AbstractEffectModifier;
 import java.util.ArrayList;
 import java.util.HashSet;
 
-public class EffectEntry {
+public class Effect {
     public String effect_id;
     public String effect_name;
     public int icon;
     public HashSet<String> sources = new HashSet<>();
-    public ArrayList<EffectModifier> mods = new ArrayList<>();
+    public ArrayList<ModifierEntry> mods = new ArrayList<>();
     public ArrayList<ConditionEntry> 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;
 }
diff --git a/src/engine/wpak/data/EffectDescription.java b/src/engine/wpak/data/EffectDescription.java
deleted file mode 100644
index c3c778f2..00000000
--- a/src/engine/wpak/data/EffectDescription.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// • ▌ ▄ ·.  ▄▄▄·  ▄▄ • ▪   ▄▄· ▄▄▄▄·  ▄▄▄·  ▐▄▄▄  ▄▄▄ .
-// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
-// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
-// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
-// ▀▀  █▪▀▀▀ ▀  ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀  ▀  ▀ ▀▀  █▪ ▀▀▀
-//      Magicbane Emulator Project © 2013 - 2024
-//                www.magicbane.com
-
-package engine.wpak.data;
-
-public class EffectDescription {
-    public String effect_id;
-    public String type;
-    public int level;
-    public String message;
-    public int cycleDuration;
-    public int cycleDelay;
-}
diff --git a/src/engine/wpak/data/EffectModifier.java b/src/engine/wpak/data/ModifierEntry.java
similarity index 95%
rename from src/engine/wpak/data/EffectModifier.java
rename to src/engine/wpak/data/ModifierEntry.java
index abb1b3ff..d67d8a00 100644
--- a/src/engine/wpak/data/EffectModifier.java
+++ b/src/engine/wpak/data/ModifierEntry.java
@@ -10,11 +10,11 @@ package engine.wpak.data;
 
 import engine.mbEnums;
 
-public class EffectModifier {
+public class ModifierEntry {
     public mbEnums.ModType type;
     public float min;
     public float max;
-    public float scale;
+    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..90efcac5
--- /dev/null
+++ b/src/engine/wpak/data/Power.java
@@ -0,0 +1,69 @@
+// • ▌ ▄ ·.  ▄▄▄·  ▄▄ • ▪   ▄▄· ▄▄▄▄·  ▄▄▄·  ▐▄▄▄  ▄▄▄ .
+// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
+// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
+// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
+// ▀▀  █▪▀▀▀ ▀  ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀  ▀  ▀ ▀▀  █▪ ▀▀▀
+//      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;
+
+public class Power {
+    public String power_id;
+    public String power;
+    public ArrayList<PowerEntry> 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<ActionEntry> actionEntries = new ArrayList<>();
+    public int maxLevel;
+    public int hateValue;
+    public mbEnums.CompoundCurveType hateCurve = mbEnums.CompoundCurveType.DefaultFlat;
+    public int loopAnimID;
+    public String grantOverrideVar;
+    public ArrayList<String> description = new ArrayList<>();
+    public HashMap<String, mbEnums.CompoundCurveType> curves = new HashMap<>();
+    public String category;
+    public boolean canCastWhileMoving = false;
+    public boolean bladeTrails = false;
+    public ArrayList<Effect> effectPreReqs = new ArrayList<>();
+    public ArrayList<EquipmentPreReq> equipmentPreReq = new ArrayList<>();
+    public EnumSet<mbEnums.MonsterType> monsterRestricts = EnumSet.noneOf(mbEnums.MonsterType.class);
+    public EnumSet<mbEnums.MonsterType> 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<Effect> targetEffectPrereqs = new ArrayList<>();
+    public boolean canCastWhileFlying = false;
+    public boolean isProjectile = false;
+    public HashMap<String, Float> conditions = new HashMap<>();
+
+}
diff --git a/src/engine/wpak/data/PowerActionEntry.java b/src/engine/wpak/data/PowerAction.java
similarity index 95%
rename from src/engine/wpak/data/PowerActionEntry.java
rename to src/engine/wpak/data/PowerAction.java
index 0b2aeceb..d56a03f6 100644
--- a/src/engine/wpak/data/PowerActionEntry.java
+++ b/src/engine/wpak/data/PowerAction.java
@@ -12,13 +12,13 @@ import engine.mbEnums;
 
 import java.util.ArrayList;
 
-public class PowerActionEntry {
+public class PowerAction {
 
     // Header values
 
     public String action_id;
     public String action_type;
-    public ArrayList<EffectDescription> effects = new ArrayList<>();
+    public ArrayList<Effect> effects = new ArrayList<>();
     public int petLevel;
     public int petRace;
     public StatTransfer statTransfer;
diff --git a/src/engine/wpak/data/PowerData.java b/src/engine/wpak/data/PowerData.java
deleted file mode 100644
index af98c498..00000000
--- a/src/engine/wpak/data/PowerData.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// • ▌ ▄ ·.  ▄▄▄·  ▄▄ • ▪   ▄▄· ▄▄▄▄·  ▄▄▄·  ▐▄▄▄  ▄▄▄ .
-// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
-// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
-// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
-// ▀▀  █▪▀▀▀ ▀  ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀  ▀  ▀ ▀▀  █▪ ▀▀▀
-//      Magicbane Emulator Project © 2013 - 2024
-//                www.magicbane.com
-
-package engine.wpak.data;
-
-import engine.mbEnums;
-
-public class PowerData {
-    public mbEnums.PowerType power_type;
-    public int icon;
-    public String powerBase;
-}
diff --git a/src/engine/wpak/data/PowerEntry.java b/src/engine/wpak/data/PowerEntry.java
index 6a240726..fb805faa 100644
--- a/src/engine/wpak/data/PowerEntry.java
+++ b/src/engine/wpak/data/PowerEntry.java
@@ -10,60 +10,8 @@ package engine.wpak.data;
 
 import engine.mbEnums;
 
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.HashMap;
-
 public class PowerEntry {
-    public String power_id;
-    public String power;
-    public ArrayList<PowerData> 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<ActionEntry> actionEntries = new ArrayList<>();
-    public int maxLevel;
-    public int hateValue;
-    public mbEnums.CompoundCurveType hateCurve = mbEnums.CompoundCurveType.DefaultFlat;
-    public int loopAnimID;
-    public String grantOverrideVar;
-    public ArrayList<String> description = new ArrayList<>();
-    public HashMap<String, mbEnums.CompoundCurveType> curves = new HashMap<>();
-    public String category;
-    public boolean canCastWhileMoving = false;
-    public boolean bladeTrails = false;
-    public ArrayList<EffectDescription> effectPreReqs = new ArrayList<>();
-    public ArrayList<EquipmentPreReq> equipmentPreReq = new ArrayList<>();
-    public EnumSet<mbEnums.MonsterType> monsterRestricts = EnumSet.noneOf(mbEnums.MonsterType.class);
-    public EnumSet<mbEnums.MonsterType> 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<EffectDescription> targetEffectPrereqs = new ArrayList<>();
-    public boolean canCastWhileFlying = false;
-    public boolean isProjectile = false;
-    public HashMap<String, Float> conditions = new HashMap<>();
-
+    public mbEnums.PowerType power_type;
+    public int icon;
+    public String powerBase;
 }