Public Repository for the Magicbane Shadowbane Emulator
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.

327 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) {
}
}