diff --git a/src/engine/gameManager/PowersManager.java b/src/engine/gameManager/PowersManager.java index 6e833886..91c0bd2a 100644 --- a/src/engine/gameManager/PowersManager.java +++ b/src/engine/gameManager/PowersManager.java @@ -11,7 +11,6 @@ package engine.gameManager; import engine.InterestManagement.Terrain; import engine.InterestManagement.WorldGrid; import engine.db.handlers.dbEffectsBaseHandler; -import engine.db.handlers.dbPowerHandler; import engine.db.handlers.dbSkillReqHandler; import engine.job.AbstractJob; import engine.job.AbstractScheduleJob; @@ -28,7 +27,9 @@ import engine.net.Dispatch; import engine.net.client.ClientConnection; import engine.net.client.msg.*; import engine.objects.*; +import engine.parsers.objects.wpak.EffectTemplate; import engine.parsers.objects.wpak.PowActionCostTemplate; +import engine.parsers.objects.wpak.PowerActionTemplate; import engine.parsers.objects.wpak.PowerTemplate; import engine.powers.*; import engine.powers.poweractions.AbstractPowerAction; @@ -41,6 +42,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; @@ -103,6 +105,42 @@ public enum PowersManager { Logger.info("Loaded " + PowersManager._effect_costMaps.size() + " effect cost maps from PowActionCostInfo.cfg"); } + // Effects.cfg in file order, then the ApplyEffect/ApplyEffects/Invis actions with no Effects.cfg block + private static void loadEffects() { + + int effectID = 0; + int actionKeyCount = 0; + PowerActionTemplate powerActionTemplate; + + for (EffectTemplate effectTemplate : EffectTemplate._effects.values()) + addEffect(new EffectsBase(effectTemplate, ++effectID)); + + for (String actionID : new TreeSet<>(PowerActionTemplate._powerActions.keySet())) { + + if (EffectTemplate._effects.containsKey(actionID)) + continue; + + powerActionTemplate = PowerActionTemplate._powerActions.get(actionID); + + switch (powerActionTemplate.action_type) { + case ApplyEffect: + case ApplyEffects: + case Invis: + addEffect(new EffectsBase(powerActionTemplate, ++effectID)); + actionKeyCount++; + break; + } + } + + Logger.info("Loaded " + EffectTemplate._effects.size() + " effects from Effects.cfg and " + + actionKeyCount + " effect keys from PowerActions.cfg"); + } + + private static void addEffect(EffectsBase effectsBase) { + PowersManager.effectsBaseByToken.put(effectsBase.getToken(), effectsBase); + PowersManager.effectsBaseByIDString.put(effectsBase.getIDString(), effectsBase); + } + // Powers.cfg target type wins over static_power_powerbase private static void applyClientTargetTypes() { @@ -153,24 +191,11 @@ public enum PowersManager { // This pre-loads all powers and effects public static void InitializePowers() { - // Add EffectsBase - ArrayList ebList = dbEffectsBaseHandler.getAllEffectsBase(); - - for (EffectsBase eb : ebList) { - PowersManager.effectsBaseByToken.put(eb.getToken(), eb); - PowersManager.effectsBaseByIDString.put(eb.getIDString(), eb); - - } - - // Add Fail Conditions - EffectsBase.getFailConditions(PowersManager.effectsBaseByIDString); + loadEffects(); // Add Modifiers to Effects dbEffectsBaseHandler.cacheAllEffectModifiers(); - // Add Source Types to Effects - dbPowerHandler.addAllSourceTypes(); - // Add PowerActions AbstractPowerAction.getAllPowerActions(PowersManager.powerActionsByIDString, PowersManager.powerActionsByID, PowersManager.effectsBaseByIDString); diff --git a/src/engine/mbEnums.java b/src/engine/mbEnums.java index e51f78e0..c2438ccd 100644 --- a/src/engine/mbEnums.java +++ b/src/engine/mbEnums.java @@ -1097,11 +1097,28 @@ public class mbEnums { public static EffectSourceType GetEffectSourceType(String modName) { EffectSourceType returnMod; + String name; + if (modName.isEmpty()) return EffectSourceType.None; + name = modName.replace(",", "").replace("-", "").trim(); + + // Effects.cfg SOURCE blocks use the short damage names + switch (name) { + case "Crush": + name = "Crushing"; + break; + case "Pierce": + name = "Piercing"; + break; + case "Slash": + name = "Slashing"; + break; + } + try { - returnMod = EffectSourceType.valueOf(modName.replace(",", "")); + returnMod = EffectSourceType.valueOf(name); } catch (Exception e) { Logger.error(e); return EffectSourceType.None; diff --git a/src/engine/parsers/wpak/EffectParser.java b/src/engine/parsers/wpak/EffectParser.java index 426ec872..c7ac4bcb 100644 --- a/src/engine/parsers/wpak/EffectParser.java +++ b/src/engine/parsers/wpak/EffectParser.java @@ -15,6 +15,7 @@ import org.pmw.tinylog.Logger; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; // Loads Effects.cfg. ModTypes.cfg and CompoundCurves.cfg must be loaded first: // a mod's argument layout comes from its behavior, and curve names are checked. @@ -25,7 +26,7 @@ public class EffectParser { public static HashMap parseEffectsFile() { - HashMap effects = new HashMap<>(); + HashMap effects = new LinkedHashMap<>(); WpakBlock root; EffectTemplate effect; int blockCount = 0; diff --git a/src/engine/powers/EffectsBase.java b/src/engine/powers/EffectsBase.java index 5861718d..af5dd9cf 100644 --- a/src/engine/powers/EffectsBase.java +++ b/src/engine/powers/EffectsBase.java @@ -28,8 +28,12 @@ import engine.objects.AbstractCharacter; import engine.objects.AbstractWorldObject; import engine.objects.Effect; import engine.objects.PlayerCharacter; +import engine.parsers.objects.wpak.CurveRamp; +import engine.parsers.objects.wpak.EffectTemplate; +import engine.parsers.objects.wpak.PowerActionTemplate; import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.server.MBServerStatics; +import engine.util.Hasher; import org.pmw.tinylog.Logger; import java.sql.Connection; @@ -123,6 +127,131 @@ public class EffectsBase { // getFailConditions(); } + public EffectsBase(EffectTemplate effectTemplate, int id) { + + this.UUID = id; + this.IDString = effectTemplate.effect_id; + this.name = effectTemplate.effect_name; + this.token = effectToken(this.IDString); + this.isItemEffect = effectTemplate.isitemeffect; + this.isSpireEffect = effectTemplate.isspireeffect; + this.ignoreMod = effectTemplate.ignorenomod; + this.dontSave = effectTemplate.dontsave; + this.isPrefix = this.IDString.startsWith("PRE-"); + this.isSuffix = this.IDString.startsWith("SUF-"); + + loadFailConditions(effectTemplate.conditions); + loadSourceTypes(effectTemplate.sources); + } + + // A power action with no Effects.cfg block that the server still keys as an effect: + // item enchantment parents (PRE-/SUF-/ARM-) and the action tokens sent in effect messages. + public EffectsBase(PowerActionTemplate powerActionTemplate, int id) { + + this.UUID = id; + this.IDString = powerActionTemplate.action_id; + this.token = effectToken(this.IDString); + this.isPrefix = this.IDString.startsWith("PRE-"); + this.isSuffix = this.IDString.startsWith("SUF-"); + } + + // INVIS-D and SafeMode show as the SafeModeB/A action tokens on the client + private static int effectToken(String IDString) { + + switch (IDString) { + case "INVIS-D": + return Hasher.SBStringHash("SafeModeB"); + case "SafeMode": + return Hasher.SBStringHash("SafeModeA"); + default: + return Hasher.SBStringHash(IDString); + } + } + + private void loadFailConditions(ArrayList conditions) { + + CurveRamp curveRamp; + + if (conditions.isEmpty()) + return; + + if (!EffectsBase.EffectFailConditions.containsKey(this.IDString)) + EffectsBase.EffectFailConditions.put(this.IDString, new HashSet<>()); + + for (EffectTemplate.ConditionEntry condition : conditions) { + + EffectsBase.EffectFailConditions.get(this.IDString).add(condition.condition); + + switch (condition.condition) { + case TakeDamage: + this.cancelOnTakeDamage = true; + this.amount = condition.amount; + + curveRamp = (condition.curve == null) ? null : CurveRamp.fromCurve(condition.curve); + + if (condition.curve != null && curveRamp == null) + Logger.warn("Effect " + this.IDString + " TakeDamage curve " + condition.curve + " has no ramp form"); + + this.amountRamp = (curveRamp == null) ? 0 : curveRamp.ramp; + this.useRampAdd = (curveRamp == null) || curveRamp.useAdd; + + if (condition.damage_types.isEmpty()) + break; + + if (!EffectsBase.EffectDamageTypes.containsKey(this.token)) + EffectsBase.EffectDamageTypes.put(this.token, new HashSet<>()); + + EffectsBase.EffectDamageTypes.get(this.token).addAll(condition.damage_types); + break; + case Attack: + this.cancelOnAttack = true; + break; + case AttackSwing: + this.cancelOnAttackSwing = true; + break; + case Cast: + this.cancelOnCast = true; + break; + case CastSpell: + this.cancelOnCastSpell = true; + break; + case EquipChange: + this.cancelOnEquipChange = true; + break; + case Logout: + this.cancelOnLogout = true; + break; + case Move: + this.cancelOnMove = true; + break; + case NewCharm: + this.cancelOnNewCharm = true; + break; + case Sit: + this.cancelOnSit = true; + break; + case TerritoryClaim: + this.cancelOnTerritoryClaim = true; + break; + case UnEquip: + this.cancelOnUnEquip = true; + break; + } + } + } + + private void loadSourceTypes(ArrayList sources) { + + if (sources.isEmpty()) + return; + + if (!EffectsBase.effectSourceTypeMap.containsKey(this.token)) + EffectsBase.effectSourceTypeMap.put(this.token, new HashSet<>()); + + for (String source : sources) + EffectsBase.effectSourceTypeMap.get(this.token).add(EffectSourceType.GetEffectSourceType(source)); + } + public static void getFailConditions(HashMap effects) { try (Connection connection = DbManager.getConnection();