diff --git a/Changelog.txt b/Changelog.txt index 96529da12..018795586 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,6 @@ Version 2.1.175 + (API) Many skills with RNG elements now send out a SubSkillEvent (which can be used to modify probability or cancel the results), some skills without RNG still send out this event when activated, this event is cancellable so it can be used to make a skill fail + Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk Added a setting to chat.yml to toggle sending party or admin chat messages to console Added a set of "mastery" subskills meant for end game progression Added the mastery subskill 'Mother Lode' to Mining diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 8a7df7ac0..d1e9b45a9 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -28,6 +28,8 @@ import org.bukkit.Color; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Tameable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -215,7 +217,7 @@ public enum PrimarySkillType { } } - public static PrimarySkillType bySecondaryAbility(SubSkillType subSkillType) { + public static @Nullable PrimarySkillType bySecondaryAbility(@NotNull SubSkillType subSkillType) { for (PrimarySkillType type : values()) { if (type.getSkillAbilities().contains(subSkillType)) { return type; diff --git a/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerSkillEvent.java b/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerSkillEvent.java index e899ea528..6238886c0 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerSkillEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerSkillEvent.java @@ -11,10 +11,10 @@ import org.jetbrains.annotations.NotNull; * Generic event for mcMMO skill handling. */ public abstract class McMMOPlayerSkillEvent extends PlayerEvent { - protected PrimarySkillType skill; + protected @NotNull PrimarySkillType skill; protected int skillLevel; - protected McMMOPlayerSkillEvent(Player player, PrimarySkillType skill) { + protected McMMOPlayerSkillEvent(@NotNull Player player, @NotNull PrimarySkillType skill) { super(player); this.skill = skill; this.skillLevel = UserManager.getPlayer(player).getSkillLevel(skill); @@ -23,7 +23,7 @@ public abstract class McMMOPlayerSkillEvent extends PlayerEvent { /** * @return The skill involved in this event */ - public PrimarySkillType getSkill() { + public @NotNull PrimarySkillType getSkill() { return skill; } diff --git a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java index ee4fbb873..88912d764 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java @@ -1,48 +1,36 @@ package com.gmail.nossr50.events.skills.secondaryabilities; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; +import org.jetbrains.annotations.NotNull; public class SubSkillEvent extends McMMOPlayerSkillEvent implements Cancellable { - private SubSkillType subSkillType; + private final @NotNull SubSkillType subSkillType; private boolean cancelled = false; private double resultModifier = 1.0D; /** - * Only skills using the old system will fire this event * @param player target player * @param subSkillType target subskill - * @Deprecated Skills will be using a new system stemming from the AbstractSubSkill class so make sure you check for both events, this event will be removed eventually. */ - @Deprecated - public SubSkillEvent(Player player, SubSkillType subSkillType) { - super(player, PrimarySkillType.bySecondaryAbility(subSkillType)); + public SubSkillEvent(@NotNull Player player, @NotNull SubSkillType subSkillType) { + super(player, subSkillType.getParentSkill()); this.subSkillType = subSkillType; } /** - * Only skills using the old system will fire this event * @param player target player * @param subSkillType target subskill - * @param resultModifier a value multiplied against the final result of the dice roll, typically between 0-1.0 - * @Deprecated Skills will be using a new system stemming from the AbstractSubSkill class so make sure you check for both events, this event will be removed eventually. + * @param resultModifier a value multiplied against the probability (1.5 would increase probability by 50%) */ - @Deprecated - public SubSkillEvent(Player player, SubSkillType subSkillType, double resultModifier) { - super(player, PrimarySkillType.bySecondaryAbility(subSkillType)); + public SubSkillEvent(@NotNull Player player, @NotNull SubSkillType subSkillType, double resultModifier) { + super(player, subSkillType.getParentSkill()); this.subSkillType = subSkillType; this.resultModifier = resultModifier; } - public SubSkillEvent(Player player, AbstractSubSkill abstractSubSkill) - { - super(player, abstractSubSkill.getPrimarySkill()); - } - public double getResultModifier() { return resultModifier; } @@ -55,7 +43,7 @@ public class SubSkillEvent extends McMMOPlayerSkillEvent implements Cancellable * Gets the SubSkillType involved in the event * @return the SubSkillType */ - public SubSkillType getSubSkillType() { + public @NotNull SubSkillType getSubSkillType() { return subSkillType; } diff --git a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java index c3d2756b6..e3f9db0af 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java @@ -10,7 +10,6 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Location; import org.bukkit.entity.Entity; @@ -116,10 +115,10 @@ public class ArcheryManager extends SkillManager { * @param oldDamage The raw damage value of this arrow before we modify it */ public double skillShot(double oldDamage) { - if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) { + if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) { + return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage); + } else { return oldDamage; } - - return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage); } } diff --git a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java index 73593a362..d654e2fdd 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java @@ -11,8 +11,10 @@ import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; -import com.gmail.nossr50.util.random.SkillProbabilityType; -import com.gmail.nossr50.util.skills.*; +import com.gmail.nossr50.util.skills.CombatUtils; +import com.gmail.nossr50.util.skills.ParticleEffectUtils; +import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityDamageEvent.DamageModifier; @@ -69,11 +71,11 @@ public class AxesManager extends SkillManager { * Handle the effects of the Axe Mastery ability */ public double axeMastery() { - if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.AXES_AXE_MASTERY, getPlayer())) { - return 0; + if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.AXES_AXE_MASTERY, getPlayer())) { + return Axes.getAxeMasteryBonusDamage(getPlayer()); } - return Axes.getAxeMasteryBonusDamage(getPlayer()); + return 0; } /** diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java index 797595146..744c23a43 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java @@ -17,7 +17,6 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Material; import org.bukkit.block.BlockState; @@ -72,7 +71,7 @@ public class UnarmedManager extends SkillManager { } public boolean blockCrackerCheck(@NotNull BlockState blockState) { - if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) { + if (!SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) { return false; } @@ -149,11 +148,11 @@ public class UnarmedManager extends SkillManager { * Handle the effects of the Iron Arm ability */ public double calculateSteelArmStyleDamage() { - if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) { - return 0; + if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) { + return getSteelArmStyleDamage(); } - return getSteelArmStyleDamage(); + return 0; } public double getSteelArmStyleDamage() { diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index e1f2d1b97..6d9530019 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -9,7 +9,6 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.experience.McMMOPlayerLevelChangeEvent; import com.gmail.nossr50.events.experience.McMMOPlayerLevelDownEvent; import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent; @@ -190,8 +189,7 @@ public final class EventUtils { * @param subSkillType target subskill * @return the event after it has been fired */ - @Deprecated - public static @NotNull SubSkillEvent callSubSkillEvent(Player player, SubSkillType subSkillType) { + public static @NotNull SubSkillEvent callSubSkillEvent(@NotNull Player player, @NotNull SubSkillType subSkillType) { SubSkillEvent event = new SubSkillEvent(player, subSkillType); mcMMO.p.getServer().getPluginManager().callEvent(event); @@ -213,19 +211,6 @@ public final class EventUtils { return event; } - /** - * Calls a new SubSkillEvent for this SubSkill and then returns it - * @param player target player - * @param abstractSubSkill target subskill - * @return the event after it has been fired - */ - public static SubSkillEvent callSubSkillEvent(Player player, AbstractSubSkill abstractSubSkill) { - SubSkillEvent event = new SubSkillEvent(player, abstractSubSkill); - mcMMO.p.getServer().getPluginManager().callEvent(event); - - return event; - } - public static FakePlayerAnimationEvent callFakeArmSwingEvent(Player player) { FakePlayerAnimationEvent event = new FakePlayerAnimationEvent(player); mcMMO.p.getServer().getPluginManager().callEvent(event); diff --git a/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java index 6401ca757..e5b4a5cc8 100644 --- a/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java +++ b/src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java @@ -13,9 +13,7 @@ public class ProbabilityImpl implements Probability { * @param staticProbability the value to assign to this probability */ public ProbabilityImpl(double staticProbability) throws ValueOutOfBoundsException { - if(staticProbability > 1) { - throw new ValueOutOfBoundsException("Value should never be above 1 for Probability! This suggests a coding mistake, contact the devs!"); - } else if (staticProbability < 0) { + if (staticProbability < 0) { throw new ValueOutOfBoundsException("Value should never be negative for Probability! This suggests a coding mistake, contact the devs!"); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index 13c404963..799a9c2f8 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -10,8 +10,10 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; @@ -348,16 +350,34 @@ public final class SkillUtils { * * 3) Creates a {@link Probability} and pipes it to {@link RandomChanceUtil} which processes the result and returns it * + * This also calls a {@link SubSkillEvent} which can be cancelled, if it is cancelled this will return false + * The outcome of the probability can also be modified by this event that is called + * * @param subSkillType target subskill * @param player target player, can be null (null players are given odds equivalent to a player with no levels or luck) * @return true if the Skill RNG succeeds, false if it fails */ - public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, @Nullable Player player) { + public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, @NotNull Player player) { try { //Process probability Probability probability = getSubSkillProbability(subSkillType, player); - //Player can be null - boolean isLucky = player != null && Permissions.lucky(player, subSkillType.getParentSkill()); + + //Send out event + SubSkillEvent subSkillEvent = EventUtils.callSubSkillEvent(player, subSkillType); + + if(subSkillEvent.isCancelled()) { + return false; //Event got cancelled so this doesn't succeed + } + + //Result modifier + double resultModifier = subSkillEvent.getResultModifier(); + + //Mutate probability + if(resultModifier != 1.0D) + probability = ProbabilityFactory.ofPercentageValue(probability.getValue() * resultModifier); + + //Luck + boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill()); if(isLucky) { return RandomChanceUtil.processProbability(probability, RandomChanceUtil.LUCKY_MODIFIER); @@ -407,6 +427,16 @@ public final class SkillUtils { } } + /** + * Skills activate without RNG, this allows other plugins to prevent that activation + * @param subSkillType target subskill + * @param player target player + * @return true if the skill succeeds (wasn't cancelled by any other plugin) + */ + public static boolean isNonRNGSkillActivationSuccessful(@NotNull SubSkillType subSkillType, @NotNull Player player) { + return !EventUtils.callSubSkillEvent(player, subSkillType).isCancelled(); + } + /** * Grab the {@link Probability} for a specific {@link SubSkillType} for a specific {@link Player} *