diff --git a/Server/src/main/content/data/consumables/Consumables.java b/Server/src/main/content/data/consumables/Consumables.java index d02f9f118..67791684b 100644 --- a/Server/src/main/content/data/consumables/Consumables.java +++ b/Server/src/main/content/data/consumables/Consumables.java @@ -353,7 +353,7 @@ public enum Consumables { FISHING(new Potion(new int[] {2438, 151, 153, 155}, new SkillEffect(Skills.FISHING, 3, 0))), PRAYER(new Potion(new int[] {2434, 139, 141, 143}, new PrayerEffect(7, 0.25))), SUPER_RESTO(new Potion(new int[] {3024, 3026, 3028, 3030}, new RestoreEffect(8, 0.25, true))), - ZAMMY_BREW(new Potion(new int[] {2450, 189, 191, 193}, new MultiEffect(new DamageEffect(10, true), new SkillEffect(Skills.ATTACK, 0, 0.25), new SkillEffect(Skills.STRENGTH, 0, 0.15), new SkillEffect(Skills.DEFENCE, 0, -0.1)))), + ZAMMY_BREW(new Potion(new int[] {2450, 189, 191, 193}, new MultiEffect(new DamageEffect(10, true, 2), new SkillEffect(Skills.ATTACK, 2, 0.20), new SkillEffect(Skills.STRENGTH, 2, 0.12), new SkillEffect(Skills.DEFENCE, -2, -0.10), new PrayerEffect(0.0, 0.10, true)))), ANTIFIRE(new Potion(new int[] {2452, 2454, 2456, 2458}, new AddTimerEffect("dragonfire:immunity", 600, true))), GUTH_REST(new Potion(new int[] {4417, 4419, 4421, 4423}, new MultiEffect(new RemoveTimerEffect("poison"), new EnergyEffect(5), new HealingEffect(5)))), MAGIC_ESS(new Potion(new int[] {9021, 9022, 9023, 9024}, new SkillEffect(Skills.MAGIC,3,0))), @@ -363,7 +363,7 @@ public enum Consumables { /** Barbarian Mixes */ PRAYERMIX(new BarbarianMix(new int[] {11465, 11467}, new MultiEffect(new PrayerEffect(7, 0.25), new HealingEffect(6)))), - ZAMMY_MIX(new BarbarianMix(new int[] {11521, 11523}, new MultiEffect(new DamageEffect(10, true), new SkillEffect(Skills.ATTACK, 0, 0.15), new SkillEffect(Skills.STRENGTH, 0, 0.25), new SkillEffect(Skills.DEFENCE, 0, -0.1)))), + ZAMMY_MIX(new BarbarianMix(new int[]{11521, 11523}, new MultiEffect(new ZamorakMixEffect(), new SkillEffect(Skills.ATTACK, 2, 0.20), new SkillEffect(Skills.STRENGTH, 2, 0.12), new SkillEffect(Skills.DEFENCE, -2, -0.10)))), ATT_MIX(new BarbarianMix(new int[] {11429, 11431}, new MultiEffect(new SkillEffect(Skills.ATTACK, 3, 0.1), new HealingEffect(3)))), ANTIP_MIX(new BarbarianMix(new int[] {11433, 11435}, new MultiEffect(new AddTimerEffect("poison:immunity", secondsToTicks(90)), new HealingEffect(3)))), RELIC_MIX(new BarbarianMix(new int[] {11437, 11439}, new MultiEffect(new CureDiseaseEffect(), new HealingEffect(3)))), diff --git a/Server/src/main/content/data/consumables/effects/DamageEffect.java b/Server/src/main/content/data/consumables/effects/DamageEffect.java index c4573306b..1b5e4778c 100644 --- a/Server/src/main/content/data/consumables/effects/DamageEffect.java +++ b/Server/src/main/content/data/consumables/effects/DamageEffect.java @@ -7,15 +7,21 @@ import core.game.node.entity.player.Player; public class DamageEffect extends ConsumableEffect { final double amt; final boolean isPercent; + final int baseAmount; - public DamageEffect(double amt,boolean isPercent){ + public DamageEffect(double amt, boolean isPercent) { + this(amt, isPercent, 0); + } + + public DamageEffect(double amt, boolean isPercent, int baseAmount) { this.amt = amt; this.isPercent = isPercent; + this.baseAmount = baseAmount; } @Override public void activate(Player p) { - p.getImpactHandler().manualHit(p,-getHealthEffectValue(p), ImpactHandler.HitsplatType.NORMAL); + p.getImpactHandler().manualHit(p, -getHealthEffectValue(p), ImpactHandler.HitsplatType.NORMAL); } @Override @@ -23,8 +29,8 @@ public class DamageEffect extends ConsumableEffect { double amount = amt; if (isPercent) { amount /= 100; - return (int) -(amount * player.getSkills().getLifepoints()); + return (int) -(amount * player.getSkills().getLifepoints() + baseAmount); } - return (int) -amt; + return (int) -(amt + baseAmount); } } diff --git a/Server/src/main/content/data/consumables/effects/PrayerEffect.kt b/Server/src/main/content/data/consumables/effects/PrayerEffect.kt index 9f636bc27..5edaff7dc 100644 --- a/Server/src/main/content/data/consumables/effects/PrayerEffect.kt +++ b/Server/src/main/content/data/consumables/effects/PrayerEffect.kt @@ -5,16 +5,18 @@ import core.game.consumable.ConsumableEffect import core.game.node.entity.player.Player import core.game.node.entity.skill.Skills import org.rs09.consts.Items +import kotlin.math.ceil import kotlin.math.floor -class PrayerEffect(var base: Double, var bonus: Double) : ConsumableEffect() { +class PrayerEffect @JvmOverloads constructor(var base: Double, var bonus: Double, private val roundUp: Boolean = false) : ConsumableEffect() { override fun activate(player: Player?) { if(player == null) return val level = getStatLevel(player, Skills.PRAYER) var b = bonus if(inInventory(player, Items.HOLY_WRENCH_6714)) b += 0.02 // Leaving this in for futureproofing. Current update is for properly rounding down. - val amount = floor(base + (level * b)) + val rawAmount = base + (level * b) + val amount = if (roundUp) ceil(rawAmount) else floor(rawAmount) modPrayerPoints(player, amount) } } \ No newline at end of file diff --git a/Server/src/main/content/data/consumables/effects/ZamorakMixEffect.java b/Server/src/main/content/data/consumables/effects/ZamorakMixEffect.java new file mode 100644 index 000000000..688da0961 --- /dev/null +++ b/Server/src/main/content/data/consumables/effects/ZamorakMixEffect.java @@ -0,0 +1,25 @@ +package content.data.consumables.effects; + +import core.game.consumable.ConsumableEffect; +import core.game.node.entity.combat.ImpactHandler; +import core.game.node.entity.player.Player; + +/** + * The Zamorak mix shows the regular Zamorak brew hitsplat (10% of pre-drink lifepoints + 2, rounded down) + * but also heals 6 lifepoints. The heal must be applied before the hit so the net change can never kill + * the player, while the hitsplat still reflects the pre-heal lifepoints. + */ +public class ZamorakMixEffect extends ConsumableEffect { + + @Override + public void activate(Player p) { + int damage = (int) (p.getSkills().getLifepoints() * 0.10 + 2); + p.getSkills().heal(6); + p.getImpactHandler().manualHit(p, damage, ImpactHandler.HitsplatType.NORMAL); + } + + @Override + public int getHealthEffectValue(Player player) { + return 6 - (int) (player.getSkills().getLifepoints() * 0.10 + 2); + } +} diff --git a/Server/src/test/kotlin/content/ZamorakBrewTests.kt b/Server/src/test/kotlin/content/ZamorakBrewTests.kt new file mode 100644 index 000000000..42d6c099a --- /dev/null +++ b/Server/src/test/kotlin/content/ZamorakBrewTests.kt @@ -0,0 +1,67 @@ +package content + +import TestUtils +import content.data.consumables.Consumables +import core.game.node.entity.skill.Skills +import core.game.node.item.Item +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.rs09.consts.Items + +class ZamorakBrewTests { + companion object { + init { + TestUtils.preTestSetup() + } + } + + @Test + fun zamorakBrewShouldDamageTenPercentOfCurrentLifepointsPlusTwo() { + TestUtils.getMockPlayer("zammybrewdrinker").use { p -> + p.skills.setStaticLevel(Skills.HITPOINTS, 99) + p.skills.lifepoints = 6 + p.inventory.clear() + p.inventory.add(Item(Items.ZAMORAK_BREW4_2450)) + + Consumables.getConsumableById(Items.ZAMORAK_BREW4_2450) + .consumable + .consume(p.inventory.get(0), p) + + Assertions.assertEquals(4, p.skills.lifepoints) + } + } + + @Test + fun zamorakMixDamageShouldBeBasedOnLifepointsBeforeItHeals() { + TestUtils.getMockPlayer("zammymixdrinker").use { p -> + p.skills.setStaticLevel(Skills.HITPOINTS, 99) + p.skills.lifepoints = 6 + p.inventory.clear() + p.inventory.add(Item(Items.ZAMORAK_MIX2_11521)) + + Consumables.getConsumableById(Items.ZAMORAK_MIX2_11521) + .consumable + .consume(p.inventory.get(0), p) + + // Damage on pre-drink lifepoints (10% of 6 + 2 = 2), then heal 6: 6 - 2 + 6 = 10 + Assertions.assertEquals(10, p.skills.lifepoints) + } + } + + @Test + fun zamorakMixShouldNotKillAtLowLifepoints() { + TestUtils.getMockPlayer("zammymixlowhp").use { p -> + p.skills.setStaticLevel(Skills.HITPOINTS, 99) + p.skills.lifepoints = 2 + p.inventory.clear() + p.inventory.add(Item(Items.ZAMORAK_MIX2_11521)) + + Consumables.getConsumableById(Items.ZAMORAK_MIX2_11521) + .consumable + .consume(p.inventory.get(0), p) + + // Hitsplat shows 2 (10% of 2 + 2), but the heal lands first: 2 + 6 - 2 = 6, no death + Assertions.assertEquals(6, p.skills.lifepoints) + } + } +}