// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.objects; import engine.gameManager.ChatManager; import engine.gameManager.ConfigManager; import engine.gameManager.PowersManager; import engine.mbEnums; import engine.mbEnums.ModType; import engine.mbEnums.SourceType; import engine.powers.DamageShield; import engine.powers.EffectsBase; import engine.powers.effectmodifiers.AbstractEffectModifier; import java.util.HashMap; import java.util.HashSet; import java.util.concurrent.ConcurrentHashMap; public class PlayerBonuses { //First bonus set private ConcurrentHashMap bonusFloats = new ConcurrentHashMap<>(); private ConcurrentHashMap bonusDamageShields = new ConcurrentHashMap<>(); private ConcurrentHashMap bonusStrings = new ConcurrentHashMap<>(); private ConcurrentHashMap> bonusLists = new ConcurrentHashMap<>(); private ConcurrentHashMap> bonusBools = new ConcurrentHashMap<>(); private ConcurrentHashMap skillBonuses = new ConcurrentHashMap<>(); private ConcurrentHashMap regens = new ConcurrentHashMap<>(); //If active == 0 then all gets come from the A list and all puts go to the B list //If active == 1 then all gets come from the B list and all puts go to the A list //They alternate each time bonuses are calculated so the one being updated isn't read from. /** * Generic Constructor */ public PlayerBonuses(PlayerCharacter pc) { } public PlayerBonuses(Mob mob) { clearRuneBaseEffects(); } public static void InitializeBonuses(PlayerCharacter player) { if (player.bonuses == null) return; if (ConfigManager.serverType.equals(mbEnums.ServerType.LOGINSERVER)) return; player.bonuses.calculateRuneBaseEffects(player); } public static PlayerBonuses grantBonuses(AbstractCharacter ac) { if (ac.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) return new PlayerBonuses((PlayerCharacter) ac); else if (ac.getObjectType().equals(mbEnums.GameObjectType.Mob)) return new PlayerBonuses((Mob) ac); else return null; } public void clearRuneBaseEffects() { this.bonusBools.clear(); this.bonusFloats.clear(); this.bonusStrings.clear(); this.bonusDamageShields.clear(); this.bonusLists.clear(); this.skillBonuses.clear(); this.regens.put(ModType.HealthRecoverRate, (float) 1); this.regens.put(ModType.ManaRecoverRate, (float) 1); this.regens.put(ModType.StaminaRecoverRate, (float) 1); } public void calculateRuneBaseEffects(PlayerCharacter pc) { //Clear everything clearRuneBaseEffects(); //recalculate race if (pc.race != null) { if (pc.race.getEffectsList() != null) for (MobBaseEffects raceEffect : pc.race.getEffectsList()) { EffectsBase eb = PowersManager.getEffectByToken(raceEffect.getToken()); if (eb == null) continue; if (pc.getLevel() < raceEffect.getReqLvl()) continue; for (AbstractEffectModifier modifier : eb.getModifiers()) { modifier.applyBonus(pc, raceEffect.getRank()); } } if (SkillsBase.runeSkillsCache.containsKey(pc.getRaceID())) { for (int skillToken : SkillsBase.runeSkillsCache.get(pc.getRaceID()).keySet()) { float amount = SkillsBase.runeSkillsCache.get(pc.getRaceID()).get(skillToken); SkillsBase sb = SkillsBase.tokenCache.get(skillToken); if (sb == null) continue; if (this.skillBonuses.containsKey(sb.sourceType) == false) this.skillBonuses.put(sb.sourceType, amount); else this.skillBonuses.put(sb.sourceType, this.skillBonuses.get(sb.sourceType) + amount); } } } //calculate baseclass effects if (pc.baseClass != null) { if (pc.baseClass.getEffectsList() != null) for (MobBaseEffects classEffect : pc.baseClass.getEffectsList()) { EffectsBase eb = PowersManager.getEffectByToken(classEffect.getToken()); if (eb == null) continue; if (pc.getLevel() < classEffect.getReqLvl()) continue; for (AbstractEffectModifier modifier : eb.getModifiers()) { modifier.applyBonus(pc, classEffect.getRank()); } } if (SkillsBase.runeSkillsCache.containsKey(pc.getBaseClassID())) { for (int skillToken : SkillsBase.runeSkillsCache.get(pc.getBaseClassID()).keySet()) { float amount = SkillsBase.runeSkillsCache.get(pc.getBaseClassID()).get(skillToken); SkillsBase sb = SkillsBase.tokenCache.get(skillToken); if (sb == null) continue; if (this.skillBonuses.containsKey(sb.sourceType) == false) this.skillBonuses.put(sb.sourceType, amount); else this.skillBonuses.put(sb.sourceType, this.skillBonuses.get(sb.sourceType) + amount); } } } //calculate promotionClass Effects if (pc.getPromotionClass() != null) { if (pc.getPromotionClass().getEffectsList() != null) for (MobBaseEffects promoEffect : pc.getPromotionClass().getEffectsList()) { EffectsBase eb = PowersManager.getEffectByToken(promoEffect.getToken()); if (eb == null) continue; if (pc.getLevel() < promoEffect.getReqLvl()) continue; for (AbstractEffectModifier modifier : eb.getModifiers()) { modifier.applyBonus(pc, promoEffect.getRank()); } } if (SkillsBase.runeSkillsCache.containsKey(pc.getPromotionClassID())) { for (int skillToken : SkillsBase.runeSkillsCache.get(pc.getPromotionClassID()).keySet()) { float amount = SkillsBase.runeSkillsCache.get(pc.getPromotionClassID()).get(skillToken); SkillsBase sb = SkillsBase.tokenCache.get(skillToken); if (sb == null) continue; if (this.skillBonuses.containsKey(sb.sourceType) == false) this.skillBonuses.put(sb.sourceType, amount); else this.skillBonuses.put(sb.sourceType, this.skillBonuses.get(sb.sourceType) + amount); } } } for (CharacterRune runes : pc.getRunes()) { RuneBase characterRune = RuneBase.getRuneBase(runes.getRuneBaseID()); if (characterRune.getEffectsList() != null) for (MobBaseEffects runeEffect : characterRune.getEffectsList()) { EffectsBase eb = PowersManager.getEffectByToken(runeEffect.getToken()); if (eb == null) continue; if (pc.getLevel() < runeEffect.getReqLvl()) continue; for (AbstractEffectModifier modifier : eb.getModifiers()) { modifier.applyBonus(pc, runeEffect.getRank()); } } if (SkillsBase.runeSkillsCache.containsKey(runes.getRuneBaseID())) { for (int skillToken : SkillsBase.runeSkillsCache.get(runes.getRuneBaseID()).keySet()) { float amount = SkillsBase.runeSkillsCache.get(runes.getRuneBaseID()).get(skillToken); SkillsBase sb = SkillsBase.tokenCache.get(skillToken); if (sb == null) continue; if (this.skillBonuses.containsKey(sb.sourceType) == false) this.skillBonuses.put(sb.sourceType, amount); else this.skillBonuses.put(sb.sourceType, this.skillBonuses.get(sb.sourceType) + amount); } } } //Update seeInvis if needed float seeInvis = this.getFloat(ModType.SeeInvisible, SourceType.None); if (pc.getSeeInvis() < seeInvis) pc.setSeeInvis((short) seeInvis); } public void grantEffect(RuneBaseEffect rbe) { } public void setFloat(AbstractEffectModifier mod, float val) { if (val != 0) this.bonusFloats.put(mod, val); else this.bonusFloats.remove(mod); } public void setString(AbstractEffectModifier mod, String val) { if (!val.isEmpty()) this.bonusStrings.put(mod, val); else this.bonusStrings.remove(mod); } public void setList(ModType mod, HashSet val) { if (!val.equals(null)) this.bonusLists.put(mod, val); else this.bonusLists.remove(mod); } public void addFloat(AbstractEffectModifier mod, Float val) { if (this.bonusFloats.containsKey(mod) == false) this.bonusFloats.put(mod, val); else this.bonusFloats.put(mod, this.bonusFloats.get(mod) + val); } public void multFloat(AbstractEffectModifier mod, Float val) { if (this.bonusFloats.containsKey(mod) == false) this.bonusFloats.put(mod, val); else this.bonusFloats.put(mod, this.bonusFloats.get(mod) + (val * (this.bonusFloats.get(mod) + val))); } public void multRegen(ModType mod, Float val) { this.regens.put(mod, this.regens.get(mod) + (this.regens.get(mod) * val)); } public boolean getBool(ModType modType, SourceType sourceType) { if (this.bonusBools.containsKey(modType) == false) return false; if (this.bonusBools.get(modType).containsKey(sourceType) == false) return false; return this.bonusBools.get(modType).get(sourceType); } public float getSkillBonus(SourceType sourceType) { if (this.skillBonuses.containsKey(sourceType) == false) return 0; return this.skillBonuses.get(sourceType); } public float getFloat(ModType modType, SourceType sourceType) { float amount = 0; for (AbstractEffectModifier mod : this.bonusFloats.keySet()) { if (mod.getPercentMod() != 0) continue; if (mod.modType.equals(modType) == false || mod.sourceType.equals(sourceType) == false) continue; if (this.bonusFloats.get(mod) == null) continue; amount += this.bonusFloats.get(mod); } return amount; } public float getFloatPercentPositive(ModType modType, SourceType sourceType) { float amount = 0; for (AbstractEffectModifier mod : this.bonusFloats.keySet()) { if (mod.getPercentMod() == 0 && !modType.equals(ModType.AdjustAboveDmgCap)) continue; if (mod.modType.equals(modType) == false || mod.sourceType.equals(sourceType) == false) continue; if (this.bonusFloats.get(mod) == null) continue; if (this.bonusFloats.get(mod) < 0) continue; amount += this.bonusFloats.get(mod); } return amount; } public float getFloatPercentAll(ModType modType, SourceType sourceType) { float amount = 0; for (AbstractEffectModifier mod : this.bonusFloats.keySet()) { if (mod.getPercentMod() == 0 && !modType.equals(ModType.AdjustAboveDmgCap)) continue; if (mod.modType.equals(modType) == false || mod.sourceType.equals(sourceType) == false) continue; if (this.bonusFloats.get(mod) == null) continue; amount += this.bonusFloats.get(mod); } return amount; } public float getRegen(ModType modType) { return this.regens.get(modType); } public float getFloatPercentNullZero(ModType modType, SourceType sourceType) { float amount = 0; for (AbstractEffectModifier mod : this.bonusFloats.keySet()) { if (mod.getPercentMod() == 0) continue; if (mod.modType.equals(modType) == false || mod.sourceType.equals(sourceType) == false) continue; if (this.bonusFloats.get(mod) == null) continue; amount += this.bonusFloats.get(mod); } return amount; } public float getFloatPercentNegative(ModType modType, SourceType sourceType) { float amount = 0; for (AbstractEffectModifier mod : this.bonusFloats.keySet()) { if (mod.getPercentMod() == 0) continue; if (mod.modType.equals(modType) == false || mod.sourceType.equals(sourceType) == false) continue; if (this.bonusFloats.get(mod) == null) continue; if (this.bonusFloats.get(mod) > 0) continue; amount += this.bonusFloats.get(mod); } return amount; } public HashSet getList(ModType modType) { if (this.bonusLists.containsKey(modType)) return this.bonusLists.get(modType); else return null; } public ConcurrentHashMap getDamageShields() { return this.bonusDamageShields; } public void addDamageShield(AbstractEffectModifier mod, DamageShield ds) { this.bonusDamageShields.put(mod, ds); } public void updateIfHigher(AbstractEffectModifier mod, Float val) { if (this.bonusFloats.containsKey(mod) == false) { this.bonusFloats.put(mod, val); return; } float oldVal = this.getFloat(mod.modType, mod.sourceType); if (oldVal > val) return; this.bonusFloats.put(mod, val); } //Read maps public void printBonusesToClient(PlayerCharacter pc) { for (ModType modType : this.bonusBools.keySet()) { for (SourceType sourceType : this.bonusBools.get(modType).keySet()) { ChatManager.chatSystemInfo(pc, modType.name() + "-" + sourceType.name() + " = " + this.bonusBools.get(modType).get(sourceType)); } } for (ModType modType : ModType.values()) { if (modType.equals(ModType.StaminaRecoverRate) || modType.equals(ModType.HealthRecoverRate) || modType.equals(ModType.ManaRecoverRate)) ChatManager.chatSystemInfo(pc, modType.name() + " = " + this.getRegen(modType)); else for (SourceType sourceType : SourceType.values()) { float amount = this.getFloat(modType, sourceType); float percentAmount = this.getFloatPercentPositive(modType, sourceType); float percentAmountNegative = this.getFloatPercentNegative(modType, sourceType); if (amount != 0) ChatManager.chatSystemInfo(pc, modType.name() + "-" + (sourceType.equals(SourceType.None) == false ? sourceType.name() : "") + " = " + amount); if (percentAmount != 0) ChatManager.chatSystemInfo(pc, "Percent : " + modType.name() + "-" + (sourceType.equals(SourceType.None) == false ? sourceType.name() : "") + " = " + percentAmount); if (percentAmountNegative != 0) ChatManager.chatSystemInfo(pc, "Negative Percent : " + modType.name() + "-" + (sourceType.equals(SourceType.None) == false ? sourceType.name() : "") + " = " + percentAmountNegative); } } } public void setBool(ModType modType, SourceType sourceType, boolean val) { if (val == true) { if (this.bonusBools.get(modType) == null) { HashMap sourceMap = new HashMap<>(); this.bonusBools.put(modType, sourceMap); } this.bonusBools.get(modType).put(sourceType, val); return; } if (this.bonusBools.containsKey(modType)) this.bonusBools.get(modType).remove(sourceType); } }