You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
326 lines
14 KiB
326 lines
14 KiB
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . |
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· |
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ |
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ |
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ |
|
// Magicbane Emulator Project © 2013 - 2022 |
|
// www.magicbane.com |
|
|
|
|
|
package engine.powers.effectmodifiers; |
|
|
|
import engine.Enum.DamageType; |
|
import engine.Enum.GameObjectType; |
|
import engine.Enum.ModType; |
|
import engine.Enum.SourceType; |
|
import engine.gameManager.ChatManager; |
|
import engine.gameManager.ZergManager; |
|
import engine.jobs.AbstractEffectJob; |
|
import engine.jobs.DamageOverTimeJob; |
|
import engine.net.AbstractNetMsg; |
|
import engine.net.DispatchMessage; |
|
import engine.net.client.msg.ModifyHealthKillMsg; |
|
import engine.net.client.msg.ModifyHealthMsg; |
|
import engine.objects.*; |
|
import org.pmw.tinylog.Logger; |
|
|
|
import java.sql.ResultSet; |
|
import java.sql.SQLException; |
|
import java.util.concurrent.ThreadLocalRandom; |
|
|
|
public class HealthEffectModifier extends AbstractEffectModifier { |
|
|
|
private DamageType damageType; |
|
|
|
public HealthEffectModifier(ResultSet rs) throws SQLException { |
|
super(rs); |
|
String damageTypeDB = rs.getString("type"); |
|
try { |
|
this.damageType = DamageType.valueOf(damageTypeDB); |
|
} catch (IllegalArgumentException e) { |
|
Logger.error("DamageType could not be loaded from database. " + "UUID = " + this.UUID |
|
+ " value received = '" + damageTypeDB + '\'', e); |
|
} |
|
} |
|
|
|
public static float getMinDamage(float baseMin, float intelligence, float spirit, float focus) { |
|
float min = baseMin * (((float) Math.pow(intelligence, 0.75f) * 0.0311f) + (0.02f * (int) focus) + ((float) Math.pow(spirit, 0.75f) * 0.0416f)); |
|
return (float) ((int) (min + 0.5f)); //round to nearest whole number |
|
} |
|
|
|
public static float getMaxDamage(float baseMax, float intelligence, float spirit, float focus) { |
|
float max = baseMax * (((float) Math.pow(intelligence, 0.75f) * 0.0785f) + (0.015f * (int) focus) + ((float) Math.pow(spirit, 0.75f) * 0.0157f)); |
|
return (float) ((int) (max + 0.5f)); //round to nearest whole number |
|
} |
|
|
|
@Override |
|
protected void _applyEffectModifier(AbstractCharacter source, AbstractWorldObject awo, int trains, AbstractEffectJob effect) { |
|
if (awo == null) { |
|
Logger.error("_applyEffectModifier(): NULL AWO passed in."); |
|
return; |
|
} |
|
|
|
if (effect == null) { |
|
Logger.error("_applyEffectModifier(): NULL AbstractEffectJob passed in."); |
|
return; |
|
} |
|
|
|
float modAmount = 0f; |
|
|
|
// Modify health by percent |
|
if (this.percentMod != 0f) { |
|
|
|
//high level mobs/players should not be %damaged/healed. |
|
if (awo.getHealthMax() > 25000f && (this.percentMod < 0f || this.percentMod > 5f)) |
|
return; |
|
|
|
float mod = 1f; |
|
if (this.useRampAdd) |
|
mod = (this.percentMod + (this.ramp * trains)) / 100; |
|
else |
|
mod = (this.percentMod * (1 + (this.ramp * trains))) / 100; |
|
modAmount = mod * awo.getHealthMax(); |
|
if (AbstractWorldObject.IsAbstractCharacter(awo)) { |
|
if (((AbstractCharacter) awo).isSit()) |
|
modAmount *= 2.5f; |
|
} |
|
|
|
//debug for spell damage and atr |
|
if (source.getDebug(16) && source.getObjectType().equals(GameObjectType.PlayerCharacter)) { |
|
PlayerCharacter pc = (PlayerCharacter) source; |
|
String smsg = "Percent Damage: " + mod * 100 + '%'; |
|
ChatManager.chatSystemInfo(pc, smsg); |
|
} |
|
} |
|
|
|
// Modify health by min/max amount |
|
else if (this.minMod != 0f || this.maxMod != 0f) { |
|
float min = this.minMod; |
|
float max = this.maxMod; |
|
if (this.ramp > 0f) { |
|
float mod = this.ramp * trains; |
|
if (this.useRampAdd) { |
|
min += mod; |
|
max += mod; |
|
} else { |
|
min *= (1 + mod); |
|
max *= (1 + mod); |
|
} |
|
} |
|
if (source.getObjectType().equals(GameObjectType.PlayerCharacter)) { |
|
PlayerCharacter pc = (PlayerCharacter) source; |
|
|
|
float focus; |
|
CharacterSkill skill = pc.getSkills().get(effect.getPower().getSkillName()); |
|
if (skill == null) |
|
focus = CharacterSkill.getQuickMastery(pc, effect.getPower().getSkillName()); |
|
else |
|
focus = skill.getModifiedAmount(); |
|
//TODO clean up old formulas once new one is verified |
|
// min *= (0.5 + 0.0075 * pc.getStatIntCurrent() + 0.011 * pc.getStatSpiCurrent() + 0.0196 * focus); |
|
// max *= (0.62 + 0.0192 * pc.getStatIntCurrent() + 0.00415 * pc.getStatSpiCurrent() + 0.015 * focus); |
|
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 = HealthEffectModifier.getMinDamage(min, intt, spi, focus); |
|
max = HealthEffectModifier.getMaxDamage(max, intt, spi, focus); |
|
|
|
//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); |
|
} |
|
} else if (source.getObjectType() == GameObjectType.Mob) { |
|
Mob pc = (Mob) source; |
|
|
|
float focus; |
|
CharacterSkill skill = pc.getSkills().get(effect.getPower().getSkillName()); |
|
if (skill == null) |
|
focus = CharacterSkill.getQuickMastery(pc, effect.getPower().getSkillName()); |
|
else |
|
focus = skill.getModifiedAmount(); |
|
//TODO clean up old formulas once new one is verified |
|
// min *= (0.5 + 0.0075 * pc.getStatIntCurrent() + 0.011 * pc.getStatSpiCurrent() + 0.0196 * focus); |
|
// max *= (0.62 + 0.0192 * pc.getStatIntCurrent() + 0.00415 * pc.getStatSpiCurrent() + 0.015 * focus); |
|
float intt = (pc.getStatIntCurrent() >= 1) ? (float) pc.getStatIntCurrent() : 1f; |
|
|
|
if (pc.isPlayerGuard()) |
|
intt = 200; |
|
float spi = (pc.getStatSpiCurrent() >= 1) ? (float) pc.getStatSpiCurrent() : 1f; |
|
|
|
if (pc.isPlayerGuard()) |
|
spi = 200; |
|
// 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 = HealthEffectModifier.getMinDamage(min, intt, spi, focus); |
|
max = HealthEffectModifier.getMaxDamage(max, intt, spi, focus); |
|
|
|
//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); |
|
// } |
|
} |
|
modAmount = calculateDamage(source, min, max, awo, trains); |
|
PlayerBonuses bonus = source.getBonuses(); |
|
|
|
// Apply any power effect modifiers (such as stances) |
|
if (bonus != null) |
|
modAmount *= (1 + (bonus.getFloatPercentAll(ModType.PowerDamageModifier, SourceType.None))); |
|
} |
|
if (modAmount == 0f) |
|
return; |
|
if (AbstractWorldObject.IsAbstractCharacter(awo)) { |
|
AbstractCharacter ac = (AbstractCharacter) awo; |
|
|
|
if (!ac.isAlive()) |
|
return; |
|
|
|
int powerID = 0, effectID = 0; |
|
String powerName = ""; |
|
if (effect.getPower() != null) { |
|
powerID = effect.getPower().getToken(); |
|
powerName = effect.getPower().getName(); |
|
} else { |
|
Logger.error("Power has returned null! Damage will fail to register! (" + (ac.getCurrentHitpoints() > 0 ? "Alive)" : "Dead)")); |
|
} |
|
|
|
if (effect.getEffect() != null) { |
|
effectID = effect.getEffect().getToken(); |
|
} else { |
|
Logger.error("Effect has returned null! Damage will fail to register! (" + (ac.getCurrentHitpoints() > 0 ? "Alive)" : "Dead)")); |
|
} |
|
|
|
//see if target is immune to heals |
|
if (modAmount > 0f) { |
|
boolean skipImmune = false; |
|
|
|
PlayerBonuses bonus = ac.getBonuses(); |
|
if (!skipImmune && bonus.getFloat(ModType.BlackMantle, SourceType.Heal) >= trains) { |
|
ModifyHealthMsg mhm = new ModifyHealthMsg(source, ac, 0f, 0f, 0f, powerID, powerName, trains, effectID); |
|
mhm.setUnknown03(5); //set target is immune |
|
DispatchMessage.sendToAllInRange(ac, mhm); |
|
return; |
|
} |
|
} |
|
float mod = 0; |
|
|
|
//Modify health |
|
|
|
mod = ac.modifyHealth(modAmount, source, false); |
|
|
|
float cur = awo.getCurrentHitpoints(); |
|
float maxAmount = awo.getHealthMax() - cur; |
|
|
|
AbstractNetMsg mhm = null; |
|
if (modAmount < 0 && cur < 0 && mod != 0) |
|
mhm = new ModifyHealthKillMsg(source, ac, modAmount, 0f, 0f, powerID, powerName, trains, effectID); |
|
else |
|
mhm = new ModifyHealthMsg(source, ac, modAmount, 0f, 0f, powerID, powerName, trains, effectID); |
|
|
|
if (effect instanceof DamageOverTimeJob) { |
|
if (mhm instanceof ModifyHealthMsg) |
|
((ModifyHealthMsg) mhm).setOmitFromChat(1); |
|
else if (mhm instanceof ModifyHealthKillMsg) |
|
((ModifyHealthKillMsg) mhm).setUnknown02(1); |
|
} |
|
|
|
//send the damage |
|
|
|
DispatchMessage.sendToAllInRange(ac, mhm); |
|
|
|
// //send corpse if this kills a mob |
|
// //TODO fix the someone misses blurb. |
|
// if(awo instanceof Mob && awo.getHealth() <= 0) { |
|
// CombatMessageMsg cmm = new CombatMessageMsg(null, 0, awo, 15); |
|
// try { |
|
// DispatchMessage.sendToAllInRange(ac, cmm); |
|
// } catch (MsgSendException e) { |
|
// Logger.error("MobCorpseSendError", e); |
|
// } |
|
// } |
|
} else if (awo.getObjectType().equals(GameObjectType.Building)) { |
|
|
|
Building b = (Building) awo; |
|
|
|
if (modAmount < 0 && (!b.isVulnerable())) |
|
return; //can't damage invul building |
|
|
|
int powerID = 0, effectID = 0; |
|
String powerName = ""; |
|
if (effect.getPower() != null) { |
|
powerID = effect.getPower().getToken(); |
|
powerName = effect.getPower().getName(); |
|
} else |
|
Logger.error("Power has returned null! Damage will fail to register! (" + (b.getRank() == -1 ? "Standing)" : "Destroyed)")); |
|
|
|
if (effect.getEffect() != null) { |
|
effectID = effect.getEffect().getToken(); |
|
} else |
|
Logger.error("Effect has returned null! Damage will fail to register! (" + (b.getRank() == -1 ? "Standing)" : "Destroyed)")); |
|
|
|
float mod = b.modifyHealth(modAmount, source); |
|
ModifyHealthMsg mhm = new ModifyHealthMsg(source, b, modAmount, 0f, 0f, powerID, powerName, trains, effectID); |
|
|
|
if (effect instanceof DamageOverTimeJob) |
|
mhm.setOmitFromChat(1); |
|
|
|
//send the damage |
|
|
|
DispatchMessage.sendToAllInRange(b, mhm); |
|
|
|
} |
|
} |
|
|
|
private float calculateDamage(AbstractCharacter source, float minDamage, float maxDamage, AbstractWorldObject awo, int trains) { |
|
|
|
// get range between min and max |
|
float range = maxDamage - minDamage; |
|
|
|
// Damage is calculated twice to average a more central point |
|
float damage = ThreadLocalRandom.current().nextFloat() * range; |
|
damage = (damage + (ThreadLocalRandom.current().nextFloat() * range)) / 2; |
|
|
|
// put it back between min and max |
|
damage += minDamage; |
|
|
|
Resists resists = null; |
|
// get resists |
|
if (AbstractWorldObject.IsAbstractCharacter(awo)) { |
|
AbstractCharacter ac = (AbstractCharacter) awo; |
|
resists = ac.getResists(); |
|
} else if (awo.getObjectType().equals(GameObjectType.Building)) |
|
resists = ((Building) awo).getResists(); |
|
|
|
// calculate resists in if any |
|
if (resists != null) { |
|
if (AbstractWorldObject.IsAbstractCharacter(awo)) |
|
damage = resists.getResistedDamage(source, (AbstractCharacter) awo, damageType, damage * -1, trains) * -1; |
|
else |
|
damage = resists.getResistedDamage(source, null, damageType, damage * -1, trains) * -1; |
|
} |
|
|
|
if (AbstractWorldObject.IsAbstractCharacter(awo)) { |
|
AbstractCharacter ac = (AbstractCharacter) awo; |
|
if (ac.isSit()) |
|
damage *= 2.5f; // increase damage if sitting |
|
} |
|
|
|
return damage; |
|
} |
|
|
|
@Override |
|
public void applyBonus(AbstractCharacter ac, int trains) { |
|
|
|
} |
|
|
|
@Override |
|
public void applyBonus(Item item, int trains) { |
|
} |
|
|
|
@Override |
|
public void applyBonus(Building building, int trains) { |
|
} |
|
|
|
}
|
|
|