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.
466 lines
18 KiB
466 lines
18 KiB
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . |
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· |
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ |
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ |
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ |
|
// Magicbane Emulator Project © 2013 - 2022 |
|
// www.magicbane.com |
|
|
|
|
|
package engine.objects; |
|
|
|
import engine.gameManager.ChatManager; |
|
import engine.gameManager.DbManager; |
|
import engine.mbEnums; |
|
import engine.mbEnums.ModType; |
|
import engine.mbEnums.SourceType; |
|
import engine.server.MBServerStatics; |
|
import org.pmw.tinylog.Logger; |
|
|
|
import java.sql.ResultSet; |
|
import java.sql.SQLException; |
|
import java.util.HashSet; |
|
import java.util.Iterator; |
|
import java.util.concurrent.ConcurrentHashMap; |
|
|
|
public class Resists { |
|
|
|
private static ConcurrentHashMap<Integer, Resists> mobResists = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); |
|
private ConcurrentHashMap<mbEnums.DamageType, Float> resists = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); |
|
private ConcurrentHashMap<mbEnums.DamageType, Boolean> immuneTo = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); |
|
private mbEnums.DamageType protection; |
|
private int protectionTrains = 0; |
|
private boolean immuneToAll; |
|
|
|
/** |
|
* Generic Constructor |
|
*/ |
|
|
|
public Resists(String type) { |
|
switch (type) { |
|
case "Building": |
|
setBuildingResists(); |
|
break; |
|
case "Mine": |
|
setMineResists(); |
|
break; |
|
default: |
|
setGenericResists(); |
|
break; |
|
} |
|
} |
|
|
|
public Resists(Resists r) { |
|
for (mbEnums.DamageType dt : r.resists.keySet()) |
|
this.resists.put(dt, r.resists.get(dt)); |
|
for (mbEnums.DamageType dt : r.immuneTo.keySet()) |
|
this.immuneTo.put(dt, r.immuneTo.get(dt)); |
|
this.protection = r.protection; |
|
this.protectionTrains = r.protectionTrains; |
|
this.immuneToAll = r.immuneToAll; |
|
} |
|
|
|
/** |
|
* Generic Constructor for player |
|
*/ |
|
public Resists(PlayerCharacter pc) { |
|
setGenericResists(); |
|
} |
|
|
|
public Resists(Mob mob) { |
|
setGenericResists(); |
|
} |
|
|
|
/** |
|
* Called for mobBase when getting from the db fails |
|
*/ |
|
public Resists(MobBase mobBase) { |
|
setGenericResists(); |
|
} |
|
|
|
/** |
|
* Database Constructor |
|
*/ |
|
public Resists(ResultSet rs) throws SQLException { |
|
this.immuneToAll = false; |
|
this.resists.put(mbEnums.DamageType.SLASHING, rs.getFloat("slash")); |
|
this.resists.put(mbEnums.DamageType.CRUSHING, rs.getFloat("crush")); |
|
this.resists.put(mbEnums.DamageType.PIERCING, rs.getFloat("pierce")); |
|
this.resists.put(mbEnums.DamageType.MAGIC, rs.getFloat("magic")); |
|
this.resists.put(mbEnums.DamageType.BLEEDING, rs.getFloat("bleed")); |
|
this.resists.put(mbEnums.DamageType.POISON, rs.getFloat("poison")); |
|
this.resists.put(mbEnums.DamageType.MENTAL, rs.getFloat("mental")); |
|
this.resists.put(mbEnums.DamageType.HOLY, rs.getFloat("holy")); |
|
this.resists.put(mbEnums.DamageType.UNHOLY, rs.getFloat("unholy")); |
|
this.resists.put(mbEnums.DamageType.LIGHTNING, rs.getFloat("lightning")); |
|
this.resists.put(mbEnums.DamageType.FIRE, rs.getFloat("fire")); |
|
this.resists.put(mbEnums.DamageType.COLD, rs.getFloat("cold")); |
|
this.resists.put(mbEnums.DamageType.HEALING, 0f); |
|
} |
|
|
|
//Handle Fortitudes |
|
private static float handleFortitude(AbstractCharacter target, mbEnums.DamageType type, float damage) { |
|
if (target == null || !(target.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter))) |
|
return damage; |
|
PlayerBonuses bonus = target.getBonuses(); |
|
|
|
//see if there is a fortitude |
|
float damageCap = bonus.getFloatPercentAll(ModType.DamageCap, SourceType.None); |
|
if (damageCap == 0f || type == mbEnums.DamageType.HEALING) |
|
return damage; |
|
|
|
//is fortitude, Are we under the cap? |
|
float maxHealth = target.getHealthMax(); |
|
float capFire = maxHealth * (damageCap); |
|
if (damage < capFire) |
|
return damage; |
|
|
|
//let's see if valid damagetype to apply it |
|
boolean exclusive; |
|
HashSet<SourceType> forts = bonus.getList(ModType.IgnoreDamageCap); |
|
if (forts == null) { |
|
exclusive = true; |
|
forts = bonus.getList(ModType.ExclusiveDamageCap); |
|
} else |
|
exclusive = false; |
|
if (forts == null || !isValidDamageCapType(forts, type, exclusive)) |
|
return damage; |
|
|
|
float adjustedDamage = bonus.getFloatPercentAll(ModType.AdjustAboveDmgCap, SourceType.None); |
|
//Adjust damage down and return new amount |
|
float aadc = 1 + adjustedDamage; |
|
return capFire * aadc; |
|
} |
|
|
|
//Test if Damagetype is valid for foritude |
|
private static boolean isValidDamageCapType(HashSet<SourceType> forts, mbEnums.DamageType damageType, boolean exclusive) { |
|
for (SourceType fort : forts) { |
|
mbEnums.DamageType dt = mbEnums.DamageType.getDamageType(fort.name()); |
|
|
|
if (dt.equals(mbEnums.DamageType.NONE)) |
|
continue; |
|
|
|
if (dt.equals(damageType)) { |
|
return exclusive; |
|
} |
|
} |
|
return !exclusive; |
|
} |
|
|
|
/** |
|
* Calculate Current Resists for Player |
|
*/ |
|
public static void calculateResists(AbstractCharacter ac) { |
|
if (ac.getResists() != null) |
|
ac.getResists().calculateResists(ac, true); |
|
else |
|
Logger.error("Unable to find resists for character " + ac.getObjectUUID()); |
|
} |
|
|
|
private static float[] getArmorResists(Item armor, float[] phys) { |
|
|
|
if (armor == null) |
|
return phys; |
|
|
|
if (armor.template.item_type.equals(mbEnums.ItemType.ARMOR)) { |
|
phys[0] += armor.template.combat_attack_resist.get("SLASHING"); |
|
phys[1] += armor.template.combat_attack_resist.get("CRUSHING"); |
|
phys[2] += armor.template.combat_attack_resist.get("PIERCING"); |
|
} |
|
|
|
return phys; |
|
} |
|
|
|
/** |
|
* Get mob resists from db if there, otherwise set defaults |
|
*/ |
|
public static Resists getResists(int resistID) { |
|
//check cache first |
|
if (mobResists.containsKey(resistID)) |
|
return new Resists(mobResists.get(resistID)); |
|
|
|
//get from database |
|
Resists resists = DbManager.ResistQueries.GET_RESISTS_FOR_MOB(resistID); |
|
if (resists != null) { |
|
mobResists.put(resistID, resists); |
|
return new Resists(resists); |
|
} |
|
|
|
//failed, may want to debug this |
|
return null; |
|
} |
|
|
|
/** |
|
* Create generic resists for buildings |
|
*/ |
|
public final void setBuildingResists() { |
|
this.immuneToAll = false; |
|
this.resists.put(mbEnums.DamageType.SLASHING, 85f); |
|
this.resists.put(mbEnums.DamageType.CRUSHING, 85f); |
|
this.resists.put(mbEnums.DamageType.SIEGE, 0f); |
|
this.immuneTo.put(mbEnums.DamageType.PIERCING, true); |
|
this.immuneTo.put(mbEnums.DamageType.MAGIC, true); |
|
this.immuneTo.put(mbEnums.DamageType.BLEEDING, true); |
|
this.immuneTo.put(mbEnums.DamageType.POISON, true); |
|
this.immuneTo.put(mbEnums.DamageType.MENTAL, true); |
|
this.immuneTo.put(mbEnums.DamageType.HOLY, true); |
|
this.immuneTo.put(mbEnums.DamageType.UNHOLY, true); |
|
this.immuneTo.put(mbEnums.DamageType.LIGHTNING, true); |
|
this.immuneTo.put(mbEnums.DamageType.FIRE, true); |
|
this.immuneTo.put(mbEnums.DamageType.COLD, true); |
|
|
|
} |
|
|
|
/** |
|
* Create generic resists for mines |
|
*/ |
|
public final void setMineResists() { |
|
this.immuneToAll = false; |
|
this.immuneTo.put(mbEnums.DamageType.SLASHING, true); |
|
this.immuneTo.put(mbEnums.DamageType.CRUSHING, true); |
|
this.immuneTo.put(mbEnums.DamageType.PIERCING, true); |
|
this.immuneTo.put(mbEnums.DamageType.MAGIC, true); |
|
this.immuneTo.put(mbEnums.DamageType.BLEEDING, true); |
|
this.immuneTo.put(mbEnums.DamageType.POISON, true); |
|
this.immuneTo.put(mbEnums.DamageType.MENTAL, true); |
|
this.immuneTo.put(mbEnums.DamageType.HOLY, true); |
|
this.immuneTo.put(mbEnums.DamageType.UNHOLY, true); |
|
this.immuneTo.put(mbEnums.DamageType.LIGHTNING, true); |
|
this.immuneTo.put(mbEnums.DamageType.FIRE, true); |
|
this.immuneTo.put(mbEnums.DamageType.COLD, true); |
|
this.resists.put(mbEnums.DamageType.SIEGE, 0f); |
|
} |
|
|
|
/** |
|
* Create generic resists |
|
*/ |
|
public final void setGenericResists() { |
|
this.immuneToAll = false; |
|
this.resists.put(mbEnums.DamageType.SLASHING, 0f); |
|
this.resists.put(mbEnums.DamageType.CRUSHING, 0f); |
|
this.resists.put(mbEnums.DamageType.PIERCING, 0f); |
|
this.resists.put(mbEnums.DamageType.MAGIC, 0f); |
|
this.resists.put(mbEnums.DamageType.BLEEDING, 0f); |
|
this.resists.put(mbEnums.DamageType.POISON, 0f); |
|
this.resists.put(mbEnums.DamageType.MENTAL, 0f); |
|
this.resists.put(mbEnums.DamageType.HOLY, 0f); |
|
this.resists.put(mbEnums.DamageType.UNHOLY, 0f); |
|
this.resists.put(mbEnums.DamageType.LIGHTNING, 0f); |
|
this.resists.put(mbEnums.DamageType.FIRE, 0f); |
|
this.resists.put(mbEnums.DamageType.COLD, 0f); |
|
this.resists.put(mbEnums.DamageType.HEALING, 0f); |
|
this.immuneTo.put(mbEnums.DamageType.SIEGE, true); |
|
|
|
} |
|
|
|
/** |
|
* Get a resist |
|
*/ |
|
public float getResist(mbEnums.DamageType type, int trains) { |
|
//get resisted amount |
|
Float amount = 0f; |
|
if (this.resists.containsKey(type)) |
|
amount = this.resists.get(type); |
|
|
|
//add protection |
|
if (trains > 0 && protection != null && type.equals(this.protection)) { |
|
float prot = 50 + this.protectionTrains - trains; |
|
amount += (prot >= 0) ? prot : 0; |
|
} |
|
|
|
if (amount == null) |
|
return 0f; |
|
if (amount > 75f) |
|
return 75f; |
|
return amount; |
|
} |
|
|
|
/** |
|
* get immuneTo |
|
*/ |
|
public boolean immuneTo(mbEnums.DamageType type) { |
|
if (this.immuneTo.containsKey(type)) |
|
return this.immuneTo.get(type); |
|
else |
|
return false; |
|
} |
|
|
|
/** |
|
* get immuneToAll |
|
*/ |
|
public boolean immuneToAll() { |
|
return this.immuneToAll; |
|
} |
|
|
|
public boolean immuneToAttacks() { |
|
return immuneTo(mbEnums.DamageType.ATTACK); |
|
} |
|
|
|
/** |
|
* Set a resist |
|
*/ |
|
public void setResist(mbEnums.DamageType type, float value) { |
|
this.resists.put(type, value); |
|
} |
|
|
|
/** |
|
* set immuneToAll |
|
*/ |
|
public void setImmuneToAll(boolean value) { |
|
this.immuneToAll = value; |
|
} |
|
|
|
/** |
|
* set resists from mobbase |
|
*/ |
|
public void setMobResists(int resistID) { |
|
//TODO add this in later |
|
//calls `static_npc_mob_resists` table WHERE `ID`='resistID' |
|
} |
|
|
|
/** |
|
* get Damage after resist |
|
* Expects heals as negative damage and damage as positive damage for fortitudes. |
|
*/ |
|
public float getResistedDamage(AbstractCharacter source, AbstractCharacter target, mbEnums.DamageType type, float damage, int trains) { |
|
//handle fortitudes |
|
damage = handleFortitude(target, type, damage); |
|
|
|
//calculate armor piercing |
|
float ap = source.getBonuses().getFloatPercentAll(ModType.ArmorPiercing, SourceType.None); |
|
float damageAfterResists = damage * (1 - (this.getResist(type, trains) * 0.01f) + ap); |
|
|
|
//check to see if any damage absorbers should cancel |
|
if (target != null) |
|
target.cancelOnTakeDamage(type, (damageAfterResists)); |
|
|
|
return damageAfterResists; |
|
} |
|
|
|
public void calculateResists(AbstractCharacter ac, boolean val) { |
|
this.immuneTo.clear(); |
|
|
|
// get resists for runes |
|
PlayerBonuses rb = ac.getBonuses(); |
|
float slash = 0f, crush = 0f, pierce = 0f, magic = 0f, bleed = 0f, mental = 0f, holy = 0f, unholy = 0f, poison = 0f, lightning = 0f, fire = 0f, cold = 0f, healing = 0f; |
|
|
|
if (rb != null) { |
|
// Handle immunities |
|
if (rb.getBool(ModType.ImmuneTo, SourceType.Stun)) |
|
this.immuneTo.put(mbEnums.DamageType.STUN, true); |
|
if (rb.getBool(ModType.ImmuneTo, SourceType.Blind)) |
|
this.immuneTo.put(mbEnums.DamageType.BLINDNESS, true); |
|
if (rb.getBool(ModType.ImmuneToAttack, SourceType.None)) |
|
this.immuneTo.put(mbEnums.DamageType.ATTACK, true); |
|
if (rb.getBool(ModType.ImmuneToPowers, SourceType.None)) |
|
this.immuneTo.put(mbEnums.DamageType.POWERS, true); |
|
if (rb.getBool(ModType.ImmuneTo, SourceType.Powerblock)) |
|
this.immuneTo.put(mbEnums.DamageType.POWERINHIBITOR, true); |
|
if (rb.getBool(ModType.ImmuneTo, SourceType.DeBuff)) |
|
this.immuneTo.put(mbEnums.DamageType.DEBUFF, true); |
|
if (rb.getBool(ModType.ImmuneTo, SourceType.Fear)) |
|
this.immuneTo.put(mbEnums.DamageType.FEAR, true); |
|
if (rb.getBool(ModType.ImmuneTo, SourceType.Charm)) |
|
this.immuneTo.put(mbEnums.DamageType.CHARM, true); |
|
if (rb.getBool(ModType.ImmuneTo, SourceType.Root)) |
|
this.immuneTo.put(mbEnums.DamageType.ROOT, true); |
|
if (rb.getBool(ModType.ImmuneTo, SourceType.Snare)) |
|
this.immuneTo.put(mbEnums.DamageType.SNARE, true); |
|
|
|
// Handle resists |
|
slash += rb.getFloat(ModType.Resistance, SourceType.Slashing); |
|
crush += rb.getFloat(ModType.Resistance, SourceType.Crushing); |
|
pierce += rb.getFloat(ModType.Resistance, SourceType.Piercing); |
|
magic += rb.getFloat(ModType.Resistance, SourceType.Magic); |
|
bleed += rb.getFloat(ModType.Resistance, SourceType.Bleeding); |
|
poison += rb.getFloat(ModType.Resistance, SourceType.Poison); |
|
mental += rb.getFloat(ModType.Resistance, SourceType.Mental); |
|
holy += rb.getFloat(ModType.Resistance, SourceType.Holy); |
|
unholy += rb.getFloat(ModType.Resistance, SourceType.Unholy); |
|
lightning += rb.getFloat(ModType.Resistance, SourceType.Lightning); |
|
fire += rb.getFloat(ModType.Resistance, SourceType.Fire); |
|
cold += rb.getFloat(ModType.Resistance, SourceType.Cold); |
|
healing += rb.getFloat(ModType.Resistance, SourceType.Healing); // DamageType.Healing.name()); |
|
|
|
} |
|
|
|
// get resists from equipment |
|
if (ac.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) { |
|
if (ac.charItemManager != null && ac.charItemManager.getEquipped() != null) { |
|
float[] phys = {0f, 0f, 0f}; |
|
ConcurrentHashMap<mbEnums.EquipSlotType, Item> equip = ac.charItemManager.getEquipped(); |
|
|
|
// get base physical resists |
|
phys = Resists.getArmorResists(equip.get(mbEnums.EquipSlotType.HELM), phys); |
|
phys = Resists.getArmorResists(equip.get(mbEnums.EquipSlotType.CHEST), phys); |
|
phys = Resists.getArmorResists(equip.get(mbEnums.EquipSlotType.UPARM), phys); |
|
phys = Resists.getArmorResists(equip.get(mbEnums.EquipSlotType.HANDS), phys); |
|
phys = Resists.getArmorResists(equip.get(mbEnums.EquipSlotType.LEGS), phys); |
|
phys = Resists.getArmorResists(equip.get(mbEnums.EquipSlotType.FEET), phys); |
|
slash += phys[0]; |
|
crush += phys[1]; |
|
pierce += phys[2]; |
|
|
|
} |
|
} |
|
|
|
this.resists.put(mbEnums.DamageType.SLASHING, slash); |
|
this.resists.put(mbEnums.DamageType.CRUSHING, crush); |
|
this.resists.put(mbEnums.DamageType.PIERCING, pierce); |
|
this.resists.put(mbEnums.DamageType.MAGIC, magic); |
|
this.resists.put(mbEnums.DamageType.BLEEDING, bleed); |
|
this.resists.put(mbEnums.DamageType.POISON, poison); |
|
this.resists.put(mbEnums.DamageType.MENTAL, mental); |
|
this.resists.put(mbEnums.DamageType.HOLY, holy); |
|
this.resists.put(mbEnums.DamageType.UNHOLY, unholy); |
|
this.resists.put(mbEnums.DamageType.LIGHTNING, lightning); |
|
this.resists.put(mbEnums.DamageType.FIRE, fire); |
|
this.resists.put(mbEnums.DamageType.COLD, cold); |
|
this.resists.put(mbEnums.DamageType.HEALING, healing); |
|
|
|
this.immuneTo.put(mbEnums.DamageType.SIEGE, true); |
|
|
|
// debug printing of resists |
|
// printResists(pc); |
|
} |
|
|
|
public void printResistsToClient(PlayerCharacter pc) { |
|
for (mbEnums.DamageType dt : resists.keySet()) |
|
ChatManager.chatSystemInfo(pc, " resist." + dt.name() + ": " + resists.get(dt)); |
|
for (mbEnums.DamageType dt : immuneTo.keySet()) |
|
ChatManager.chatSystemInfo(pc, " immuneTo." + dt.name() + ": " + immuneTo.get(dt)); |
|
ChatManager.chatSystemInfo(pc, " immuneToAll: " + this.immuneToAll); |
|
if (protection != null) |
|
ChatManager.chatSystemInfo(pc, " Protection: " + protection.name() + ", Trains: " + protectionTrains); |
|
else |
|
ChatManager.chatSystemInfo(pc, " Protection: None"); |
|
} |
|
|
|
public String getResists(PlayerCharacter pc) { |
|
String out = pc.getName(); |
|
|
|
out += "Resists: "; |
|
Iterator<mbEnums.DamageType> it = this.resists.keySet().iterator(); |
|
while (it.hasNext()) { |
|
mbEnums.DamageType damType = it.next(); |
|
String dtName = damType.name(); |
|
out += dtName + '=' + this.resists.get(dtName) + ", "; |
|
} |
|
|
|
out += "ImmuneTo: "; |
|
it = this.immuneTo.keySet().iterator(); |
|
while (it.hasNext()) { |
|
mbEnums.DamageType damType = it.next(); |
|
|
|
String dtName = damType.name(); |
|
out += dtName + '=' + this.resists.get(dtName) + ", "; |
|
} |
|
|
|
if (protection != null) |
|
out += "Protection: " + protection.name() + ", Trains: " + protectionTrains; |
|
else |
|
out += "Protection: none"; |
|
|
|
return out; |
|
} |
|
}
|
|
|