// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.powers.poweractions; import engine.Enum; import engine.Enum.DamageType; import engine.Enum.ModType; import engine.Enum.SourceType; import engine.gameManager.ChatManager; import engine.math.Vector3fImmutable; import engine.net.AbstractNetMsg; import engine.net.DispatchMessage; import engine.net.client.msg.ModifyHealthKillMsg; import engine.net.client.msg.ModifyHealthMsg; import engine.objects.*; import engine.powers.ActionsBase; import engine.powers.EffectsBase; import engine.powers.PowersBase; import engine.powers.effectmodifiers.HealthEffectModifier; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.concurrent.ThreadLocalRandom; public class TransferStatPowerAction extends AbstractPowerAction { protected String effectID; protected boolean transferFromHealth = false; protected boolean transferFromMana = false; protected boolean transferFromStamina = false; protected boolean transferToHealth = false; protected boolean transferToMana = false; protected boolean transferToStamina = false; protected float transferAmount; protected float transferRamp; protected boolean transferRampAdd; protected float transferEfficiency; protected float transferEfficiencyRamp; protected boolean transferEfficiencyRampAdd; protected boolean targetToCaster; protected DamageType damageType; protected EffectsBase effect; public TransferStatPowerAction(ResultSet rs, HashMap effects) throws SQLException { super(rs); this.effectID = rs.getString("effectID"); String st = rs.getString("transferFromType"); if (st.equals("HEALTH")) this.transferFromHealth = true; else if (st.equals("MANA")) this.transferFromMana = true; else this.transferFromStamina = true; st = rs.getString("transferToType"); if (st.equals("HEALTH")) this.transferToHealth = true; else if (st.equals("MANA")) this.transferToMana = true; else this.transferToStamina = true; this.transferAmount = rs.getFloat("transferAmount"); this.transferRamp = rs.getFloat("transferRamp"); this.transferEfficiency = rs.getFloat("transferEfficiency"); this.transferEfficiencyRamp = rs.getFloat("transferEfficiencyRamp"); int flags = rs.getInt("flags"); this.transferRampAdd = ((flags & 4096) != 0) ? true : false; this.transferEfficiencyRampAdd = ((flags & 8192) != 0) ? true : false; this.targetToCaster = ((flags & 16384) != 0) ? true : false; this.effect = effects.get(this.effectID); try { String damageString = rs.getString("damageType"); // Damage type can sometimes be null in the DB. if (damageString.isEmpty() == false) this.damageType = DamageType.valueOf(damageString); } catch (Exception e) { this.damageType = null; } } public String getEffectID() { return this.effectID; } public boolean transferFromHealth() { return this.transferFromHealth; } public boolean transferFromMana() { return this.transferFromMana; } public boolean transferFromStamina() { return this.transferFromStamina; } public boolean transferToHealth() { return this.transferToHealth; } public boolean transferToMana() { return this.transferToMana; } public boolean transferToStamina() { return this.transferToStamina; } public EffectsBase getEffect() { return this.effect; } public float getTransferAmount(float trains) { // if (this.transferRampAdd) return this.transferAmount + (this.transferRamp * trains); // else // return this.transferAmount * (1 + (this.transferRamp * trains)); } public float getTransferEfficiency(float trains) { return this.transferEfficiency + (this.transferEfficiencyRamp * trains); } public boolean targetToCaster() { return this.targetToCaster; } @Override protected void _startAction(AbstractCharacter source, AbstractWorldObject awo, Vector3fImmutable targetLoc, int trains, ActionsBase ab, PowersBase pb) { this.__startAction(source, awo, trains, ab, pb); } //Added for dependancy check on TransferStatOTPowerAction protected void __startAction(AbstractCharacter source, AbstractWorldObject awo, int trains, ActionsBase ab, PowersBase pb) { this.runAction(source, awo, trains, ab, pb); } public void runAction(AbstractCharacter source, AbstractWorldObject awo, int trains, ActionsBase ab, PowersBase pb) { if (source == null || awo == null || ab == null || pb == null) return; if (!source.isAlive() || !awo.isAlive()) return; AbstractWorldObject fromAwo; AbstractWorldObject toAwo; if (this.targetToCaster) { fromAwo = awo; toAwo = source; } else { fromAwo = source; toAwo = awo; } if (AbstractWorldObject.IsAbstractCharacter(fromAwo) && AbstractWorldObject.IsAbstractCharacter(toAwo)) { AbstractCharacter from = (AbstractCharacter) fromAwo; AbstractCharacter to = (AbstractCharacter) toAwo; //get amount to drain float fromAmount = getTransferAmount(trains); //modify for resists if needed if (this.damageType != null) { Resists resists = from.getResists(); if (resists != null) fromAmount = resists.getResistedDamage(to, from, this.damageType, fromAmount * -1, trains) * -1; } float min = fromAmount;// * (getTransferEfficiency(trains) / 100); float max = min; float damage = 0f; if (source.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) { PlayerCharacter pc = (PlayerCharacter) source; float focus; CharacterSkill skill = pc.getSkills().get(pb.getSkillName()); if (skill == null) focus = CharacterSkill.getQuickMastery(pc, pb.getSkillName()); else focus = skill.getModifiedAmount(); //TODO fix this formula later float intt = (pc.getStatIntCurrent() >= 1) ? (float)pc.getStatIntCurrent() : 1f; float spi = (pc.getStatSpiCurrent() >= 1) ? (float)pc.getStatSpiCurrent() : 1f; // min *= (intt * 0.0045 + 0.055 * (float)Math.sqrt(intt - 0.5) + spi * 0.006 + 0.07 * (float)Math.sqrt(spi - 0.5) + 0.02 * (int)focus); // max *= (intt * 0.0117 + 0.13 * (float)Math.sqrt(intt - 0.5) + spi * 0.0024 + (float)Math.sqrt(spi - 0.5) * 0.021 + 0.015 * (int)focus); // min *= (0.62 + 0.0192 * pc.getStatSpiCurrent() + 0.00415 * pc.getStatIntCurrent() + 0.015 * focus) / 2; // max *= (0.62 + 0.0192 * pc.getStatIntCurrent() + 0.00415 * pc.getStatSpiCurrent() + 0.015 * focus) / 2; min = HealthEffectModifier.getMinDamage(min, intt, spi, focus); max = HealthEffectModifier.getMaxDamage(max, intt, spi, focus); // get range between min and max float range = max - min; //debug for spell damage and atr if (pc.getDebug(16)) { String smsg = "Damage: " + (int)Math.abs(min) + " - " + (int)Math.abs(max); ChatManager.chatSystemInfo(pc, smsg); } // Damage is calculated twice to average a more central point damage = ThreadLocalRandom.current().nextFloat() * range; damage = (damage + (ThreadLocalRandom.current().nextFloat() * range)) / 2; // put it back between min and max damage += min; } // Apply any power effect modifiers (such as stances) PlayerBonuses bonus = source.getBonuses(); if (bonus != null) damage *= (1 + bonus.getFloatPercentAll(ModType.PowerDamageModifier, SourceType.None)); //get amount to transfer fromAmount = damage; float toAmount = fromAmount * (getTransferEfficiency(trains) / 100); //get max amount to transfer, don't give more then the target has float maxDrain; if (this.transferFromHealth) maxDrain = from.getCurrentHitpoints(); else if (this.transferFromMana) maxDrain = from.getMana(); else maxDrain = from.getStamina(); if (toAmount > maxDrain) toAmount = maxDrain; //prep messages for transfer int powerID = pb.getToken(); int effectID = 496519310; String powerName = pb.getName(); ModifyHealthMsg mhmTo; // ModifyHealthMsg mhmFrom; AbstractNetMsg mhmFrom = null; //stop if target is immune to drains if ( from.getBonuses().getBool(ModType.ImmuneTo, SourceType.Drain)) { ModifyHealthMsg mhm = new ModifyHealthMsg(source, to, 0f, 0f, 0f, powerID, powerName, trains, effectID); mhm.setUnknown03(5); //set target is immune DispatchMessage.sendToAllInRange(from, mhm); return; } //apply transfer bonus if (this.transferToHealth) { to.modifyHealth(toAmount, source, false); mhmTo = new ModifyHealthMsg(source, to, toAmount, 0f, 0f, powerID, powerName, trains, effectID); } else if (this.transferToMana) { to.modifyMana(toAmount, source); mhmTo = new ModifyHealthMsg(source, to, 0f, toAmount, 0f, powerID, powerName, trains, effectID); } else { to.modifyStamina(toAmount, source); mhmTo = new ModifyHealthMsg(source, to, 0f, 0f, toAmount, powerID, powerName, trains, effectID); } //subtract transfer amount if (this.transferFromHealth) { float modFrom = from.modifyHealth(-fromAmount, source, false); float cur = from.getHealth(); if (cur < 0 && modFrom != 0) mhmFrom = new ModifyHealthKillMsg(source, from, -fromAmount, 0f, 0f, powerID, powerName, trains, effectID); else mhmFrom = new ModifyHealthMsg(source, from, -fromAmount, 0f, 0f, powerID, powerName, trains, effectID); } else if (this.transferFromMana) { from.modifyMana(-fromAmount, source); mhmFrom = new ModifyHealthMsg(source, from, 0f, -fromAmount, 0f, powerID, powerName, trains, effectID); } else { from.modifyStamina(-fromAmount, source); mhmFrom = new ModifyHealthMsg(source, from, 0f, 0f, -fromAmount, powerID, powerName, trains, effectID); } DispatchMessage.sendToAllInRange(to, mhmTo); DispatchMessage.sendToAllInRange(from, mhmFrom); } } @Override protected void _handleChant(AbstractCharacter source, AbstractWorldObject target, Vector3fImmutable targetLoc, int trains, ActionsBase ab, PowersBase pb) { } @Override protected void _startAction(AbstractCharacter source, AbstractWorldObject awo, Vector3fImmutable targetLoc, int numTrains, ActionsBase ab, PowersBase pb, int duration) { // TODO Auto-generated method stub } }