Browse Source

Refactor Probability API a bit

nossr50 2 years ago
parent
commit
59f711834b
39 changed files with 433 additions and 397 deletions
  1. 3 3
      src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java
  2. 3 3
      src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java
  3. 2 2
      src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java
  4. 3 3
      src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java
  5. 5 5
      src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java
  6. 3 3
      src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java
  7. 2 2
      src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java
  8. 0 2
      src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java
  9. 2 2
      src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java
  10. 2 3
      src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java
  11. 2 2
      src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java
  12. 4 4
      src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java
  13. 3 3
      src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java
  14. 11 12
      src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java
  15. 2 3
      src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java
  16. 2 2
      src/main/java/com/gmail/nossr50/listeners/EntityListener.java
  17. 2 1
      src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java
  18. 3 3
      src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java
  19. 5 4
      src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java
  20. 3 2
      src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java
  21. 2 1
      src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java
  22. 6 5
      src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java
  23. 3 2
      src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java
  24. 4 3
      src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java
  25. 4 3
      src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java
  26. 2 2
      src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java
  27. 3 5
      src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java
  28. 3 3
      src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java
  29. 6 6
      src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java
  30. 4 5
      src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java
  31. 2 2
      src/main/java/com/gmail/nossr50/util/BlockUtils.java
  32. 31 48
      src/main/java/com/gmail/nossr50/util/random/Probability.java
  33. 1 1
      src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java
  34. 226 0
      src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java
  35. 0 84
      src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java
  36. 0 127
      src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java
  37. 52 20
      src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java
  38. 22 0
      src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java
  39. 0 16
      src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java

+ 3 - 3
src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java

@@ -6,7 +6,7 @@ import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill;
 import com.gmail.nossr50.listeners.InteractionManager;
 import com.gmail.nossr50.listeners.InteractionManager;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
-import com.gmail.nossr50.util.skills.SkillUtils;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
@@ -29,7 +29,7 @@ public class AcrobaticsCommand extends SkillCommand {
     protected void dataCalculations(Player player, float skillValue) {
     protected void dataCalculations(Player player, float skillValue) {
         // ACROBATICS_DODGE
         // ACROBATICS_DODGE
         if (canDodge) {
         if (canDodge) {
-            String[] dodgeStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ACROBATICS_DODGE);
+            String[] dodgeStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.ACROBATICS_DODGE);
             dodgeChance = dodgeStrings[0];
             dodgeChance = dodgeStrings[0];
             dodgeChanceLucky = dodgeStrings[1];
             dodgeChanceLucky = dodgeStrings[1];
         }
         }
@@ -56,7 +56,7 @@ public class AcrobaticsCommand extends SkillCommand {
 
 
             if(abstractSubSkill != null)
             if(abstractSubSkill != null)
             {
             {
-                String[] rollStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ACROBATICS_ROLL);
+                String[] rollStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.ACROBATICS_ROLL);
 
 
                 messages.add(getStatMessage(SubSkillType.ACROBATICS_ROLL, rollStrings[0])
                 messages.add(getStatMessage(SubSkillType.ACROBATICS_ROLL, rollStrings[0])
                         + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", rollStrings[1]) : ""));
                         + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", rollStrings[1]) : ""));

+ 3 - 3
src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java

@@ -5,8 +5,8 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.archery.Archery;
 import com.gmail.nossr50.skills.archery.Archery;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.CombatUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
@@ -33,14 +33,14 @@ public class ArcheryCommand extends SkillCommand {
     protected void dataCalculations(Player player, float skillValue) {
     protected void dataCalculations(Player player, float skillValue) {
         // ARCHERY_ARROW_RETRIEVAL
         // ARCHERY_ARROW_RETRIEVAL
         if (canRetrieve) {
         if (canRetrieve) {
-            String[] retrieveStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ARCHERY_ARROW_RETRIEVAL);
+            String[] retrieveStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.ARCHERY_ARROW_RETRIEVAL);
             retrieveChance = retrieveStrings[0];
             retrieveChance = retrieveStrings[0];
             retrieveChanceLucky = retrieveStrings[1];
             retrieveChanceLucky = retrieveStrings[1];
         }
         }
         
         
         // ARCHERY_DAZE
         // ARCHERY_DAZE
         if (canDaze) {
         if (canDaze) {
-            String[] dazeStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ARCHERY_DAZE);
+            String[] dazeStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.ARCHERY_DAZE);
             dazeChance = dazeStrings[0];
             dazeChance = dazeStrings[0];
             dazeChanceLucky = dazeStrings[1];
             dazeChanceLucky = dazeStrings[1];
         }
         }

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java

@@ -6,9 +6,9 @@ import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.axes.Axes;
 import com.gmail.nossr50.skills.axes.Axes;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
@@ -48,7 +48,7 @@ public class AxesCommand extends SkillCommand {
         
         
         // CRITICAL HIT
         // CRITICAL HIT
         if (canCritical) {
         if (canCritical) {
-            String[] criticalHitStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.AXES_CRITICAL_STRIKES);
+            String[] criticalHitStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.AXES_CRITICAL_STRIKES);
             critChance = criticalHitStrings[0];
             critChance = criticalHitStrings[0];
             critChanceLucky = criticalHitStrings[1];
             critChanceLucky = criticalHitStrings[1];
         }
         }

+ 3 - 3
src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java

@@ -10,8 +10,8 @@ import com.gmail.nossr50.skills.fishing.FishingManager;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.random.Probability;
 import com.gmail.nossr50.util.random.Probability;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.text.StringUtils;
 import com.gmail.nossr50.util.text.StringUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
@@ -81,8 +81,8 @@ public class FishingCommand extends SkillCommand {
 
 
         // FISHING_SHAKE
         // FISHING_SHAKE
         if (canShake) {
         if (canShake) {
-            Probability shakeProbability = Probability.ofPercentageValue(fishingManager.getShakeChance());
-            String[] shakeStrings = SkillUtils.getRNGDisplayValues(shakeProbability);
+            Probability shakeProbability = Probability.ofPercent(fishingManager.getShakeChance());
+            String[] shakeStrings = ProbabilityUtil.getRNGDisplayValues(shakeProbability);
             shakeChance = shakeStrings[0];
             shakeChance = shakeStrings[0];
             shakeChanceLucky = shakeStrings[1];
             shakeChanceLucky = shakeStrings[1];
         }
         }

+ 5 - 5
src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java

@@ -5,8 +5,8 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.Material;
 import org.bukkit.Material;
@@ -46,7 +46,7 @@ public class HerbalismCommand extends SkillCommand {
         
         
         // DOUBLE DROPS
         // DOUBLE DROPS
         if (canDoubleDrop) {
         if (canDoubleDrop) {
-            String[] doubleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_DOUBLE_DROPS);
+            String[] doubleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.HERBALISM_DOUBLE_DROPS);
             doubleDropChance = doubleDropStrings[0];
             doubleDropChance = doubleDropStrings[0];
             doubleDropChanceLucky = doubleDropStrings[1];
             doubleDropChanceLucky = doubleDropStrings[1];
         }
         }
@@ -67,21 +67,21 @@ public class HerbalismCommand extends SkillCommand {
         if (canGreenThumbBlocks || canGreenThumbPlants) {
         if (canGreenThumbBlocks || canGreenThumbPlants) {
             greenThumbStage = RankUtils.getRank(player, SubSkillType.HERBALISM_GREEN_THUMB);
             greenThumbStage = RankUtils.getRank(player, SubSkillType.HERBALISM_GREEN_THUMB);
 
 
-            String[] greenThumbStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_GREEN_THUMB);
+            String[] greenThumbStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.HERBALISM_GREEN_THUMB);
             greenThumbChance = greenThumbStrings[0];
             greenThumbChance = greenThumbStrings[0];
             greenThumbChanceLucky = greenThumbStrings[1];
             greenThumbChanceLucky = greenThumbStrings[1];
         }
         }
 
 
         // HYLIAN LUCK
         // HYLIAN LUCK
         if (hasHylianLuck) {
         if (hasHylianLuck) {
-            String[] hylianLuckStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_HYLIAN_LUCK);
+            String[] hylianLuckStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.HERBALISM_HYLIAN_LUCK);
             hylianLuckChance = hylianLuckStrings[0];
             hylianLuckChance = hylianLuckStrings[0];
             hylianLuckChanceLucky = hylianLuckStrings[1];
             hylianLuckChanceLucky = hylianLuckStrings[1];
         }
         }
 
 
         // SHROOM THUMB
         // SHROOM THUMB
         if (canShroomThumb) {
         if (canShroomThumb) {
-            String[] shroomThumbStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.HERBALISM_SHROOM_THUMB);
+            String[] shroomThumbStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.HERBALISM_SHROOM_THUMB);
             shroomThumbChance = shroomThumbStrings[0];
             shroomThumbChance = shroomThumbStrings[0];
             shroomThumbChanceLucky = shroomThumbStrings[1];
             shroomThumbChanceLucky = shroomThumbStrings[1];
         }
         }

+ 3 - 3
src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java

@@ -6,8 +6,8 @@ import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.mining.MiningManager;
 import com.gmail.nossr50.skills.mining.MiningManager;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
@@ -57,14 +57,14 @@ public class MiningCommand extends SkillCommand {
 
 
         // Mastery TRIPLE DROPS
         // Mastery TRIPLE DROPS
         if (canMotherLode) {
         if (canMotherLode) {
-            String[] masteryTripleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.MINING_MOTHER_LODE);
+            String[] masteryTripleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.MINING_MOTHER_LODE);
             tripleDropChance = masteryTripleDropStrings[0];
             tripleDropChance = masteryTripleDropStrings[0];
             tripleDropChanceLucky = masteryTripleDropStrings[1];
             tripleDropChanceLucky = masteryTripleDropStrings[1];
         }
         }
         
         
         // DOUBLE DROPS
         // DOUBLE DROPS
         if (canDoubleDrop) {
         if (canDoubleDrop) {
-            String[] doubleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.MINING_DOUBLE_DROPS);
+            String[] doubleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.MINING_DOUBLE_DROPS);
             doubleDropChance = doubleDropStrings[0];
             doubleDropChance = doubleDropStrings[0];
             doubleDropChanceLucky = doubleDropStrings[1];
             doubleDropChanceLucky = doubleDropStrings[1];
         }
         }

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java

@@ -11,8 +11,8 @@ import com.gmail.nossr50.skills.repair.RepairManager;
 import com.gmail.nossr50.skills.repair.repairables.Repairable;
 import com.gmail.nossr50.skills.repair.repairables.Repairable;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.Material;
 import org.bukkit.Material;
@@ -68,7 +68,7 @@ public class RepairCommand extends SkillCommand {
 
 
         // SUPER REPAIR
         // SUPER REPAIR
         if (canSuperRepair) {
         if (canSuperRepair) {
-            String[] superRepairStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.REPAIR_SUPER_REPAIR);
+            String[] superRepairStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.REPAIR_SUPER_REPAIR);
             superRepairChance = superRepairStrings[0];
             superRepairChance = superRepairStrings[0];
             superRepairChanceLucky = superRepairStrings[1];
             superRepairChanceLucky = superRepairStrings[1];
         }
         }

+ 0 - 2
src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java

@@ -10,11 +10,9 @@ import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.commands.CommandUtils;
 import com.gmail.nossr50.util.commands.CommandUtils;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
-import com.gmail.nossr50.util.random.RandomChanceUtil;
 import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
 import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
 import com.gmail.nossr50.util.skills.PerksUtils;
 import com.gmail.nossr50.util.skills.PerksUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillActivationType;
 import com.gmail.nossr50.util.skills.SkillTools;
 import com.gmail.nossr50.util.skills.SkillTools;
 import com.gmail.nossr50.util.text.StringUtils;
 import com.gmail.nossr50.util.text.StringUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java

@@ -5,8 +5,8 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
@@ -46,7 +46,7 @@ public class SmeltingCommand extends SkillCommand {
         
         
         // SECOND SMELT
         // SECOND SMELT
         if (canSecondSmelt) {
         if (canSecondSmelt) {
-            String[] secondSmeltStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.SMELTING_SECOND_SMELT);
+            String[] secondSmeltStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.SMELTING_SECOND_SMELT);
             str_secondSmeltChance = secondSmeltStrings[0];
             str_secondSmeltChance = secondSmeltStrings[0];
             str_secondSmeltChanceLucky = secondSmeltStrings[1];
             str_secondSmeltChanceLucky = secondSmeltStrings[1];
         }
         }

+ 2 - 3
src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java

@@ -6,10 +6,9 @@ import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
@@ -39,7 +38,7 @@ public class SwordsCommand extends SkillCommand {
     protected void dataCalculations(Player player, float skillValue) {
     protected void dataCalculations(Player player, float skillValue) {
         // SWORDS_COUNTER_ATTACK
         // SWORDS_COUNTER_ATTACK
         if (canCounter) {
         if (canCounter) {
-            String[] counterStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.SWORDS_COUNTER_ATTACK);
+            String[] counterStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.SWORDS_COUNTER_ATTACK);
             counterChance = counterStrings[0];
             counterChance = counterStrings[0];
             counterChanceLucky = counterStrings[1];
             counterChanceLucky = counterStrings[1];
         }
         }

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java

@@ -5,7 +5,7 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.taming.Taming;
 import com.gmail.nossr50.skills.taming.Taming;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
-import com.gmail.nossr50.util.skills.SkillUtils;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.entity.EntityType;
 import org.bukkit.entity.EntityType;
@@ -35,7 +35,7 @@ public class TamingCommand extends SkillCommand {
     @Override
     @Override
     protected void dataCalculations(Player player, float skillValue) {
     protected void dataCalculations(Player player, float skillValue) {
         if (canGore) {
         if (canGore) {
-            String[] goreStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.TAMING_GORE);
+            String[] goreStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.TAMING_GORE);
             goreChance = goreStrings[0];
             goreChance = goreStrings[0];
             goreChanceLucky = goreStrings[1];
             goreChanceLucky = goreStrings[1];
         }
         }

+ 4 - 4
src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java

@@ -5,9 +5,9 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
@@ -40,7 +40,7 @@ public class UnarmedCommand extends SkillCommand {
     protected void dataCalculations(Player player, float skillValue) {
     protected void dataCalculations(Player player, float skillValue) {
         // UNARMED_ARROW_DEFLECT
         // UNARMED_ARROW_DEFLECT
         if (canDeflect) {
         if (canDeflect) {
-            String[] deflectStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.UNARMED_ARROW_DEFLECT);
+            String[] deflectStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.UNARMED_ARROW_DEFLECT);
             deflectChance = deflectStrings[0];
             deflectChance = deflectStrings[0];
             deflectChanceLucky = deflectStrings[1];
             deflectChanceLucky = deflectStrings[1];
         }
         }
@@ -54,7 +54,7 @@ public class UnarmedCommand extends SkillCommand {
 
 
         // UNARMED_DISARM
         // UNARMED_DISARM
         if (canDisarm) {
         if (canDisarm) {
-            String[] disarmStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.UNARMED_DISARM);
+            String[] disarmStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.UNARMED_DISARM);
             disarmChance = disarmStrings[0];
             disarmChance = disarmStrings[0];
             disarmChanceLucky = disarmStrings[1];
             disarmChanceLucky = disarmStrings[1];
         }
         }
@@ -66,7 +66,7 @@ public class UnarmedCommand extends SkillCommand {
 
 
         // IRON GRIP
         // IRON GRIP
         if (canIronGrip) {
         if (canIronGrip) {
-            String[] ironGripStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.UNARMED_IRON_GRIP);
+            String[] ironGripStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.UNARMED_IRON_GRIP);
             ironGripChance = ironGripStrings[0];
             ironGripChance = ironGripStrings[0];
             ironGripChanceLucky = ironGripStrings[1];
             ironGripChanceLucky = ironGripStrings[1];
         }
         }

+ 3 - 3
src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java

@@ -5,8 +5,8 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.Component;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
@@ -41,7 +41,7 @@ public class WoodcuttingCommand extends SkillCommand {
 
 
         //Clean Cuts
         //Clean Cuts
         if(canTripleDrop) {
         if(canTripleDrop) {
-            String[] tripleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.WOODCUTTING_CLEAN_CUTS);
+            String[] tripleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.WOODCUTTING_CLEAN_CUTS);
             tripleDropChance = tripleDropStrings[0];
             tripleDropChance = tripleDropStrings[0];
             tripleDropChanceLucky = tripleDropStrings[1];
             tripleDropChanceLucky = tripleDropStrings[1];
         }
         }
@@ -55,7 +55,7 @@ public class WoodcuttingCommand extends SkillCommand {
     }
     }
 
 
     private void setDoubleDropClassicChanceStrings(Player player) {
     private void setDoubleDropClassicChanceStrings(Player player) {
-        String[] doubleDropStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER);
+        String[] doubleDropStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER);
         doubleDropChance = doubleDropStrings[0];
         doubleDropChance = doubleDropStrings[0];
         doubleDropChanceLucky = doubleDropStrings[1];
         doubleDropChanceLucky = doubleDropStrings[1];
     }
     }

+ 11 - 12
src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java

@@ -15,10 +15,9 @@ import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.random.Probability;
 import com.gmail.nossr50.util.random.Probability;
-import com.gmail.nossr50.util.random.ProbabilityImpl;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.PerksUtils;
 import com.gmail.nossr50.util.skills.PerksUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillActivationType;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundType;
 import com.gmail.nossr50.util.sounds.SoundType;
@@ -129,7 +128,7 @@ public class Roll extends AcrobaticsSubSkill {
         float skillValue = playerProfile.getSkillLevel(getPrimarySkill());
         float skillValue = playerProfile.getSkillLevel(getPrimarySkill());
         boolean isLucky = Permissions.lucky(player, getPrimarySkill());
         boolean isLucky = Permissions.lucky(player, getPrimarySkill());
 
 
-        String[] rollStrings = SkillUtils.getRNGDisplayValues(player, SubSkillType.ACROBATICS_ROLL);
+        String[] rollStrings = ProbabilityUtil.getRNGDisplayValues(player, SubSkillType.ACROBATICS_ROLL);
         rollChance = rollStrings[0];
         rollChance = rollStrings[0];
         rollChanceLucky = rollStrings[1];
         rollChanceLucky = rollStrings[1];
 
 
@@ -137,8 +136,8 @@ public class Roll extends AcrobaticsSubSkill {
          * Graceful is double the odds of a normal roll
          * Graceful is double the odds of a normal roll
          */
          */
         Probability probability = getRollProbability(player);
         Probability probability = getRollProbability(player);
-        Probability gracefulProbability = Probability.ofPercentageValue(probability.getValue() * 2);
-        String[] gracefulRollStrings = SkillUtils.getRNGDisplayValues(gracefulProbability);
+        Probability gracefulProbability = Probability.ofPercent(probability.getValue() * 2);
+        String[] gracefulRollStrings = ProbabilityUtil.getRNGDisplayValues(gracefulProbability);
         gracefulRollChance = gracefulRollStrings[0];
         gracefulRollChance = gracefulRollStrings[0];
         gracefulRollChanceLucky = gracefulRollStrings[1];
         gracefulRollChanceLucky = gracefulRollStrings[1];
 
 
@@ -171,7 +170,7 @@ public class Roll extends AcrobaticsSubSkill {
 
 
     @NotNull
     @NotNull
     private Probability getRollProbability(Player player) {
     private Probability getRollProbability(Player player) {
-        return SkillUtils.getSubSkillProbability(SubSkillType.ACROBATICS_ROLL, player);
+        return ProbabilityUtil.getSubSkillProbability(SubSkillType.ACROBATICS_ROLL, player);
     }
     }
 
 
     @Override
     @Override
@@ -210,7 +209,7 @@ public class Roll extends AcrobaticsSubSkill {
         double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold());
         double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold());
 
 
         if (!isFatal(player, modifiedDamage)
         if (!isFatal(player, modifiedDamage)
-                && SkillUtils.isSkillRNGSuccessful(SubSkillType.ACROBATICS_ROLL, player)) {
+                && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ACROBATICS_ROLL, player)) {
             NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Roll.Text");
             NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Roll.Text");
             SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS);
             SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS);
             //player.sendMessage(LocaleLoader.getString("Acrobatics.Roll.Text"));
             //player.sendMessage(LocaleLoader.getString("Acrobatics.Roll.Text"));
@@ -247,12 +246,12 @@ public class Roll extends AcrobaticsSubSkill {
     private double gracefulRollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage, int skillLevel) {
     private double gracefulRollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage, int skillLevel) {
         double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold() * 2);
         double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold() * 2);
 
 
-        double gracefulOdds = SkillUtils.getSubSkillProbability(subSkillType, player).getValue() * 2;
-        Probability gracefulProbability = Probability.ofPercentageValue(gracefulOdds);
+        double gracefulOdds = ProbabilityUtil.getSubSkillProbability(subSkillType, player).getValue() * 2;
+        Probability gracefulProbability = Probability.ofPercent(gracefulOdds);
 
 
         if (!isFatal(player, modifiedDamage)
         if (!isFatal(player, modifiedDamage)
                 //TODO: Graceful isn't sending out an event
                 //TODO: Graceful isn't sending out an event
-                && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.ACROBATICS, player, gracefulProbability))
+                && ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.ACROBATICS, player, gracefulProbability))
         {
         {
             NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Ability.Proc");
             NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Ability.Proc");
             SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS,0.5F);
             SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS,0.5F);
@@ -421,10 +420,10 @@ public class Roll extends AcrobaticsSubSkill {
     @Override
     @Override
     public Double[] getStats(Player player)
     public Double[] getStats(Player player)
     {
     {
-        double playerChanceRoll = SkillUtils.getSubSkillProbability(subSkillType, player).getValue();
+        double playerChanceRoll = ProbabilityUtil.getSubSkillProbability(subSkillType, player).getValue();
         double playerChanceGrace = playerChanceRoll * 2;
         double playerChanceGrace = playerChanceRoll * 2;
 
 
-        double gracefulOdds = SkillUtils.getSubSkillProbability(subSkillType, player).getValue() * 2;
+        double gracefulOdds = ProbabilityUtil.getSubSkillProbability(subSkillType, player).getValue() * 2;
 
 
         return new Double[]{ playerChanceRoll, playerChanceGrace };
         return new Double[]{ playerChanceRoll, playerChanceGrace };
     }
     }

+ 2 - 3
src/main/java/com/gmail/nossr50/datatypes/treasure/Treasure.java

@@ -1,7 +1,6 @@
 package com.gmail.nossr50.datatypes.treasure;
 package com.gmail.nossr50.datatypes.treasure;
 
 
 import com.gmail.nossr50.util.random.Probability;
 import com.gmail.nossr50.util.random.Probability;
-import com.gmail.nossr50.util.random.ProbabilityImpl;
 import com.google.common.base.Objects;
 import com.google.common.base.Objects;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.ItemStack;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.NotNull;
@@ -17,7 +16,7 @@ public abstract class Treasure {
         this.drop = drop;
         this.drop = drop;
         this.xp = xp;
         this.xp = xp;
         this.dropChance = dropChance;
         this.dropChance = dropChance;
-        this.dropProbability = Probability.ofPercentageValue(dropChance / 100);
+        this.dropProbability = Probability.ofPercent(dropChance / 100);
         this.dropLevel = dropLevel;
         this.dropLevel = dropLevel;
     }
     }
 
 
@@ -47,7 +46,7 @@ public abstract class Treasure {
 
 
     public void setDropChance(double dropChance) {
     public void setDropChance(double dropChance) {
         this.dropChance = dropChance;
         this.dropChance = dropChance;
-        this.dropProbability = Probability.ofPercentageValue(dropChance / 100);
+        this.dropProbability = Probability.ofPercent(dropChance / 100);
     }
     }
 
 
     public int getDropLevel() {
     public int getDropLevel() {

+ 2 - 2
src/main/java/com/gmail/nossr50/listeners/EntityListener.java

@@ -23,8 +23,8 @@ import com.gmail.nossr50.skills.unarmed.UnarmedManager;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.CombatUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.worldguard.WorldGuardManager;
 import com.gmail.nossr50.worldguard.WorldGuardManager;
 import com.gmail.nossr50.worldguard.WorldGuardUtils;
 import com.gmail.nossr50.worldguard.WorldGuardUtils;
 import org.bukkit.ChatColor;
 import org.bukkit.ChatColor;
@@ -196,7 +196,7 @@ public class EntityListener implements Listener {
                     return;
                     return;
                 }
                 }
 
 
-                if (SkillUtils.isSkillRNGSuccessful(SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) {
+                if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) {
                     projectile.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, MetadataConstants.MCMMO_METADATA_VALUE);
                     projectile.setMetadata(MetadataConstants.METADATA_KEY_TRACKED_ARROW, MetadataConstants.MCMMO_METADATA_VALUE);
                 }
                 }
             }
             }

+ 2 - 1
src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java

@@ -14,6 +14,7 @@ import com.gmail.nossr50.util.MetadataConstants;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.ParticleEffectUtils;
 import com.gmail.nossr50.util.skills.ParticleEffectUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
@@ -93,7 +94,7 @@ public class AcrobaticsManager extends SkillManager {
         Player player = getPlayer();
         Player player = getPlayer();
 
 
         if (!isFatal(modifiedDamage)
         if (!isFatal(modifiedDamage)
-                && SkillUtils.isSkillRNGSuccessful(SubSkillType.ACROBATICS_DODGE, player)) {
+                && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ACROBATICS_DODGE, player)) {
             ParticleEffectUtils.playDodgeEffect(player);
             ParticleEffectUtils.playDodgeEffect(player);
 
 
             if (mmoPlayer.useChatNotifications()) {
             if (mmoPlayer.useChatNotifications()) {

+ 3 - 3
src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java

@@ -10,8 +10,8 @@ import com.gmail.nossr50.util.MetadataConstants;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import org.bukkit.Location;
 import org.bukkit.Location;
 import org.bukkit.entity.Entity;
 import org.bukkit.entity.Entity;
 import org.bukkit.entity.LivingEntity;
 import org.bukkit.entity.LivingEntity;
@@ -88,7 +88,7 @@ public class ArcheryManager extends SkillManager {
      * @param defender The {@link Player} being affected by the ability
      * @param defender The {@link Player} being affected by the ability
      */
      */
     public double daze(Player defender) {
     public double daze(Player defender) {
-        if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.ARCHERY_DAZE, getPlayer())) {
+        if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ARCHERY_DAZE, getPlayer())) {
             return 0;
             return 0;
         }
         }
 
 
@@ -116,7 +116,7 @@ public class ArcheryManager extends SkillManager {
      * @param oldDamage The raw damage value of this arrow before we modify it
      * @param oldDamage The raw damage value of this arrow before we modify it
      */
      */
     public double skillShot(double oldDamage) {
     public double skillShot(double oldDamage) {
-        if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) {
+        if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) {
             return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage);
             return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage);
         } else {
         } else {
             return oldDamage;
             return oldDamage;

+ 5 - 4
src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java

@@ -11,6 +11,7 @@ import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.util.ItemUtils;
 import com.gmail.nossr50.util.ItemUtils;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.ParticleEffectUtils;
 import com.gmail.nossr50.util.skills.ParticleEffectUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
@@ -68,7 +69,7 @@ public class AxesManager extends SkillManager {
      * Handle the effects of the Axe Mastery ability
      * Handle the effects of the Axe Mastery ability
      */
      */
     public double axeMastery() {
     public double axeMastery() {
-        if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.AXES_AXE_MASTERY, getPlayer())) {
+        if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.AXES_AXE_MASTERY, getPlayer())) {
             return Axes.getAxeMasteryBonusDamage(getPlayer());
             return Axes.getAxeMasteryBonusDamage(getPlayer());
         }
         }
 
 
@@ -82,7 +83,7 @@ public class AxesManager extends SkillManager {
      * @param damage The amount of damage initially dealt by the event
      * @param damage The amount of damage initially dealt by the event
      */
      */
     public double criticalHit(LivingEntity target, double damage) {
     public double criticalHit(LivingEntity target, double damage) {
-        if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) {
+        if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) {
             return 0;
             return 0;
         }
         }
 
 
@@ -117,7 +118,7 @@ public class AxesManager extends SkillManager {
 
 
         for (ItemStack armor : target.getEquipment().getArmorContents()) {
         for (ItemStack armor : target.getEquipment().getArmorContents()) {
             if (armor != null && ItemUtils.isArmor(armor)) {
             if (armor != null && ItemUtils.isArmor(armor)) {
-                if (SkillUtils.isSkillRNGSuccessful(SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) {
+                if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) {
                     SkillUtils.handleArmorDurabilityChange(armor, durabilityDamage, 1);
                     SkillUtils.handleArmorDurabilityChange(armor, durabilityDamage, 1);
                 }
                 }
             }
             }
@@ -135,7 +136,7 @@ public class AxesManager extends SkillManager {
      */
      */
     public double greaterImpact(@NotNull LivingEntity target) {
     public double greaterImpact(@NotNull LivingEntity target) {
         //static chance (3rd param)
         //static chance (3rd param)
-        if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.AXES_GREATER_IMPACT, getPlayer())) {
+        if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_GREATER_IMPACT, getPlayer())) {
             return 0;
             return 0;
         }
         }
 
 

+ 3 - 2
src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java

@@ -10,6 +10,7 @@ import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import org.bukkit.Location;
 import org.bukkit.Location;
@@ -40,10 +41,10 @@ public class ExcavationManager extends SkillManager {
 
 
                 for (ExcavationTreasure treasure : treasures) {
                 for (ExcavationTreasure treasure : treasures) {
                     if (skillLevel >= treasure.getDropLevel()
                     if (skillLevel >= treasure.getDropLevel()
-                            && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), treasure.getDropProbability())) {
+                            && ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), treasure.getDropProbability())) {
 
 
                         //Spawn Vanilla XP orbs if a dice roll succeeds
                         //Spawn Vanilla XP orbs if a dice roll succeeds
-                        if(SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), getArchaelogyExperienceOrbChance())) {
+                        if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), getArchaelogyExperienceOrbChance())) {
                             Misc.spawnExperienceOrb(location, getExperienceOrbsReward());
                             Misc.spawnExperienceOrb(location, getExperienceOrbsReward());
                         }
                         }
 
 

+ 2 - 1
src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java

@@ -18,6 +18,7 @@ import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.compat.layers.skills.MasterAnglerCompatibilityLayer;
 import com.gmail.nossr50.util.compat.layers.skills.MasterAnglerCompatibilityLayer;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
@@ -477,7 +478,7 @@ public class FishingManager extends SkillManager {
      * @param target The {@link LivingEntity} affected by the ability
      * @param target The {@link LivingEntity} affected by the ability
      */
      */
     public void shakeCheck(@NotNull LivingEntity target) {
     public void shakeCheck(@NotNull LivingEntity target) {
-        if (SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.FISHING, getPlayer(), getShakeChance())) {
+        if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.FISHING, getPlayer(), getShakeChance())) {
             List<ShakeTreasure> possibleDrops = Fishing.findPossibleDrops(target);
             List<ShakeTreasure> possibleDrops = Fishing.findPossibleDrops(target);
 
 
             if (possibleDrops == null || possibleDrops.isEmpty()) {
             if (possibleDrops == null || possibleDrops.isEmpty()) {

+ 6 - 5
src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java

@@ -20,6 +20,7 @@ import com.gmail.nossr50.runnables.skills.DelayedHerbalismXPCheckTask;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundManager;
@@ -655,7 +656,7 @@ public class HerbalismManager extends SkillManager {
      * @return true if the ability was successful, false otherwise
      * @return true if the ability was successful, false otherwise
      */
      */
     public boolean processGreenThumbBlocks(BlockState blockState) {
     public boolean processGreenThumbBlocks(BlockState blockState) {
-        if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, getPlayer())) {
+        if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, getPlayer())) {
             NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.GTh.Fail");
             NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.GTh.Fail");
             return false;
             return false;
         }
         }
@@ -670,7 +671,7 @@ public class HerbalismManager extends SkillManager {
      * @return true if the ability was successful, false otherwise
      * @return true if the ability was successful, false otherwise
      */
      */
     public boolean processHylianLuck(BlockState blockState) {
     public boolean processHylianLuck(BlockState blockState) {
-        if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) {
+        if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) {
             return false;
             return false;
         }
         }
 
 
@@ -689,7 +690,7 @@ public class HerbalismManager extends SkillManager {
 
 
         for (HylianTreasure treasure : treasures) {
         for (HylianTreasure treasure : treasures) {
             if (skillLevel >= treasure.getDropLevel()
             if (skillLevel >= treasure.getDropLevel()
-                    && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.HERBALISM, player, treasure.getDropChance())) {
+                    && ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.HERBALISM, player, treasure.getDropChance())) {
                 if (!EventUtils.simulateBlockBreak(blockState.getBlock(), player, false)) {
                 if (!EventUtils.simulateBlockBreak(blockState.getBlock(), player, false)) {
                     return false;
                     return false;
                 }
                 }
@@ -726,7 +727,7 @@ public class HerbalismManager extends SkillManager {
         playerInventory.removeItem(new ItemStack(Material.RED_MUSHROOM));
         playerInventory.removeItem(new ItemStack(Material.RED_MUSHROOM));
         player.updateInventory();
         player.updateInventory();
 
 
-        if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_SHROOM_THUMB, player)) {
+        if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_SHROOM_THUMB, player)) {
             NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.ShroomThumb.Fail");
             NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.ShroomThumb.Fail");
             return false;
             return false;
         }
         }
@@ -806,7 +807,7 @@ public class HerbalismManager extends SkillManager {
             return false;
             return false;
         }
         }
 
 
-        if (!greenTerra && !SkillUtils.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, player)) {
+        if (!greenTerra && !ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, player)) {
             return false;
             return false;
         }
         }
 
 

+ 3 - 2
src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java

@@ -13,6 +13,7 @@ import com.gmail.nossr50.runnables.skills.AbilityCooldownTask;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import org.apache.commons.lang.math.RandomUtils;
 import org.apache.commons.lang.math.RandomUtils;
@@ -114,7 +115,7 @@ public class MiningManager extends SkillManager {
 
 
     private boolean processTripleDrops(@NotNull BlockState blockState) {
     private boolean processTripleDrops(@NotNull BlockState blockState) {
         //TODO: Make this readable
         //TODO: Make this readable
-        if (SkillUtils.isSkillRNGSuccessful(SubSkillType.MINING_MOTHER_LODE, getPlayer())) {
+        if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.MINING_MOTHER_LODE, getPlayer())) {
             BlockUtils.markDropsAsBonus(blockState, 2);
             BlockUtils.markDropsAsBonus(blockState, 2);
             return true;
             return true;
         } else {
         } else {
@@ -124,7 +125,7 @@ public class MiningManager extends SkillManager {
 
 
     private void processDoubleDrops(@NotNull BlockState blockState) {
     private void processDoubleDrops(@NotNull BlockState blockState) {
         //TODO: Make this readable
         //TODO: Make this readable
-        if (SkillUtils.isSkillRNGSuccessful(SubSkillType.MINING_DOUBLE_DROPS, getPlayer())) {
+        if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.MINING_DOUBLE_DROPS, getPlayer())) {
             boolean useTriple = mmoPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER) && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops();
             boolean useTriple = mmoPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER) && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops();
             BlockUtils.markDropsAsBonus(blockState, useTriple);
             BlockUtils.markDropsAsBonus(blockState, useTriple);
         }
         }

+ 4 - 3
src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java

@@ -14,6 +14,7 @@ import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundManager;
@@ -318,7 +319,7 @@ public class RepairManager extends SkillManager {
         if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.REPAIR_SUPER_REPAIR))
         if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.REPAIR_SUPER_REPAIR))
             return false;
             return false;
 
 
-        if (SkillUtils.isSkillRNGSuccessful(SubSkillType.REPAIR_SUPER_REPAIR, getPlayer())) {
+        if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.REPAIR_SUPER_REPAIR, getPlayer())) {
             NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Repair.Skills.FeltEasy");
             NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Repair.Skills.FeltEasy");
             return true;
             return true;
         }
         }
@@ -369,10 +370,10 @@ public class RepairManager extends SkillManager {
 
 
             Enchantment enchantment = enchant.getKey();
             Enchantment enchantment = enchant.getKey();
 
 
-            if (SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), getKeepEnchantChance())) {
+            if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), getKeepEnchantChance())) {
 
 
                 if (ArcaneForging.arcaneForgingDowngrades && enchantLevel > 1
                 if (ArcaneForging.arcaneForgingDowngrades && enchantLevel > 1
-                        && (!SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), 100 - getDowngradeEnchantChance()))) {
+                        && (!ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), 100 - getDowngradeEnchantChance()))) {
                     item.addUnsafeEnchantment(enchantment, enchantLevel - 1);
                     item.addUnsafeEnchantment(enchantment, enchantLevel - 1);
                     downgraded = true;
                     downgraded = true;
                 }
                 }

+ 4 - 3
src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java

@@ -14,6 +14,7 @@ import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundManager;
@@ -119,7 +120,7 @@ public class SalvageManager extends SkillManager {
 
 
         for(int x = 0; x < potentialSalvageYield-1; x++) {
         for(int x = 0; x < potentialSalvageYield-1; x++) {
 
 
-            if(SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, chanceOfSuccess)) {
+            if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, chanceOfSuccess)) {
                 chanceOfSuccess-=3;
                 chanceOfSuccess-=3;
                 chanceOfSuccess = Math.max(chanceOfSuccess, 90);
                 chanceOfSuccess = Math.max(chanceOfSuccess, 90);
 
 
@@ -250,12 +251,12 @@ public class SalvageManager extends SkillManager {
 
 
             if (!Salvage.arcaneSalvageEnchantLoss
             if (!Salvage.arcaneSalvageEnchantLoss
                     || Permissions.hasSalvageEnchantBypassPerk(player)
                     || Permissions.hasSalvageEnchantBypassPerk(player)
-                    || SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractFullEnchantChance())) {
+                    || ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractFullEnchantChance())) {
                 enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true);
                 enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true);
             }
             }
             else if (enchantLevel > 1
             else if (enchantLevel > 1
                     && Salvage.arcaneSalvageDowngrades
                     && Salvage.arcaneSalvageDowngrades
-                    && SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractPartialEnchantChance())) {
+                    && ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractPartialEnchantChance())) {
                 enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true);
                 enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true);
                 downgraded = true;
                 downgraded = true;
             } else {
             } else {

+ 2 - 2
src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java

@@ -8,8 +8,8 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import org.bukkit.block.Furnace;
 import org.bukkit.block.Furnace;
 import org.bukkit.event.inventory.FurnaceBurnEvent;
 import org.bukkit.event.inventory.FurnaceBurnEvent;
 import org.bukkit.event.inventory.FurnaceSmeltEvent;
 import org.bukkit.event.inventory.FurnaceSmeltEvent;
@@ -24,7 +24,7 @@ public class SmeltingManager extends SkillManager {
 
 
     public boolean isSecondSmeltSuccessful() {
     public boolean isSecondSmeltSuccessful() {
         return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.SMELTING_SECOND_SMELT)
         return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.SMELTING_SECOND_SMELT)
-                && SkillUtils.isSkillRNGSuccessful(SubSkillType.SMELTING_SECOND_SMELT, getPlayer());
+                && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.SMELTING_SECOND_SMELT, getPlayer());
     }
     }
 
 
     /**
     /**

+ 3 - 5
src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java

@@ -14,11 +14,9 @@ import com.gmail.nossr50.util.ItemUtils;
 import com.gmail.nossr50.util.MetadataConstants;
 import com.gmail.nossr50.util.MetadataConstants;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
-import com.gmail.nossr50.util.random.RandomChanceUtil;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillActivationType;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import org.bukkit.entity.Entity;
 import org.bukkit.entity.Entity;
 import org.bukkit.entity.LivingEntity;
 import org.bukkit.entity.LivingEntity;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
@@ -78,7 +76,7 @@ public class SwordsManager extends SkillManager {
         }
         }
 
 
         double ruptureOdds = mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank());
         double ruptureOdds = mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank());
-        if (SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.SWORDS, this.getPlayer(), ruptureOdds)) {
+        if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SWORDS, this.getPlayer(), ruptureOdds)) {
 
 
             if (target instanceof Player defender) {
             if (target instanceof Player defender) {
 
 
@@ -144,7 +142,7 @@ public class SwordsManager extends SkillManager {
      */
      */
     public void counterAttackChecks(@NotNull LivingEntity attacker, double damage) {
     public void counterAttackChecks(@NotNull LivingEntity attacker, double damage) {
 
 
-        if (SkillUtils.isSkillRNGSuccessful(SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) {
+        if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) {
             CombatUtils.dealDamage(attacker, damage / Swords.counterAttackModifier, getPlayer());
             CombatUtils.dealDamage(attacker, damage / Swords.counterAttackModifier, getPlayer());
 
 
             NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Countered");
             NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Countered");

+ 3 - 3
src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java

@@ -15,9 +15,9 @@ import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.ParticleEffectUtils;
 import com.gmail.nossr50.util.skills.ParticleEffectUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundType;
 import com.gmail.nossr50.util.sounds.SoundType;
 import com.gmail.nossr50.util.text.StringUtils;
 import com.gmail.nossr50.util.text.StringUtils;
@@ -143,7 +143,7 @@ public class TamingManager extends SkillManager {
      * @param damage The damage being absorbed by the wolf
      * @param damage The damage being absorbed by the wolf
      */
      */
     public void fastFoodService(@NotNull Wolf wolf, double damage) {
     public void fastFoodService(@NotNull Wolf wolf, double damage) {
-        if (!SkillUtils.isSkillRNGSuccessful(SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) {
+        if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) {
             return;
             return;
         }
         }
 
 
@@ -262,7 +262,7 @@ public class TamingManager extends SkillManager {
         if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL))
         if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL))
             return;
             return;
 
 
-        if(!SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.TAMING, getPlayer(), mcMMO.p.getAdvancedConfig().getPummelChance()))
+        if(!ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.TAMING, getPlayer(), mcMMO.p.getAdvancedConfig().getPummelChance()))
             return;
             return;
 
 
         ParticleEffectUtils.playGreaterImpactEffect(target);
         ParticleEffectUtils.playGreaterImpactEffect(target);

+ 6 - 6
src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java

@@ -12,8 +12,8 @@ import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 import org.bukkit.Material;
 import org.bukkit.Material;
 import org.bukkit.block.BlockState;
 import org.bukkit.block.BlockState;
 import org.bukkit.entity.Item;
 import org.bukkit.entity.Item;
@@ -67,7 +67,7 @@ public class UnarmedManager extends SkillManager {
     }
     }
 
 
     public boolean blockCrackerCheck(@NotNull BlockState blockState) {
     public boolean blockCrackerCheck(@NotNull BlockState blockState) {
-        if (!SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) {
+        if (!ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) {
             return false;
             return false;
         }
         }
 
 
@@ -98,7 +98,7 @@ public class UnarmedManager extends SkillManager {
      * @param defender The defending player
      * @param defender The defending player
      */
      */
     public void disarmCheck(@NotNull Player defender) {
     public void disarmCheck(@NotNull Player defender) {
-        if (SkillUtils.isSkillRNGSuccessful(SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) {
+        if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) {
             if (EventUtils.callDisarmEvent(defender).isCancelled()) {
             if (EventUtils.callDisarmEvent(defender).isCancelled()) {
                 return;
                 return;
             }
             }
@@ -121,7 +121,7 @@ public class UnarmedManager extends SkillManager {
      * Check for arrow deflection.
      * Check for arrow deflection.
      */
      */
     public boolean deflectCheck() {
     public boolean deflectCheck() {
-        if (SkillUtils.isSkillRNGSuccessful(SubSkillType.UNARMED_ARROW_DEFLECT, getPlayer())) {
+        if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.UNARMED_ARROW_DEFLECT, getPlayer())) {
             NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.ArrowDeflect");
             NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.ArrowDeflect");
             return true;
             return true;
         }
         }
@@ -144,7 +144,7 @@ public class UnarmedManager extends SkillManager {
      * Handle the effects of the Iron Arm ability
      * Handle the effects of the Iron Arm ability
      */
      */
     public double calculateSteelArmStyleDamage() {
     public double calculateSteelArmStyleDamage() {
-        if (SkillUtils.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) {
+        if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) {
             return getSteelArmStyleDamage();
             return getSteelArmStyleDamage();
         }
         }
 
 
@@ -178,7 +178,7 @@ public class UnarmedManager extends SkillManager {
     private boolean hasIronGrip(@NotNull Player defender) {
     private boolean hasIronGrip(@NotNull Player defender) {
         if (!Misc.isNPCEntityExcludingVillagers(defender)
         if (!Misc.isNPCEntityExcludingVillagers(defender)
                 && Permissions.isSubSkillEnabled(defender, SubSkillType.UNARMED_IRON_GRIP)
                 && Permissions.isSubSkillEnabled(defender, SubSkillType.UNARMED_IRON_GRIP)
-                && SkillUtils.isSkillRNGSuccessful(SubSkillType.UNARMED_IRON_GRIP, defender)) {
+                && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.UNARMED_IRON_GRIP, defender)) {
             NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Defender");
             NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Defender");
             NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Attacker");
             NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Attacker");
 
 

+ 4 - 5
src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java

@@ -13,10 +13,9 @@ import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.*;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
-import com.gmail.nossr50.util.random.RandomChanceUtil;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
-import com.gmail.nossr50.util.skills.SkillActivationType;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import org.bukkit.Bukkit;
 import org.bukkit.Bukkit;
 import org.bukkit.Material;
 import org.bukkit.Material;
@@ -71,14 +70,14 @@ public class WoodcuttingManager extends SkillManager {
     private boolean checkHarvestLumberActivation(Material material) {
     private boolean checkHarvestLumberActivation(Material material) {
         return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
         return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
                 && RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
                 && RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
-                && SkillUtils.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer())
+                && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer())
                 && mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material);
                 && mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material);
     }
     }
 
 
     private boolean checkCleanCutsActivation(Material material) {
     private boolean checkCleanCutsActivation(Material material) {
         return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
         return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
                 && RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
                 && RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
-                && SkillUtils.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer())
+                && ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer())
                 && mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material);
                 && mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material);
     }
     }
 
 
@@ -330,7 +329,7 @@ public class WoodcuttingManager extends SkillManager {
                     if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) {
                     if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) {
                         if(mcMMO.p.getAdvancedConfig().isKnockOnWoodXPOrbEnabled()) {
                         if(mcMMO.p.getAdvancedConfig().isKnockOnWoodXPOrbEnabled()) {
                             //TODO: Test the results of this RNG, should be 10%
                             //TODO: Test the results of this RNG, should be 10%
-                            if(SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.WOODCUTTING, player, 10)) {
+                            if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.WOODCUTTING, player, 10)) {
                                 int randOrbCount = Math.max(1, Misc.getRandom().nextInt(100));
                                 int randOrbCount = Math.max(1, Misc.getRandom().nextInt(100));
                                 Misc.spawnExperienceOrb(blockState.getLocation(), randOrbCount);
                                 Misc.spawnExperienceOrb(blockState.getLocation(), randOrbCount);
                             }
                             }

+ 2 - 2
src/main/java/com/gmail/nossr50/util/BlockUtils.java

@@ -7,7 +7,7 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.skills.repair.Repair;
 import com.gmail.nossr50.skills.repair.Repair;
 import com.gmail.nossr50.skills.salvage.Salvage;
 import com.gmail.nossr50.skills.salvage.Salvage;
-import com.gmail.nossr50.util.skills.SkillUtils;
+import com.gmail.nossr50.util.random.ProbabilityUtil;
 import org.bukkit.Material;
 import org.bukkit.Material;
 import org.bukkit.World;
 import org.bukkit.World;
 import org.bukkit.block.Block;
 import org.bukkit.block.Block;
@@ -67,7 +67,7 @@ public final class BlockUtils {
      */
      */
     public static boolean checkDoubleDrops(Player player, BlockState blockState, PrimarySkillType skillType, SubSkillType subSkillType) {
     public static boolean checkDoubleDrops(Player player, BlockState blockState, PrimarySkillType skillType, SubSkillType subSkillType) {
         if (mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) {
         if (mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) {
-            return SkillUtils.isSkillRNGSuccessful(subSkillType, player);
+            return ProbabilityUtil.isSkillRNGSuccessful(subSkillType, player);
         }
         }
 
 
         return false;
         return false;

+ 31 - 48
src/main/java/com/gmail/nossr50/util/random/Probability.java

@@ -1,12 +1,9 @@
 package com.gmail.nossr50.util.random;
 package com.gmail.nossr50.util.random;
 
 
-import com.gmail.nossr50.datatypes.player.McMMOPlayer;
-import com.gmail.nossr50.datatypes.skills.SubSkillType;
-import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.util.player.UserManager;
-import org.bukkit.entity.Player;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.VisibleForTesting;
+
+import java.util.concurrent.ThreadLocalRandom;
 
 
 public interface Probability {
 public interface Probability {
     /**
     /**
@@ -20,52 +17,38 @@ public interface Probability {
      */
      */
     double getValue();
     double getValue();
 
 
-    static @NotNull Probability ofSubSkill(@Nullable Player player,
-                                           @NotNull SubSkillType subSkillType,
-                                           @NotNull SkillProbabilityType skillProbabilityType) {
-
-        switch (skillProbabilityType) {
-            case DYNAMIC_CONFIGURABLE:
-                double probabilityCeiling;
-                double xCeiling;
-                double xPos;
-
-                if (player != null) {
-                    McMMOPlayer mmoPlayer = UserManager.getPlayer(player);
-                    if(mmoPlayer != null)
-                        xPos = mmoPlayer.getSkillLevel(subSkillType.getParentSkill());
-                    else
-                        xPos = 0;
-                } else {
-                    xPos = 0;
-                }
+    static @NotNull Probability ofPercent(double percentageValue) {
+        return new ProbabilityImpl(percentageValue);
+    }
 
 
-                //Probability ceiling is configurable in this type
-                probabilityCeiling = mcMMO.p.getAdvancedConfig().getMaximumProbability(subSkillType);
-                //The xCeiling is configurable in this type
-                xCeiling = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(subSkillType);
-                return new ProbabilityImpl(xPos, xCeiling, probabilityCeiling);
-            case STATIC_CONFIGURABLE:
-                try {
-                    return ofPercentageValue(getStaticRandomChance(subSkillType));
-                } catch (InvalidStaticChance invalidStaticChance) {
-                    invalidStaticChance.printStackTrace();
-                }
-            default:
-                throw new RuntimeException("No case in switch statement for Skill Probability Type!");
-        }
+    /**
+     * Simulates a "roll of the dice"
+     * If the value passed is higher than the "random" value, than it is a successful roll
+     *
+     * @param probabilityValue probability value
+     * @return true for succeeding, false for failing
+     */
+    static private boolean isSuccessfulRoll(double probabilityValue) {
+        return probabilityValue >= ThreadLocalRandom.current().nextDouble(100D);
     }
     }
 
 
-    static @NotNull Probability ofPercentageValue(double percentageValue) {
-        return new ProbabilityImpl(percentageValue / 100);
+    /**
+     * Simulate an outcome on a probability and return true or false for the result of that outcome
+     *
+     * @return true if the probability succeeded, false if it failed
+     */
+    default boolean evaluate() {
+        return isSuccessfulRoll(getValue());
     }
     }
 
 
-    static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance {
-        return switch (subSkillType) {
-            case AXES_ARMOR_IMPACT -> mcMMO.p.getAdvancedConfig().getImpactChance();
-            case AXES_GREATER_IMPACT -> mcMMO.p.getAdvancedConfig().getGreaterImpactChance();
-            case TAMING_FAST_FOOD_SERVICE -> mcMMO.p.getAdvancedConfig().getFastFoodChance();
-            default -> throw new InvalidStaticChance();
-        };
+    /**
+     * Modify and then Simulate an outcome on a probability and return true or false for the result of that outcome
+     *
+     * @param probabilityMultiplier probability will be multiplied by this before success is checked
+     * @return true if the probability succeeded, false if it failed
+     */
+    default boolean evaluate(double probabilityMultiplier) {
+        double probabilityValue = getValue() * probabilityMultiplier;
+        return isSuccessfulRoll(probabilityValue);
     }
     }
 }
 }

+ 1 - 1
src/main/java/com/gmail/nossr50/util/random/ProbabilityImpl.java

@@ -20,7 +20,7 @@ public class ProbabilityImpl implements Probability {
         probabilityValue = staticProbability;
         probabilityValue = staticProbability;
     }
     }
 
 
-    public ProbabilityImpl(double xPos, double xCeiling, double probabilityCeiling) throws ValueOutOfBoundsException {
+    ProbabilityImpl(double xPos, double xCeiling, double probabilityCeiling) throws ValueOutOfBoundsException {
         if(probabilityCeiling > 100) {
         if(probabilityCeiling > 100) {
             throw new ValueOutOfBoundsException("Probability Ceiling should never be above 100!");
             throw new ValueOutOfBoundsException("Probability Ceiling should never be above 100!");
         } else if (probabilityCeiling < 0) {
         } else if (probabilityCeiling < 0) {

+ 226 - 0
src/main/java/com/gmail/nossr50/util/random/ProbabilityUtil.java

@@ -0,0 +1,226 @@
+package com.gmail.nossr50.util.random;
+
+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.events.skills.secondaryabilities.SubSkillEvent;
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.util.EventUtils;
+import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.player.UserManager;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.text.DecimalFormat;
+
+public class ProbabilityUtil {
+    public static final @NotNull DecimalFormat percent = new DecimalFormat("##0.00%");
+    public static final double LUCKY_MODIFIER = 1.333D;
+
+    /**
+     * Return a chance of success in "percentage" format, show to the player in UI elements
+     *
+     * @param player target player
+     * @param subSkillType target subskill
+     * @param isLucky whether to apply luck modifiers
+     *
+     * @return "percentage" representation of success
+     */
+    public static double chanceOfSuccessPercentage(@NotNull Player player,
+                                                   @NotNull SubSkillType subSkillType,
+                                                   boolean isLucky) {
+        Probability probability = getSubSkillProbability(subSkillType, player);
+        //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale
+        double percentageValue = probability.getValue(); //Doesn't need to be scaled
+
+        //Apply lucky modifier
+        if(isLucky) {
+            percentageValue *= LUCKY_MODIFIER;
+        }
+
+        return percentageValue;
+    }
+
+    public static double chanceOfSuccessPercentage(@NotNull Probability probability, boolean isLucky) {
+        //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale
+        double percentageValue = probability.getValue();
+
+        //Apply lucky modifier
+        if(isLucky) {
+            percentageValue *= LUCKY_MODIFIER;
+        }
+
+        return percentageValue;
+    }
+
+    static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance {
+        return switch (subSkillType) {
+            case AXES_ARMOR_IMPACT -> mcMMO.p.getAdvancedConfig().getImpactChance();
+            case AXES_GREATER_IMPACT -> mcMMO.p.getAdvancedConfig().getGreaterImpactChance();
+            case TAMING_FAST_FOOD_SERVICE -> mcMMO.p.getAdvancedConfig().getFastFoodChance();
+            default -> throw new InvalidStaticChance();
+        };
+    }
+
+    static SkillProbabilityType getProbabilityType(@NotNull SubSkillType subSkillType) {
+        SkillProbabilityType skillProbabilityType = SkillProbabilityType.DYNAMIC_CONFIGURABLE;
+
+        if(subSkillType == SubSkillType.TAMING_FAST_FOOD_SERVICE
+                || subSkillType == SubSkillType.AXES_ARMOR_IMPACT
+                || subSkillType == SubSkillType.AXES_GREATER_IMPACT)
+            skillProbabilityType = SkillProbabilityType.STATIC_CONFIGURABLE;
+
+        return skillProbabilityType;
+    }
+
+    static @NotNull Probability ofSubSkill(@Nullable Player player,
+                                           @NotNull SubSkillType subSkillType) {
+        switch (getProbabilityType(subSkillType)) {
+            case DYNAMIC_CONFIGURABLE:
+                double probabilityCeiling;
+                double xCeiling;
+                double xPos;
+
+                if (player != null) {
+                    McMMOPlayer mmoPlayer = UserManager.getPlayer(player);
+                    if(mmoPlayer != null)
+                        xPos = mmoPlayer.getSkillLevel(subSkillType.getParentSkill());
+                    else
+                        xPos = 0;
+                } else {
+                    xPos = 0;
+                }
+
+                //Probability ceiling is configurable in this type
+                probabilityCeiling = mcMMO.p.getAdvancedConfig().getMaximumProbability(subSkillType);
+                //The xCeiling is configurable in this type
+                xCeiling = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(subSkillType);
+                return new ProbabilityImpl(xPos, xCeiling, probabilityCeiling);
+            case STATIC_CONFIGURABLE:
+                try {
+                    return Probability.ofPercent(getStaticRandomChance(subSkillType));
+                } catch (InvalidStaticChance invalidStaticChance) {
+                    invalidStaticChance.printStackTrace();
+                }
+            default:
+                throw new RuntimeException("No case in switch statement for Skill Probability Type!");
+        }
+    }
+
+    /**
+     * This is one of several Skill RNG check methods
+     * This helper method is for specific {@link SubSkillType}, which help mcMMO understand where the RNG values used in our calculations come from this {@link SubSkillType}
+     * <p>
+     * 1) Determine where the RNG values come from for the passed {@link SubSkillType}
+     *  NOTE: In the config file, there are values which are static and which are more dynamic, this is currently a bit hardcoded and will need to be updated manually
+     * <p>
+     * 2) Determine whether to use Lucky multiplier and influence the outcome
+     * <p>
+     * 3) Creates a {@link Probability} and pipes it to {@link ProbabilityUtil} which processes the result and returns it
+     * <p>
+     * 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, @NotNull Player player) {
+        //Process probability
+        Probability probability = getSubSkillProbability(subSkillType, player);
+
+        //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 = Probability.ofPercent(probability.getValue() * resultModifier);
+
+        //Luck
+        boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
+
+        if(isLucky) {
+            return probability.evaluate(LUCKY_MODIFIER);
+        } else {
+            return probability.evaluate();
+        }
+    }
+
+    /**
+     * This is one of several Skill RNG check methods
+     * This helper method is specific to static value RNG, which can be influenced by a player's Luck
+     *
+     * @param primarySkillType the related primary skill
+     * @param player the target player, can be null (null players have the worst odds)
+     * @param probabilityPercentage the probability of this player succeeding in "percentage" format (0-100 inclusive)
+     * @return true if the RNG succeeds, false if it fails
+     */
+    public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, @Nullable Player player, double probabilityPercentage) {
+        //Grab a probability converted from a "percentage" value
+        Probability probability = Probability.ofPercent(probabilityPercentage);
+
+        return isStaticSkillRNGSuccessful(primarySkillType, player, probability);
+    }
+
+    /**
+     * This is one of several Skill RNG check methods
+     * This helper method is specific to static value RNG, which can be influenced by a player's Luck
+     *
+     * @param primarySkillType the related primary skill
+     * @param player the target player, can be null (null players have the worst odds)
+     * @param probability the probability of this player succeeding
+     * @return true if the RNG succeeds, false if it fails
+     */
+    public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, @Nullable Player player, @NotNull Probability probability) {
+        boolean isLucky = player != null && Permissions.lucky(player, primarySkillType);
+
+        if(isLucky) {
+            return probability.evaluate(LUCKY_MODIFIER);
+        } else {
+            return probability.evaluate();
+        }
+    }
+
+    /**
+     * 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}
+     *
+     * @param subSkillType target subskill
+     * @param player target player
+     * @return the Probability of this skill succeeding
+     */
+    public static @NotNull Probability getSubSkillProbability(@NotNull SubSkillType subSkillType, @Nullable Player player) {
+        return ProbabilityUtil.ofSubSkill(player, subSkillType);
+    }
+
+    public static @NotNull String[] getRNGDisplayValues(@NotNull Player player, @NotNull SubSkillType subSkill) {
+        double firstValue = chanceOfSuccessPercentage(player, subSkill, false);
+        double secondValue = chanceOfSuccessPercentage(player, subSkill, true);
+
+        return new String[]{percent.format(firstValue), percent.format(secondValue)};
+    }
+
+    public static @NotNull String[] getRNGDisplayValues(@NotNull Probability probability) {
+        double firstValue = chanceOfSuccessPercentage(probability, false);
+        double secondValue = chanceOfSuccessPercentage(probability, true);
+
+        return new String[]{percent.format(firstValue), percent.format(secondValue)};
+    }
+}

+ 0 - 84
src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java

@@ -1,84 +0,0 @@
-package com.gmail.nossr50.util.random;
-
-import com.gmail.nossr50.datatypes.skills.SubSkillType;
-import com.gmail.nossr50.util.skills.SkillUtils;
-import org.bukkit.entity.Player;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.VisibleForTesting;
-
-import java.text.DecimalFormat;
-import java.util.concurrent.ThreadLocalRandom;
-
-public class RandomChanceUtil {
-    public static final @NotNull DecimalFormat percent = new DecimalFormat("##0.00%");
-    public static final double LUCKY_MODIFIER = 1.333D;
-
-    /**
-     * Simulate an outcome on a probability and return true or false for the result of that outcome
-     *
-     * @param probability target probability
-     * @return true if the probability succeeded, false if it failed
-     */
-    public static boolean processProbability(@NotNull Probability probability) {
-        return isSuccessfulRoll(probability.getValue());
-    }
-
-    /**
-     * Modify and then Simulate an outcome on a probability and return true or false for the result of that outcome
-     *
-     * @param probability target probability
-     * @param probabilityMultiplier probability will be multiplied by this before success is checked
-     * @return true if the probability succeeded, false if it failed
-     */
-    public static boolean processProbability(@NotNull Probability probability, double probabilityMultiplier) {
-        double probabilityValue = probability.getValue() * probabilityMultiplier;
-        return isSuccessfulRoll(probabilityValue);
-    }
-
-    /**
-     * Simulates a "roll of the dice"
-     * If the value passed is higher than the "random" value, than it is a successful roll
-     *
-     * @param probabilityValue probability value
-     * @return true for succeeding, false for failing
-     */
-    @VisibleForTesting
-    static boolean isSuccessfulRoll(double probabilityValue) {
-        return probabilityValue >= ThreadLocalRandom.current().nextDouble(100D);
-    }
-
-    /**
-     * Return a chance of success in "percentage" format, show to the player in UI elements
-     *
-     * @param player target player
-     * @param subSkillType target subskill
-     * @param isLucky whether to apply luck modifiers
-     *
-     * @return "percentage" representation of success
-     */
-    public static double chanceOfSuccessPercentage(@NotNull Player player, @NotNull SubSkillType subSkillType, boolean isLucky) {
-        Probability probability = SkillUtils.getSubSkillProbability(subSkillType, player);
-        //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale
-        double percentageValue = probability.getValue(); //Doesn't need to be scaled
-
-        //Apply lucky modifier
-        if(isLucky) {
-            percentageValue *= LUCKY_MODIFIER;
-        }
-
-        return percentageValue;
-    }
-
-    public static double chanceOfSuccessPercentage(@NotNull Probability probability, boolean isLucky) {
-        //Probability values are on a 0-1 scale and need to be "transformed" into a 1-100 scale
-        double percentageValue = probability.getValue();
-
-        //Apply lucky modifier
-        if(isLucky) {
-            percentageValue *= LUCKY_MODIFIER;
-        }
-
-        return percentageValue;
-    }
-
-}

+ 0 - 127
src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java

@@ -8,17 +8,13 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
 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.locale.LocaleLoader;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.metadata.ItemMetadataService;
 import com.gmail.nossr50.metadata.ItemMetadataService;
-import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.ItemUtils;
 import com.gmail.nossr50.util.ItemUtils;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Misc;
-import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.player.UserManager;
-import com.gmail.nossr50.util.random.*;
 import com.gmail.nossr50.util.text.StringUtils;
 import com.gmail.nossr50.util.text.StringUtils;
 import org.bukkit.Bukkit;
 import org.bukkit.Bukkit;
 import org.bukkit.Location;
 import org.bukkit.Location;
@@ -356,127 +352,4 @@ public final class SkillUtils {
 
 
         return quantity;
         return quantity;
     }
     }
-
-    /**
-     * This is one of several Skill RNG check methods
-     * This helper method is for specific {@link SubSkillType}, which help mcMMO understand where the RNG values used in our calculations come from from this {@link SubSkillType}
-     *
-     * 1) Determine where the RNG values come from for the passed {@link SubSkillType}
-     *  NOTE: In the config file, there are values which are static and which are more dynamic, this is currently a bit hardcoded and will need to be updated manually
-     *
-     * 2) Determine whether or not to use Lucky multiplier and influence the outcome
-     *
-     * 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, @NotNull Player player) {
-        //Process probability
-        Probability probability = getSubSkillProbability(subSkillType, player);
-
-        //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 = Probability.ofPercentageValue(probability.getValue() * resultModifier);
-
-        //Luck
-        boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
-
-        if(isLucky) {
-            return RandomChanceUtil.processProbability(probability, RandomChanceUtil.LUCKY_MODIFIER);
-        } else {
-            return RandomChanceUtil.processProbability(probability);
-        }
-    }
-
-    /**
-     * This is one of several Skill RNG check methods
-     * This helper method is specific to static value RNG, which can be influenced by a player's Luck
-     *
-     * @param primarySkillType the related primary skill
-     * @param player the target player, can be null (null players have the worst odds)
-     * @param probabilityPercentage the probability of this player succeeding in "percentage" format (0-100 inclusive)
-     * @return true if the RNG succeeds, false if it fails
-     */
-    public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, @Nullable Player player, double probabilityPercentage) {
-        //Grab a probability converted from a "percentage" value
-        Probability probability = Probability.ofPercentageValue(probabilityPercentage);
-
-        return isStaticSkillRNGSuccessful(primarySkillType, player, probability);
-    }
-
-    /**
-     * This is one of several Skill RNG check methods
-     * This helper method is specific to static value RNG, which can be influenced by a player's Luck
-     *
-     * @param primarySkillType the related primary skill
-     * @param player the target player, can be null (null players have the worst odds)
-     * @param probability the probability of this player succeeding
-     * @return true if the RNG succeeds, false if it fails
-     */
-    public static boolean isStaticSkillRNGSuccessful(@NotNull PrimarySkillType primarySkillType, @Nullable Player player, @NotNull Probability probability) {
-        boolean isLucky = player != null && Permissions.lucky(player, primarySkillType);
-
-        if(isLucky) {
-            return RandomChanceUtil.processProbability(probability, RandomChanceUtil.LUCKY_MODIFIER);
-        } else {
-            return RandomChanceUtil.processProbability(probability);
-        }
-    }
-
-    /**
-     * 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}
-     *
-     * @param subSkillType target subskill
-     * @param player target player
-     * @return the Probability of this skill succeeding
-     * @throws InvalidStaticChance when a skill that does not have a hard coded static chance and it is asked for
-     * @throws RuntimeException
-     */
-    public static @NotNull Probability getSubSkillProbability(@NotNull SubSkillType subSkillType, @Nullable Player player) {
-        SkillProbabilityType skillProbabilityType = SkillProbabilityType.DYNAMIC_CONFIGURABLE;
-
-        if(subSkillType == SubSkillType.TAMING_FAST_FOOD_SERVICE || subSkillType == SubSkillType.AXES_ARMOR_IMPACT || subSkillType == SubSkillType.AXES_GREATER_IMPACT)
-            skillProbabilityType = SkillProbabilityType.STATIC_CONFIGURABLE;
-
-        return Probability.ofSubSkill(player, subSkillType, skillProbabilityType);
-    }
-
-    public static @NotNull String[] getRNGDisplayValues(@NotNull Player player, @NotNull SubSkillType subSkill) {
-        double firstValue = RandomChanceUtil.chanceOfSuccessPercentage(player, subSkill, false);
-        double secondValue = RandomChanceUtil.chanceOfSuccessPercentage(player, subSkill, true);
-
-        return new String[]{RandomChanceUtil.percent.format(firstValue), RandomChanceUtil.percent.format(secondValue)};
-    }
-
-    public static @NotNull String[] getRNGDisplayValues(@NotNull Probability probability) {
-        double firstValue = RandomChanceUtil.chanceOfSuccessPercentage(probability, false);
-        double secondValue = RandomChanceUtil.chanceOfSuccessPercentage(probability, true);
-
-        return new String[]{RandomChanceUtil.percent.format(firstValue), RandomChanceUtil.percent.format(secondValue)};
-    }
 }
 }

+ 52 - 20
src/test/java/com/gmail/nossr50/util/random/ProbabilityTest.java

@@ -1,13 +1,15 @@
 package com.gmail.nossr50.util.random;
 package com.gmail.nossr50.util.random;
 
 
+import org.bukkit.entity.Player;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.Mockito;
 
 
 import java.util.stream.Stream;
 import java.util.stream.Stream;
 
 
-import static com.gmail.nossr50.util.random.RandomChanceUtil.processProbability;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 
 class ProbabilityTest {
 class ProbabilityTest {
@@ -30,42 +32,62 @@ class ProbabilityTest {
                 Arguments.of(new ProbabilityImpl(1000), 100)
                 Arguments.of(new ProbabilityImpl(1000), 100)
         );
         );
     }
     }
-    @Test
-    void testIsSuccessfulRollSucceeds() {
-        Probability probability = new ProbabilityImpl(100);
 
 
+    private static Stream<Arguments> provideOfPercentageProbabilitiesForWithinExpectations() {
+        return Stream.of(
+                // static probability, % of time for success
+                Arguments.of(Probability.ofPercent(5), 5),
+                Arguments.of(Probability.ofPercent(10), 10),
+                Arguments.of(Probability.ofPercent(15), 15),
+                Arguments.of(Probability.ofPercent(20), 20),
+                Arguments.of(Probability.ofPercent(25), 25),
+                Arguments.of(Probability.ofPercent(50), 50),
+                Arguments.of(Probability.ofPercent(75), 75),
+                Arguments.of(Probability.ofPercent(90), 90),
+                Arguments.of(Probability.ofPercent(99.9), 99.9),
+                Arguments.of(Probability.ofPercent(0.05), 0.05),
+                Arguments.of(Probability.ofPercent(0.1), 0.1),
+                Arguments.of(Probability.ofPercent(500), 100),
+                Arguments.of(Probability.ofPercent(1000), 100)
+        );
+    }
+    @Test
+    void testAlwaysWinConstructor() {
         for (int i = 0; i < 100000; i++) {
         for (int i = 0; i < 100000; i++) {
-            assertTrue(processProbability(probability));
+            assertTrue(new ProbabilityImpl(100).evaluate());
         }
         }
     }
     }
 
 
     @Test
     @Test
-    void testIsSuccessfulRollFails() {
-        Probability probability = new ProbabilityImpl(0);
-
+    void testAlwaysLoseConstructor() {
         for (int i = 0; i < 100000; i++) {
         for (int i = 0; i < 100000; i++) {
-            assertFalse(processProbability(probability));
+            assertFalse(new ProbabilityImpl(0).evaluate());
         }
         }
     }
     }
 
 
     @Test
     @Test
-    void testIsSuccessfulRollFailsOfPercentage() {
-        Probability probability = Probability.ofPercentageValue(100);
+    void testAlwaysWinOfPercent() {
+        for (int i = 0; i < 100000; i++) {
+            assertTrue(Probability.ofPercent(100).evaluate());
+        }
+    }
 
 
+    @Test
+    void testAlwaysLoseOfPercent() {
         for (int i = 0; i < 100000; i++) {
         for (int i = 0; i < 100000; i++) {
-            assertFalse(processProbability(probability));
+            assertFalse(Probability.ofPercent(0).evaluate());
         }
         }
     }
     }
 
 
     @ParameterizedTest
     @ParameterizedTest
     @MethodSource("provideProbabilitiesForWithinExpectations")
     @MethodSource("provideProbabilitiesForWithinExpectations")
-    void testProcessProbabilityWithinExpectations(Probability probability, double expectedWinPercent) {
+    void testOddsExpectationsImplConstructor(Probability probability, double expectedWinPercent) {
         // Probabilities are tested 200,000,000 times with a margin of error of 0.01%
         // Probabilities are tested 200,000,000 times with a margin of error of 0.01%
         int iterations = 200000000;
         int iterations = 200000000;
         double winCount = 0;
         double winCount = 0;
 
 
         for (int i = 0; i < iterations; i++) {
         for (int i = 0; i < iterations; i++) {
-            if(processProbability(probability)) {
+            if(probability.evaluate()) {
                 winCount++;
                 winCount++;
             }
             }
         }
         }
@@ -75,11 +97,21 @@ class ProbabilityTest {
         assertEquals(expectedWinPercent, successPercent, 0.01D);
         assertEquals(expectedWinPercent, successPercent, 0.01D);
     }
     }
 
 
-    @Test
-    void ofPercentageValue() {
-    }
+    @ParameterizedTest
+    @MethodSource("provideOfPercentageProbabilitiesForWithinExpectations")
+    void testOddsExpectationsOfPercent(Probability probability, double expectedWinPercent) {
+        // Probabilities are tested 200,000,000 times with a margin of error of 0.01%
+        int iterations = 200000000;
+        double winCount = 0;
 
 
-    @Test
-    void ofSubSkill() {
+        for (int i = 0; i < iterations; i++) {
+            if(probability.evaluate()) {
+                winCount++;
+            }
+        }
+
+        double successPercent = (winCount / iterations) * 100;
+        System.out.println(successPercent + ", " + expectedWinPercent);
+        assertEquals(expectedWinPercent, successPercent, 0.01D);
     }
     }
-}
+}

+ 22 - 0
src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java

@@ -0,0 +1,22 @@
+package com.gmail.nossr50.util.random;
+
+import org.bukkit.entity.Player;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+class ProbabilityUtilTest {
+
+    // Mocks
+    Player player;
+
+    @BeforeEach
+    public void setupMocks() {
+        this.player = Mockito.mock(Player.class);
+    }
+
+    @Test
+    public void testChanceOfSuccessPercentage() {
+
+    }
+}

+ 0 - 16
src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java

@@ -1,16 +0,0 @@
-//package com.gmail.nossr50.util.skills;
-//
-//import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
-//import com.google.common.collect.ImmutableList;
-//import org.junit.Before;
-//import org.junit.Test;
-//import org.junit.runner.RunWith;
-//import org.powermock.core.classloader.annotations.PrepareForTest;
-//import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
-//import org.powermock.modules.junit4.PowerMockRunner;
-//
-//@RunWith(PowerMockRunner.class)
-//@PrepareForTest(SkillTools.class)
-//public class SkillToolsTest {
-//
-//}