// • ▌ ▄ ·.  ▄▄▄·  ▄▄ • ▪   ▄▄· ▄▄▄▄·  ▄▄▄·  ▐▄▄▄  ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀  █▪▀▀▀ ▀  ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀  ▀  ▀ ▀▀  █▪ ▀▀▀
//      Magicbane Emulator Project © 2013 - 2022
//                www.magicbane.com


package engine.powers;

import engine.gameManager.DispatchManager;
import engine.gameManager.PowersManager;
import engine.job.JobContainer;
import engine.jobs.AbstractEffectJob;
import engine.jobs.DamageOverTimeJob;
import engine.jobs.FinishSpireEffectJob;
import engine.jobs.NoTimeJob;
import engine.mbEnums;
import engine.mbEnums.EffectSourceType;
import engine.mbEnums.GameObjectType;
import engine.mbEnums.PowerFailCondition;
import engine.net.Dispatch;
import engine.net.client.ClientConnection;
import engine.net.client.msg.ApplyEffectMsg;
import engine.objects.*;
import engine.powers.effectmodifiers.*;
import engine.server.MBServerStatics;
import engine.util.Hasher;
import engine.wpak.data.ConditionEntry;
import engine.wpak.data.Effect;
import engine.wpak.data.ModifierEntry;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;

public class EffectsBase {
    private static final ConcurrentHashMap<String, String> itemEffectsByName = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
    public static int NewID = 3000;
    public int UUID;
    public String IDString;
    // public String name;
    public int token;
    public float amount;
    public float amountRamp;
    // flags
    public boolean isItemEffect;
    public boolean isSpireEffect;
    public boolean ignoreNoMod;
    public boolean dontSave;
    public boolean cancelOnAttack = false;
    public boolean cancelOnAttackSwing = false;
    public boolean cancelOnCast = false;
    public boolean cancelOnCastSpell = false;
    public boolean cancelOnEquipChange = false;
    public boolean cancelOnLogout = false;
    public boolean cancelOnMove = false;
    public boolean cancelOnNewCharm = false;
    public boolean cancelOnSit = false;
    public boolean cancelOnTakeDamage = false;
    public boolean cancelOnTerritoryClaim = false;
    public boolean cancelOnUnEquip = false;
    public boolean useRampAdd;
    public boolean isPrefix = false; //used by items
    public boolean isSuffix = false; //used by items
    public String name = "";
    public float value = 0;
    private ConcurrentHashMap<mbEnums.ResourceType, Integer> resourceCosts = new ConcurrentHashMap<>();

    //loaded values from parser
    public HashSet<EffectSourceType> effectSources = new HashSet<>();
    public HashSet<AbstractEffectModifier> effectModifiers = new HashSet<>();
    public HashSet<PowerFailCondition> effectFailCondition = new HashSet<>();

    public  HashSet<mbEnums.DamageType> effectDamageTypes = new HashSet<>();

    /**
     * No Table ID Constructor
     */
    public EffectsBase() {

    }

    /**
     * EffectEntry Constructor
     */

    public EffectsBase(Effect entry) {
        this.IDString = entry.effect_id;
        this.name = entry.effect_name;
        this.token = Hasher.SBStringHash(entry.effect_name);

        //override tokens for some effects like Safemode that use the Action Token instead of the effect Token,
        switch (this.IDString) {
            case "INVIS-D":
                this.token = -1661751254;
                break;
            case "SafeMode":
                this.token = -1661750486;
                break;

        }
        this.isItemEffect = entry.isItemEffect;
        this.isSpireEffect = entry.isSpireEffect;
        this.ignoreNoMod = entry.ignoreNoMod;
        this.dontSave = entry.dontSave;

        if (this.IDString.startsWith("PRE-"))
            this.isPrefix = true;
        else if (this.IDString.startsWith("SUF-"))
            this.isSuffix = true;

        //load effect modifiers
        for (ModifierEntry mod : entry.mods)
            this.effectModifiers.add(getCombinedModifiers(null, mod, this, mod.type));

        //load sources
        for (String source : entry.sources)
            this.effectSources.add(EffectSourceType.GetEffectSourceType(source));

        //load fail conditions
        for (ConditionEntry condition : entry.conditions) {
            PowerFailCondition failCondition = PowerFailCondition.valueOf(condition.condition);
            this.effectFailCondition.add(failCondition);
            loadFailConditions(failCondition, this, condition);

            //add all damage types
            if(!condition.damageTypes.isEmpty())
                this.effectDamageTypes.addAll(condition.damageTypes);
        }


    }

    public static void loadFailConditions(PowerFailCondition failCondition, EffectsBase eb, ConditionEntry entry) {

        if (failCondition == null || eb == null) {
            return;
        }

        switch (failCondition) {

            case TakeDamage:

                eb.cancelOnTakeDamage = true;


                eb.amount = entry.arg;
                eb.amountRamp = (float) entry.curveType.getValue();
                eb.useRampAdd = (float) entry.curveType.getValue() != 0;
                break;
            case Attack:
                eb.cancelOnAttack = true;
                break;
            case AttackSwing:
                eb.cancelOnAttackSwing = true;
                break;
            case Cast:
                eb.cancelOnCast = true;
                break;
            case CastSpell:
                eb.cancelOnCastSpell = true;
                break;
            case EquipChange:
                eb.cancelOnEquipChange = true;
                break;
            case Logout:
                eb.cancelOnLogout = true;
                break;
            case Move:
                eb.cancelOnMove = true;
                break;
            case NewCharm:
                eb.cancelOnNewCharm = true;
                break;
            case Sit:
                eb.cancelOnSit = true;
                break;
            case TerritoryClaim:
                eb.cancelOnTerritoryClaim = true;
                break;
            case UnEquip:
                eb.cancelOnUnEquip = true;
                break;
        }
    }

    public EffectsBase(EffectsBase copyEffect, int newToken, String IDString) {

        UUID = NewID++;
        this.IDString = IDString;
        this.token = newToken;

        //filll
        if (copyEffect == null) {
            int flags = 0;
            this.isItemEffect = ((flags & 1) != 0) ? true : false;
            this.isSpireEffect = ((flags & 2) != 0) ? true : false;
            this.ignoreNoMod = ((flags & 4) != 0) ? true : false;
            this.dontSave = ((flags & 8) != 0) ? true : false;

            if (this.IDString.startsWith("PRE-"))
                this.isPrefix = true;
            else if (this.IDString.startsWith("SUF-"))
                this.isSuffix = true;

        }


        this.amount = copyEffect.amount;
        this.amountRamp = copyEffect.amountRamp;
        this.isItemEffect = copyEffect.isItemEffect;
        this.isSpireEffect = copyEffect.isSpireEffect;
        this.ignoreNoMod = copyEffect.ignoreNoMod;
        this.dontSave = copyEffect.dontSave;
        this.cancelOnAttack = copyEffect.cancelOnAttack;
        this.cancelOnAttackSwing = copyEffect.cancelOnAttackSwing;
        this.cancelOnCast = copyEffect.cancelOnCast;
        this.cancelOnCastSpell = copyEffect.cancelOnCastSpell;
        this.cancelOnEquipChange = copyEffect.cancelOnEquipChange;
        this.cancelOnLogout = copyEffect.cancelOnLogout;
        this.cancelOnMove = copyEffect.cancelOnMove;
        this.cancelOnNewCharm = copyEffect.cancelOnNewCharm;
        this.cancelOnSit = copyEffect.cancelOnSit;
        this.cancelOnTakeDamage = copyEffect.cancelOnTakeDamage;
        this.cancelOnTerritoryClaim = copyEffect.cancelOnTerritoryClaim;
        this.cancelOnUnEquip = copyEffect.cancelOnUnEquip;
        this.useRampAdd = copyEffect.useRampAdd;
        this.isPrefix = copyEffect.isPrefix;
        this.isSuffix = copyEffect.isSuffix;
        this.name = copyEffect.name;
        this.value = copyEffect.value;
        this.resourceCosts = copyEffect.resourceCosts;

    }

    /**
     * ResultSet Constructor
     */
    public EffectsBase(ResultSet rs) throws SQLException {

        this.UUID = rs.getInt("ID");
        this.IDString = rs.getString("IDString");
        this.name = rs.getString("name");
        this.token = rs.getInt("Token");

        //override tokens for some effects like Safemode that use the Action Token instead of the effect Token,
        switch (this.IDString) {
            case "INVIS-D":
                this.token = -1661751254;
                break;
            case "SafeMode":
                this.token = -1661750486;
                break;

        }
        int flags = rs.getInt("flags");
        this.isItemEffect = ((flags & 1) != 0) ? true : false;
        this.isSpireEffect = ((flags & 2) != 0) ? true : false;
        this.ignoreNoMod = ((flags & 4) != 0) ? true : false;
        this.dontSave = ((flags & 8) != 0) ? true : false;

        if (this.IDString.startsWith("PRE-"))
            this.isPrefix = true;
        else if (this.IDString.startsWith("SUF-"))
            this.isSuffix = true;
        // getFailConditions();
    }

    public static String getItemEffectsByName(String string) {
        if (EffectsBase.itemEffectsByName.containsKey(string))
            return EffectsBase.itemEffectsByName.get(string);
        return "";
    }

    public static void addItemEffectsByName(String name, String ID) {
        EffectsBase.itemEffectsByName.put(name, ID);
    }

    public float getDamageAmount(int trains) {
        if (useRampAdd)
            return (amount + (amountRamp * trains));
        else
            return (amount * (1 + (amountRamp * trains)));
    }

    // public String getName() {
    // return this.name;
    // }

    public boolean damageTypeSpecific() {

        return !this.effectDamageTypes.isEmpty();

    }

    public boolean containsDamageType(mbEnums.DamageType dt) {
        return this.effectDamageTypes.contains(dt);
    }

    public int getUUID() {
        return this.UUID;
    }

    public String getIDString() {
        return this.IDString;
    }

    public int getToken() {
        return this.token;
    }

    //For Debugging purposes.
    public void setToken(int token) {
        this.token = token;
    }

    public HashSet<AbstractEffectModifier> getModifiers() {
        return this.effectModifiers;
    }

    public boolean isPrefix() {
        return this.isPrefix;
    }

    public boolean isSuffix() {
        return this.isSuffix;
    }

    public void startEffect(AbstractCharacter source, AbstractWorldObject awo, int trains, AbstractEffectJob effect) {


        // Add SourceTypes for dispel

        if (this.token != 0) {
            if (effect == null) {
                Logger.error("AbstractEffectModifier.applyEffectModifier: missing FinishEffectTimeJob");
                return;
            }
            // AbstractWorldObject source = effect.getSource();
            if (source == null) {
                Logger.error("AbstractEffectModifier.applyEffectModifier: missing source");
                return;
            }
            PowersBase pb = effect.getPower();
            if (pb == null) {
                Logger.error("AbstractEffectModifier.applyEffectModifier: missing power");
                return;
            }
            ActionsBase ab = effect.getAction();
            if (ab == null) {
                Logger.error("AbstractEffectModifier.applyEffectModifier: missing action");
                return;
            }

            //don't send effect if dead, except for death shroud
            if (!awo.isAlive()) {
                if (pb.getToken() != 1672601862)
                    return;
            }


            if (!effect.skipSendEffect()) {
                //				float duration = (pb.isChant()) ? pb.getChantDuration() * 1000 : ab.getDuration(trains);
                float duration = ab.getDurationInSeconds(trains);
                if (pb.getToken() == 1672601862) {

                    engine.objects.Effect eff = awo.getEffects().get("DeathShroud");


                    if (eff != null) {
                        JobContainer jc = eff.getJobContainer();


                        if (jc != null) {
                            duration = jc.timeOfExection() - System.currentTimeMillis();
                            duration *= .001f;
                        }
                    }
                }


                if (duration > 0f) {
                    int removeToken = this.token;
                    ApplyEffectMsg pum = new ApplyEffectMsg();
                    if (effect.getAction() != null)
                        if (effect.getAction().getPowerAction() != null
                                && PowersManager.ActionTokenByIDString.containsKey(effect.getAction().getPowerAction().getIDString()))
                            try {
                                removeToken = PowersManager.ActionTokenByIDString.get(effect.getAction().getPowerAction().getIDString());
                            } catch (Exception e) {
                                removeToken = this.token;
                            }

                    pum.setEffectID(removeToken);
                    pum.setSourceType(source.getObjectType().ordinal());
                    pum.setSourceID(source.getObjectUUID());
                    pum.setTargetType(awo.getObjectType().ordinal());
                    pum.setTargetID(awo.getObjectUUID());
                    pum.setNumTrains(trains);
                    pum.setDuration((int) duration);
                    //					pum.setDuration((pb.isChant()) ? (int)pb.getChantDuration() : ab.getDurationInSeconds(trains));
                    pum.setPowerUsedID(pb.getToken());
                    pum.setPowerUsedName(pb.getName());
                    DispatchManager.sendToAllInRange(awo, pum);
                }

                if (awo.getObjectType().equals(GameObjectType.Item)) {
                    if (source.charItemManager != null) {
                        source.charItemManager.updateInventory();
                    }
                }
            }

            // call modifiers to do their job
            if (!effect.skipApplyEffect()) {
                for (AbstractEffectModifier em : this.getModifiers())
                    em.applyEffectModifier(source, awo, trains, effect);
            }
        }
    }

    // Send end effect message to client
    public void endEffect(AbstractWorldObject source, AbstractWorldObject awo, int trains, PowersBase pb, AbstractEffectJob effect) {
        if (awo == null) {
            Logger.error("endEffect(): Null AWO object passed in.");
            return;
        }
        if (pb == null) {
            Logger.error("endEffect(): Null PowerBase object passed in.");
            return;
        }
        if (!effect.skipCancelEffect() && !effect.isNoOverwrite()) {

            int sendToken = this.token;

            if (effect.getAction() != null)
                if (effect.getAction().getPowerAction() != null
                        && PowersManager.ActionTokenByIDString.containsKey(effect.getAction().getPowerAction().getIDString()))
                    try {
                        sendToken = PowersManager.ActionTokenByIDString.get(effect.getAction().getPowerAction().getIDString());
                    } catch (Exception e) {
                        sendToken = this.token;
                    }
            ApplyEffectMsg pum = new ApplyEffectMsg();
            pum.setEffectID(sendToken);
            if (source != null) {
                pum.setSourceType(source.getObjectType().ordinal());
                pum.setSourceID(source.getObjectUUID());
            } else {
                pum.setSourceType(0);
                pum.setSourceID(0);
            }
            pum.setTargetType(awo.getObjectType().ordinal());
            pum.setTargetID(awo.getObjectUUID());
            pum.setUnknown02(2);
            pum.setNumTrains(0);
            pum.setDuration(-1);
            pum.setPowerUsedID(pb.getToken());
            pum.setPowerUsedName(pb.getName());
            DispatchManager.sendToAllInRange(awo, pum);

        }
    }

    public void endEffectNoPower(int trains, AbstractEffectJob effect) {

        AbstractWorldObject source = effect.getSource();

        if (source == null)
            return;

        if (!effect.skipCancelEffect() && !effect.isNoOverwrite()) {
            ApplyEffectMsg pum = new ApplyEffectMsg();
            pum.setEffectID(this.token);

            pum.setSourceType(source.getObjectType().ordinal());
            pum.setSourceID(source.getObjectUUID());
            pum.setTargetType(source.getObjectType().ordinal());
            pum.setTargetID(source.getObjectUUID());
            pum.setUnknown02(2);
            pum.setNumTrains(0);
            pum.setDuration(-1);
            pum.setUnknown06((byte) 1);
            pum.setEffectSourceType(effect.getEffectSourceType());
            pum.setEffectSourceID(effect.getEffectSourceID());
            pum.setPowerUsedID(0);
            pum.setPowerUsedName(this.name);

            if (source.getObjectType() == GameObjectType.PlayerCharacter) {
                Dispatch dispatch = Dispatch.borrow((PlayerCharacter) source, pum);
                DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.PRIMARY);
            }
        }
    }

    public void sendEffect(AbstractEffectJob effect, int duration, ClientConnection conn) {
        if (effect == null && conn != null)
            return;

        if (conn == null)
            return;
        AbstractWorldObject source = effect.getSource();
        AbstractWorldObject awo = effect.getTarget();
        int trains = effect.getTrains();
        if (source == null || awo == null)
            return;

        if (this.token != 0) {
            PowersBase pb = effect.getPower();
            if (pb == null) {
                Logger.error("AbstractEffectModifier.applyEffectModifier: missing power");
                return;
            }
            ActionsBase ab = effect.getAction();
            if (ab == null) {
                Logger.error("AbstractEffectModifier.applyEffectModifier: missing action");
                return;
            }

            //don't send effect if dead, except for death shroud
            if (!awo.isAlive()) {
                if (pb.getToken() != 1672601862)
                    return;
            }

            //duration for damage over times is (total time - (number of ticks x 5 seconds per tick))
            if (effect instanceof DamageOverTimeJob)
                duration = ((DamageOverTimeJob) effect).getTickLength();

            //			float dur = (pb.isChant()) ? pb.getChantDuration() * 1000 : ab.getDuration(trains);
            float dur = ab.getDuration(trains);
            if (dur > 0f) {
                ApplyEffectMsg pum = new ApplyEffectMsg();
                pum.setEffectID(this.token);
                pum.setSourceType(source.getObjectType().ordinal());
                pum.setSourceID(source.getObjectUUID());
                pum.setTargetType(awo.getObjectType().ordinal());
                pum.setTargetID(awo.getObjectUUID());
                pum.setNumTrains(trains);
                pum.setDuration(duration);
                pum.setPowerUsedID(pb.getToken());
                pum.setPowerUsedName(pb.getName());

                Dispatch dispatch = Dispatch.borrow(conn.getPlayerCharacter(), pum);
                DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.PRIMARY);

            }
        }
    }

    public void sendEffectNoPower(AbstractEffectJob effect, int duration, ClientConnection conn) {

        if (effect == null && conn != null)
            return;

        if (conn == null)
            return;

        AbstractWorldObject source = effect.getSource();
        AbstractWorldObject awo = effect.getTarget();
        int trains = effect.getTrains();

        if (source == null || awo == null)
            return;

        if (this.token != 0) {
            //don't send effect if dead, except for death shroud
            if (!awo.isAlive()) {
                return;
            }

            //duration for damage over times is (total time - (number of ticks x 5 seconds per tick))
            if (effect instanceof DamageOverTimeJob)
                duration = ((DamageOverTimeJob) effect).getTickLength();
            else if (effect instanceof FinishSpireEffectJob)
                duration = 45;
            else if (effect instanceof NoTimeJob)
                duration = -1;

            //			float dur = (pb.isChant()) ? pb.getChantDuration() * 1000 : ab.getDuration(trains);

            ApplyEffectMsg pum = new ApplyEffectMsg();
            pum.setEffectID(this.token);
            pum.setSourceType(source.getObjectType().ordinal());
            pum.setSourceID(source.getObjectUUID());
            pum.setTargetType(source.getObjectType().ordinal());
            pum.setTargetID(source.getObjectUUID());
            pum.setUnknown06((byte) 1);
            pum.setEffectSourceType(effect.getEffectSourceType());
            pum.setEffectSourceID(effect.getEffectSourceID());
            pum.setNumTrains(trains);
            pum.setDuration(duration);
            pum.setPowerUsedID(0);
            pum.setPowerUsedName(this.name);

            Dispatch dispatch = Dispatch.borrow(conn.getPlayerCharacter(), pum);
            DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.PRIMARY);

        }
    }

    public boolean cancelOnAttack() {
        return this.cancelOnAttack;
    }

    public boolean cancelOnAttackSwing() {
        return this.cancelOnAttackSwing;
    }

    public boolean cancelOnCast() {
        return this.cancelOnCast;
    }

    public boolean cancelOnCastSpell() {
        return this.cancelOnCastSpell;
    }

    public boolean cancelOnEquipChange() {
        return this.cancelOnEquipChange;
    }

    public boolean cancelOnLogout() {
        return this.cancelOnLogout;
    }

    public boolean cancelOnMove() {
        return this.cancelOnMove;
    }

    public boolean cancelOnNewCharm() {
        return this.cancelOnNewCharm;
    }

    public boolean cancelOnSit() {
        return this.cancelOnSit;
    }

    public boolean cancelOnTakeDamage() {
        return this.cancelOnTakeDamage;
    }

    public boolean cancelOnTerritoryClaim() {
        return this.cancelOnTerritoryClaim;
    }

    public boolean cancelOnUnEquip() {
        return this.cancelOnUnEquip;
    }

    public String getName() {

        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static AbstractEffectModifier getCombinedModifiers(AbstractEffectModifier abstractEffectModifier, ModifierEntry rs, EffectsBase effectBase, mbEnums.ModType modifier){
        switch (modifier) {
            case AdjustAboveDmgCap:
                abstractEffectModifier = new AdjustAboveDmgCapEffectModifier(rs);
                break;
            case Ambidexterity:
                abstractEffectModifier = new AmbidexterityEffectModifier(rs);
                break;
            case AnimOverride:
                break;
            case ArmorPiercing:
                abstractEffectModifier = new ArmorPiercingEffectModifier(rs);
                break;
            case AttackDelay:
                abstractEffectModifier = new AttackDelayEffectModifier(rs);
                break;
            case Attr:
                abstractEffectModifier = new AttributeEffectModifier(rs);
                break;
            case BlackMantle:
                abstractEffectModifier = new BlackMantleEffectModifier(rs);
                break;
            case BladeTrails:
                abstractEffectModifier = new BladeTrailsEffectModifier(rs);
                break;
            case Block:
                abstractEffectModifier = new BlockEffectModifier(rs);
                break;
            case BlockedPowerType:
                abstractEffectModifier = new BlockedPowerTypeEffectModifier(rs);
                break;
            case CannotAttack:
                abstractEffectModifier = new CannotAttackEffectModifier(rs);
                break;
            case CannotCast:
                abstractEffectModifier = new CannotCastEffectModifier(rs);
                break;
            case CannotMove:
                abstractEffectModifier = new CannotMoveEffectModifier(rs);
                break;
            case CannotTrack:
                abstractEffectModifier = new CannotTrackEffectModifier(rs);
                break;
            case Charmed:
                abstractEffectModifier = new CharmedEffectModifier(rs);
                break;
            case ConstrainedAmbidexterity:
                abstractEffectModifier = new ConstrainedAmbidexterityEffectModifier(rs);
                break;
            case DamageCap:
                abstractEffectModifier = new DamageCapEffectModifier(rs);
                break;
            case DamageShield:
                abstractEffectModifier = new DamageShieldEffectModifier(rs);
                break;
            case DCV:
                abstractEffectModifier = new DCVEffectModifier(rs);
                break;
            case Dodge:
                abstractEffectModifier = new DodgeEffectModifier(rs);
                break;
            case DR:
                abstractEffectModifier = new DREffectModifier(rs);
                break;
            case Durability:
                abstractEffectModifier = new DurabilityEffectModifier(rs);
                break;
            case ExclusiveDamageCap:
                abstractEffectModifier = new ExclusiveDamageCapEffectModifier(rs);
                break;
            case Fade:
                abstractEffectModifier = new FadeEffectModifier(rs);
                break;
            case Fly:
                abstractEffectModifier = new FlyEffectModifier(rs);
                break;
            case Health:
                abstractEffectModifier = new HealthEffectModifier(rs);
                break;
            case HealthFull:
                abstractEffectModifier = new HealthFullEffectModifier(rs);
                break;
            case HealthRecoverRate:
                abstractEffectModifier = new HealthRecoverRateEffectModifier(rs);
                break;
            case IgnoreDamageCap:
                abstractEffectModifier = new IgnoreDamageCapEffectModifier(rs);
                break;
            case IgnorePassiveDefense:
                abstractEffectModifier = new IgnorePassiveDefenseEffectModifier(rs);
                break;
            case ImmuneTo:
                abstractEffectModifier = new ImmuneToEffectModifier(rs);
                break;
            case ImmuneToAttack:
                abstractEffectModifier = new ImmuneToAttackEffectModifier(rs);
                break;
            case ImmuneToPowers:
                abstractEffectModifier = new ImmuneToPowersEffectModifier(rs);
                break;
            case Invisible:
                abstractEffectModifier = new InvisibleEffectModifier(rs);
                break;
            case ItemName:
                abstractEffectModifier = new ItemNameEffectModifier(rs);
                if (((ItemNameEffectModifier) abstractEffectModifier).name.isEmpty())
                    break;
                if (effectBase != null)
                    effectBase.setName((((ItemNameEffectModifier) abstractEffectModifier).name));
                break;
            case Mana:
                abstractEffectModifier = new ManaEffectModifier(rs);
                break;
            case ManaFull:
                abstractEffectModifier = new ManaFullEffectModifier(rs);
                break;
            case ManaRecoverRate:
                abstractEffectModifier = new ManaRecoverRateEffectModifier(rs);
                break;
            case MaxDamage:
                abstractEffectModifier = new MaxDamageEffectModifier(rs);
                break;
            case MeleeDamageModifier:
                abstractEffectModifier = new MeleeDamageEffectModifier(rs);
                break;
            case MinDamage:
                abstractEffectModifier = new MinDamageEffectModifier(rs);
                break;
            case NoMod:
                abstractEffectModifier = new NoModEffectModifier(rs);
                break;
            case OCV:
                abstractEffectModifier = new OCVEffectModifier(rs);
                break;
            case Parry:
                abstractEffectModifier = new ParryEffectModifier(rs);
                break;
            case PassiveDefense:
                abstractEffectModifier = new PassiveDefenseEffectModifier(rs);
                break;
            case PowerCost:
                abstractEffectModifier = new PowerCostEffectModifier(rs);
                break;
            case PowerCostHealth:
                abstractEffectModifier = new PowerCostHealthEffectModifier(rs);
                break;
            case PowerDamageModifier:
                abstractEffectModifier = new PowerDamageEffectModifier(rs);
                break;
            case ProtectionFrom:
                abstractEffectModifier = new ProtectionFromEffectModifier(rs);
                break;
            case Resistance:
                abstractEffectModifier = new ResistanceEffectModifier(rs);
                break;
            case ScaleHeight:
                abstractEffectModifier = new ScaleHeightEffectModifier(rs);
                break;
            case ScaleWidth:
                abstractEffectModifier = new ScaleWidthEffectModifier(rs);
                break;
            case ScanRange:
                abstractEffectModifier = new ScanRangeEffectModifier(rs);
                break;
            case SeeInvisible:
                abstractEffectModifier = new SeeInvisibleEffectModifier(rs);
                break;
            case Silenced:
                abstractEffectModifier = new SilencedEffectModifier(rs);
                break;
            case Skill:
                abstractEffectModifier = new SkillEffectModifier(rs);
                break;
            case Slay:
                abstractEffectModifier = new SlayEffectModifier(rs);
                break;
            case Speed:
                abstractEffectModifier = new SpeedEffectModifier(rs);
                break;
            case SpireBlock:
                abstractEffectModifier = new SpireBlockEffectModifier(rs);
                break;
            case Stamina:
                abstractEffectModifier = new StaminaEffectModifier(rs);
                break;
            case StaminaFull:
                abstractEffectModifier = new StaminaFullEffectModifier(rs);
                break;
            case StaminaRecoverRate:
                abstractEffectModifier = new StaminaRecoverRateEffectModifier(rs);
                break;
            case Stunned:
                abstractEffectModifier = new StunnedEffectModifier(rs);
                break;
            case Value:
                abstractEffectModifier = new ValueEffectModifier(rs);
                if (effectBase != null) {
                    ValueEffectModifier valueEffect = (ValueEffectModifier) abstractEffectModifier;
                    effectBase.value = valueEffect.minMod;
                    Item.addEnchantValue(effectBase.getIDString(), (int)valueEffect.minMod);
                }
                break;
            case WeaponProc:
                abstractEffectModifier = new WeaponProcEffectModifier(rs);
                break;
            case WeaponRange:
                abstractEffectModifier = new WeaponRangeEffectModifier(rs);
                break;
            case WeaponSpeed:
                abstractEffectModifier = new WeaponSpeedEffectModifier(rs);
                break;

        }
        return abstractEffectModifier;
    }

}
