RandomChanceUtil refactor part 1

This commit is contained in:
nossr50 2021-02-17 15:28:27 -08:00
parent 1bde79cd6f
commit f7640938df
43 changed files with 477 additions and 725 deletions

View File

@ -27,6 +27,7 @@ Version 2.1.175
Added 'Woodcutting.SubSkill.CleanCuts.Name' to locale Added 'Woodcutting.SubSkill.CleanCuts.Name' to locale
Added 'Woodcutting.SubSkill.CleanCuts.Stat' to locale Added 'Woodcutting.SubSkill.CleanCuts.Stat' to locale
Added 'Woodcutting.SubSkill.CleanCuts.Description' to locale Added 'Woodcutting.SubSkill.CleanCuts.Description' to locale
(Codebase) Major refactoring for how random chance was handled in the code
Added 'General.PowerLevel.Skill_Mastery.Enabled' to config.yml which is used to enable or disable the mastery skills (will also disable the new power level command) Added 'General.PowerLevel.Skill_Mastery.Enabled' to config.yml which is used to enable or disable the mastery skills (will also disable the new power level command)

View File

@ -0,0 +1,9 @@
package com.gmail.nossr50.api.exceptions;
import org.jetbrains.annotations.NotNull;
public class ValueOutOfBoundsException extends RuntimeException {
public ValueOutOfBoundsException(@NotNull String message) {
super(message);
}
}

View File

@ -6,9 +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.random.RandomChanceSkill;
import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.random.RandomChanceUtil;
import com.gmail.nossr50.util.skills.SkillActivationType;
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;
@ -31,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 = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_DODGE); String[] dodgeStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_DODGE);
dodgeChance = dodgeStrings[0]; dodgeChance = dodgeStrings[0];
dodgeChanceLucky = dodgeStrings[1]; dodgeChanceLucky = dodgeStrings[1];
} }
@ -61,18 +59,18 @@ public class AcrobaticsCommand extends SkillCommand {
double rollChance, graceChance; double rollChance, graceChance;
//Chance to roll at half //Chance to roll at half
RandomChanceSkill roll_rcs = new RandomChanceSkill(player, SubSkillType.ACROBATICS_ROLL); SkillProbabilityWrapper roll_rcs = new SkillProbabilityWrapper(player, SubSkillType.ACROBATICS_ROLL);
//Chance to graceful roll //Chance to graceful roll
RandomChanceSkill grace_rcs = new RandomChanceSkill(player, SubSkillType.ACROBATICS_ROLL); SkillProbabilityWrapper grace_rcs = new SkillProbabilityWrapper(player, SubSkillType.ACROBATICS_ROLL);
grace_rcs.setSkillLevel(grace_rcs.getSkillLevel() * 2); //Double Odds grace_rcs.setxPos(grace_rcs.getxPos() * 2); //Double Odds
//Chance Stat Calculations //Chance Stat Calculations
rollChance = RandomChanceUtil.getRandomChanceExecutionChance(roll_rcs); rollChance = RandomChanceUtil.getRandomChanceExecutionChance(roll_rcs);
graceChance = RandomChanceUtil.getRandomChanceExecutionChance(grace_rcs); graceChance = RandomChanceUtil.getRandomChanceExecutionChance(grace_rcs);
//damageThreshold = AdvancedConfig.getInstance().getRollDamageThreshold(); //damageThreshold = AdvancedConfig.getInstance().getRollDamageThreshold();
String[] rollStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_ROLL); String[] rollStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_ROLL);
//Format //Format
double rollChanceLucky = rollChance * 1.333D; double rollChanceLucky = rollChance * 1.333D;

View File

@ -6,7 +6,6 @@ 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.skills.CombatUtils; import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
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 +32,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 = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ARCHERY_ARROW_RETRIEVAL); String[] retrieveStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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 = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ARCHERY_DAZE); String[] dazeStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ARCHERY_DAZE);
dazeChance = dazeStrings[0]; dazeChance = dazeStrings[0];
dazeChanceLucky = dazeStrings[1]; dazeChanceLucky = dazeStrings[1];
} }

View File

@ -8,7 +8,6 @@ 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.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.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 +47,7 @@ public class AxesCommand extends SkillCommand {
// CRITICAL HIT // CRITICAL HIT
if (canCritical) { if (canCritical) {
String[] criticalHitStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.AXES_CRITICAL_STRIKES); String[] criticalHitStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.AXES_CRITICAL_STRIKES);
critChance = criticalHitStrings[0]; critChance = criticalHitStrings[0];
critChanceLucky = criticalHitStrings[1]; critChanceLucky = criticalHitStrings[1];
} }

View File

@ -5,7 +5,6 @@ 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.skills.RankUtils; import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
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;
@ -45,7 +44,7 @@ public class HerbalismCommand extends SkillCommand {
// DOUBLE DROPS // DOUBLE DROPS
if (canDoubleDrop) { if (canDoubleDrop) {
String[] doubleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.HERBALISM_DOUBLE_DROPS); String[] doubleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.HERBALISM_DOUBLE_DROPS);
doubleDropChance = doubleDropStrings[0]; doubleDropChance = doubleDropStrings[0];
doubleDropChanceLucky = doubleDropStrings[1]; doubleDropChanceLucky = doubleDropStrings[1];
} }
@ -66,21 +65,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 = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.HERBALISM_GREEN_THUMB); String[] greenThumbStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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 = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.HERBALISM_HYLIAN_LUCK); String[] hylianLuckStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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 = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.HERBALISM_SHROOM_THUMB); String[] shroomThumbStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.HERBALISM_SHROOM_THUMB);
shroomThumbChance = shroomThumbStrings[0]; shroomThumbChance = shroomThumbStrings[0];
shroomThumbChanceLucky = shroomThumbStrings[1]; shroomThumbChanceLucky = shroomThumbStrings[1];
} }

View File

@ -7,7 +7,6 @@ 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.skills.RankUtils; import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
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;
@ -32,7 +31,7 @@ public class MiningCommand extends SkillCommand {
private boolean canSuperBreaker; private boolean canSuperBreaker;
private boolean canDoubleDrop; private boolean canDoubleDrop;
private boolean canTripleDrop; private boolean canMotherLode;
private boolean canBlast; private boolean canBlast;
private boolean canBiggerBombs; private boolean canBiggerBombs;
private boolean canDemoExpert; private boolean canDemoExpert;
@ -56,16 +55,15 @@ public class MiningCommand extends SkillCommand {
} }
// Mastery TRIPLE DROPS // Mastery TRIPLE DROPS
if (canTripleDrop) { if (canMotherLode) {
String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.MINING_MOTHER_LODE); String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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 = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.MINING_DOUBLE_DROPS); String[] doubleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.MINING_DOUBLE_DROPS);
doubleDropChance = doubleDropStrings[0]; doubleDropChance = doubleDropStrings[0];
doubleDropChanceLucky = doubleDropStrings[1]; doubleDropChanceLucky = doubleDropStrings[1];
} }
@ -84,7 +82,7 @@ public class MiningCommand extends SkillCommand {
canBlast = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_BLAST_MINING) && Permissions.remoteDetonation(player); canBlast = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_BLAST_MINING) && Permissions.remoteDetonation(player);
canDemoExpert = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_DEMOLITIONS_EXPERTISE) && Permissions.demolitionsExpertise(player); canDemoExpert = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_DEMOLITIONS_EXPERTISE) && Permissions.demolitionsExpertise(player);
canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.MINING_DOUBLE_DROPS); canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.MINING_DOUBLE_DROPS);
canTripleDrop = Permissions.canUseSubSkill(player, SubSkillType.MINING_MOTHER_LODE); canMotherLode = Permissions.canUseSubSkill(player, SubSkillType.MINING_MOTHER_LODE);
canSuperBreaker = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_SUPER_BREAKER) && Permissions.superBreaker(player); canSuperBreaker = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_SUPER_BREAKER) && Permissions.superBreaker(player);
} }
@ -113,7 +111,7 @@ public class MiningCommand extends SkillCommand {
//messages.add(LocaleLoader.getString("Mining.Effect.DropChance", doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : "")); //messages.add(LocaleLoader.getString("Mining.Effect.DropChance", doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : ""));
} }
if(canTripleDrop) { if(canMotherLode) {
messages.add(getStatMessage(SubSkillType.MINING_MOTHER_LODE, tripleDropChance) messages.add(getStatMessage(SubSkillType.MINING_MOTHER_LODE, tripleDropChance)
+ (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", tripleDropChanceLucky) : "")); + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", tripleDropChanceLucky) : ""));
} }

View File

@ -12,7 +12,6 @@ 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.skills.RankUtils; import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
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 +67,7 @@ public class RepairCommand extends SkillCommand {
// SUPER REPAIR // SUPER REPAIR
if (canSuperRepair) { if (canSuperRepair) {
String[] superRepairStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.REPAIR_SUPER_REPAIR); String[] superRepairStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.REPAIR_SUPER_REPAIR);
superRepairChance = superRepairStrings[0]; superRepairChance = superRepairStrings[0];
superRepairChanceLucky = superRepairStrings[1]; superRepairChanceLucky = superRepairStrings[1];
} }

View File

@ -219,7 +219,7 @@ public abstract class SkillCommand implements TabExecutor {
return Math.min((int) skillValue, maxLevel) / rankChangeLevel; return Math.min((int) skillValue, maxLevel) / rankChangeLevel;
} }
protected String[] getAbilityDisplayValues(SkillActivationType skillActivationType, Player player, SubSkillType subSkill) { protected static String[] getAbilityDisplayValues(SkillActivationType skillActivationType, Player player, SubSkillType subSkill) {
return RandomChanceUtil.calculateAbilityDisplayValues(skillActivationType, player, subSkill); return RandomChanceUtil.calculateAbilityDisplayValues(skillActivationType, player, subSkill);
} }

View File

@ -6,7 +6,6 @@ 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.skills.RankUtils; import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
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,14 +38,14 @@ public class SmeltingCommand extends SkillCommand {
// FLUX MINING // FLUX MINING
/*if (canFluxMine) { /*if (canFluxMine) {
String[] fluxMiningStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.SMELTING_FLUX_MINING); String[] fluxMiningStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SMELTING_FLUX_MINING);
str_fluxMiningChance = fluxMiningStrings[0]; str_fluxMiningChance = fluxMiningStrings[0];
str_fluxMiningChanceLucky = fluxMiningStrings[1]; str_fluxMiningChanceLucky = fluxMiningStrings[1];
}*/ }*/
// SECOND SMELT // SECOND SMELT
if (canSecondSmelt) { if (canSecondSmelt) {
String[] secondSmeltStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.SMELTING_SECOND_SMELT); String[] secondSmeltStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SMELTING_SECOND_SMELT);
str_secondSmeltChance = secondSmeltStrings[0]; str_secondSmeltChance = secondSmeltStrings[0];
str_secondSmeltChanceLucky = secondSmeltStrings[1]; str_secondSmeltChanceLucky = secondSmeltStrings[1];
} }

View File

@ -8,7 +8,6 @@ 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.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.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;
@ -37,7 +36,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 = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.SWORDS_COUNTER_ATTACK); String[] counterStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SWORDS_COUNTER_ATTACK);
counterChance = counterStrings[0]; counterChance = counterStrings[0];
counterChanceLucky = counterStrings[1]; counterChanceLucky = counterStrings[1];
} }
@ -46,7 +45,7 @@ public class SwordsCommand extends SkillCommand {
if (canBleed) { if (canBleed) {
bleedLength = UserManager.getPlayer(player).getSwordsManager().getRuptureBleedTicks(); bleedLength = UserManager.getPlayer(player).getSwordsManager().getRuptureBleedTicks();
String[] bleedStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.SWORDS_RUPTURE); String[] bleedStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.SWORDS_RUPTURE);
bleedChance = bleedStrings[0]; bleedChance = bleedStrings[0];
bleedChanceLucky = bleedStrings[1]; bleedChanceLucky = bleedStrings[1];
} }

View File

@ -5,7 +5,6 @@ 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.SkillActivationType;
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 +34,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 = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.TAMING_GORE); String[] goreStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.TAMING_GORE);
goreChance = goreStrings[0]; goreChance = goreStrings[0];
goreChanceLucky = goreStrings[1]; goreChanceLucky = goreStrings[1];
} }

View File

@ -7,7 +7,6 @@ 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.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.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 +39,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 = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.UNARMED_ARROW_DEFLECT); String[] deflectStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.UNARMED_ARROW_DEFLECT);
deflectChance = deflectStrings[0]; deflectChance = deflectStrings[0];
deflectChanceLucky = deflectStrings[1]; deflectChanceLucky = deflectStrings[1];
} }
@ -54,7 +53,7 @@ public class UnarmedCommand extends SkillCommand {
// UNARMED_DISARM // UNARMED_DISARM
if (canDisarm) { if (canDisarm) {
String[] disarmStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.UNARMED_DISARM); String[] disarmStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.UNARMED_DISARM);
disarmChance = disarmStrings[0]; disarmChance = disarmStrings[0];
disarmChanceLucky = disarmStrings[1]; disarmChanceLucky = disarmStrings[1];
} }
@ -66,7 +65,7 @@ public class UnarmedCommand extends SkillCommand {
// IRON GRIP // IRON GRIP
if (canIronGrip) { if (canIronGrip) {
String[] ironGripStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.UNARMED_IRON_GRIP); String[] ironGripStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.UNARMED_IRON_GRIP);
ironGripChance = ironGripStrings[0]; ironGripChance = ironGripStrings[0];
ironGripChanceLucky = ironGripStrings[1]; ironGripChanceLucky = ironGripStrings[1];
} }

View File

@ -5,7 +5,6 @@ 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.skills.RankUtils; import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
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;
@ -43,7 +42,7 @@ public class WoodcuttingCommand extends SkillCommand {
//Clean Cuts //Clean Cuts
if(canTripleDrop) { if(canTripleDrop) {
String[] tripleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.WOODCUTTING_CLEAN_CUTS); String[] tripleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.WOODCUTTING_CLEAN_CUTS);
tripleDropChance = tripleDropStrings[0]; tripleDropChance = tripleDropStrings[0];
tripleDropChanceLucky = tripleDropStrings[1]; tripleDropChanceLucky = tripleDropStrings[1];
} }
@ -57,7 +56,7 @@ public class WoodcuttingCommand extends SkillCommand {
} }
private void setDoubleDropClassicChanceStrings(Player player) { private void setDoubleDropClassicChanceStrings(Player player) {
String[] doubleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.WOODCUTTING_HARVEST_LUMBER); String[] doubleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.WOODCUTTING_HARVEST_LUMBER);
doubleDropChance = doubleDropStrings[0]; doubleDropChance = doubleDropStrings[0];
doubleDropChanceLucky = doubleDropStrings[1]; doubleDropChanceLucky = doubleDropStrings[1];
} }

View File

@ -14,11 +14,10 @@ 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.player.UserManager; import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.random.RandomChanceSkill;
import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.random.RandomChanceUtil;
import com.gmail.nossr50.util.random.SkillProbabilityType;
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;
@ -125,14 +124,14 @@ 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 = RandomChanceUtil.calculateAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_ROLL); String[] rollStrings = RandomChanceUtil.calculateAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_ROLL);
rollChance = rollStrings[0]; rollChance = rollStrings[0];
rollChanceLucky = rollStrings[1]; rollChanceLucky = rollStrings[1];
/* /*
* Graceful is double the odds of a normal roll * Graceful is double the odds of a normal roll
*/ */
String[] gracefulRollStrings = RandomChanceUtil.calculateAbilityDisplayValuesCustom(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_ROLL, 2.0D); String[] gracefulRollStrings = RandomChanceUtil.calculateAbilityDisplayValuesCustom(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.ACROBATICS_ROLL, 2.0D);
gracefulRollChance = gracefulRollStrings[0]; gracefulRollChance = gracefulRollStrings[0];
gracefulRollChanceLucky = gracefulRollStrings[1]; gracefulRollChanceLucky = gracefulRollStrings[1];
@ -199,7 +198,7 @@ public class Roll extends AcrobaticsSubSkill {
double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold()); double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold());
if (!isFatal(player, modifiedDamage) if (!isFatal(player, modifiedDamage)
&& RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ACROBATICS_ROLL, player)) { && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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"));
@ -236,11 +235,11 @@ 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, AdvancedConfig.getInstance().getRollDamageThreshold() * 2); double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold() * 2);
RandomChanceSkill rcs = new RandomChanceSkill(player, subSkillType); SkillProbabilityWrapper rcs = new SkillProbabilityWrapper(player, subSkillType);
rcs.setSkillLevel(rcs.getSkillLevel() * 2); //Double the effective odds rcs.setxPos(rcs.getxPos() * 2); //Double the effective odds
if (!isFatal(player, modifiedDamage) if (!isFatal(player, modifiedDamage)
&& RandomChanceUtil.checkRandomChanceExecutionSuccess(rcs)) && RandomChanceUtil.processProbabilityResults(rcs))
{ {
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);
@ -373,17 +372,17 @@ public class Roll extends AcrobaticsSubSkill {
double rollChanceHalfMax, graceChanceHalfMax, damageThreshold, chancePerLevel; double rollChanceHalfMax, graceChanceHalfMax, damageThreshold, chancePerLevel;
//Chance to roll at half max skill //Chance to roll at half max skill
RandomChanceSkill rollHalfMaxSkill = new RandomChanceSkill(null, subSkillType); SkillProbabilityWrapper rollHalfMaxSkill = new SkillProbabilityWrapper(null, subSkillType);
int halfMaxSkillValue = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL)/2; int halfMaxSkillValue = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL)/2;
rollHalfMaxSkill.setSkillLevel(halfMaxSkillValue); rollHalfMaxSkill.setxPos(halfMaxSkillValue);
//Chance to graceful roll at full skill //Chance to graceful roll at full skill
RandomChanceSkill rollGraceHalfMaxSkill = new RandomChanceSkill(null, subSkillType); SkillProbabilityWrapper rollGraceHalfMaxSkill = new SkillProbabilityWrapper(null, subSkillType);
rollGraceHalfMaxSkill.setSkillLevel(halfMaxSkillValue * 2); //Double the effective odds rollGraceHalfMaxSkill.setxPos(halfMaxSkillValue * 2); //Double the effective odds
//Chance to roll per level //Chance to roll per level
RandomChanceSkill rollOneSkillLevel = new RandomChanceSkill(null, subSkillType); SkillProbabilityWrapper rollOneSkillLevel = new SkillProbabilityWrapper(null, subSkillType);
rollGraceHalfMaxSkill.setSkillLevel(1); //Level 1 skill rollGraceHalfMaxSkill.setxPos(1); //Level 1 skill
//Chance Stat Calculations //Chance Stat Calculations
rollChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollHalfMaxSkill); rollChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollHalfMaxSkill);
@ -408,10 +407,10 @@ public class Roll extends AcrobaticsSubSkill {
{ {
double playerChanceRoll, playerChanceGrace; double playerChanceRoll, playerChanceGrace;
RandomChanceSkill roll = new RandomChanceSkill(player, getSubSkillType()); SkillProbabilityWrapper roll = new SkillProbabilityWrapper(player, getSubSkillType());
RandomChanceSkill graceful = new RandomChanceSkill(player, getSubSkillType()); SkillProbabilityWrapper graceful = new SkillProbabilityWrapper(player, getSubSkillType());
graceful.setSkillLevel(graceful.getSkillLevel() * 2); //Double odds graceful.setxPos(graceful.getxPos() * 2); //Double odds
//Calculate //Calculate
playerChanceRoll = RandomChanceUtil.getRandomChanceExecutionChance(roll); playerChanceRoll = RandomChanceUtil.getRandomChanceExecutionChance(roll);

View File

@ -1,26 +1,37 @@
package com.gmail.nossr50.datatypes.treasure; package com.gmail.nossr50.datatypes.treasure;
import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.util.random.Probability;
import com.gmail.nossr50.util.random.ProbabilityFactory;
import com.gmail.nossr50.util.random.ProbabilityImpl;
import com.google.common.base.Objects;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public abstract class Treasure { public abstract class Treasure {
private int xp; private int xp;
private double dropChance; private double dropChance;
private @NotNull Probability dropProbability;
private int dropLevel; private int dropLevel;
private ItemStack drop; private @NotNull ItemStack drop;
public Treasure(ItemStack drop, int xp, double dropChance, int dropLevel) { public Treasure(ItemStack drop, int xp, double dropChance, int dropLevel) {
this.drop = drop; this.drop = drop;
this.xp = xp; this.xp = xp;
this.dropChance = dropChance; this.dropChance = dropChance;
this.dropProbability = new ProbabilityImpl(ProbabilityFactory.probabilityFromPercent(dropChance));
this.dropLevel = dropLevel; this.dropLevel = dropLevel;
} }
public ItemStack getDrop() { public @NotNull Probability getDropProbability() {
return dropProbability;
}
public @NotNull ItemStack getDrop() {
return drop; return drop;
} }
public void setDrop(ItemStack drop) { public void setDrop(@NotNull ItemStack drop) {
this.drop = drop; this.drop = drop;
} }
@ -36,8 +47,9 @@ public abstract class Treasure {
return dropChance; return dropChance;
} }
public void setDropChance(Double dropChance) { public void setDropChance(double dropChance) {
this.dropChance = dropChance; this.dropChance = dropChance;
this.dropProbability = new ProbabilityImpl(ProbabilityFactory.probabilityFromPercent(dropChance));
} }
public int getDropLevel() { public int getDropLevel() {
@ -51,4 +63,28 @@ public abstract class Treasure {
public void setDropLevel(int dropLevel) { public void setDropLevel(int dropLevel) {
this.dropLevel = dropLevel; this.dropLevel = dropLevel;
} }
@Override
public String toString() {
return "Treasure{" +
"xp=" + xp +
", dropChance=" + dropChance +
", dropProbability=" + dropProbability +
", dropLevel=" + dropLevel +
", drop=" + drop +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Treasure treasure = (Treasure) o;
return xp == treasure.xp && Double.compare(treasure.dropChance, dropChance) == 0 && dropLevel == treasure.dropLevel && Objects.equal(dropProbability, treasure.dropProbability) && Objects.equal(drop, treasure.drop);
}
@Override
public int hashCode() {
return Objects.hashCode(xp, dropChance, dropProbability, dropLevel, drop);
}
} }

View File

@ -25,9 +25,8 @@ import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDat
import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType; import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType;
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.skills.CombatUtils; import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.SkillActivationType; 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.Material; import org.bukkit.Material;
@ -180,7 +179,7 @@ public class EntityListener implements Listener {
} }
} }
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) { if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.ARCHERY_ARROW_RETRIEVAL, player)) {
projectile.setMetadata(mcMMO.trackedArrow, mcMMO.metadataValue); projectile.setMetadata(mcMMO.trackedArrow, mcMMO.metadataValue);
} }
} }

View File

@ -12,10 +12,8 @@ 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.RandomChanceUtil;
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.SkillActivationType;
import com.gmail.nossr50.util.skills.SkillUtils; 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;
@ -88,7 +86,7 @@ public class AcrobaticsManager extends SkillManager {
double modifiedDamage = Acrobatics.calculateModifiedDodgeDamage(damage, Acrobatics.dodgeDamageModifier); double modifiedDamage = Acrobatics.calculateModifiedDodgeDamage(damage, Acrobatics.dodgeDamageModifier);
Player player = getPlayer(); Player player = getPlayer();
if (!isFatal(modifiedDamage) && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ACROBATICS_DODGE, player)) { if (!isFatal(modifiedDamage) && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.ACROBATICS_DODGE, player)) {
ParticleEffectUtils.playDodgeEffect(player); ParticleEffectUtils.playDodgeEffect(player);
if (mmoPlayer.useChatNotifications()) { if (mmoPlayer.useChatNotifications()) {

View File

@ -9,9 +9,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.RandomChanceUtil;
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.SkillActivationType;
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 (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ARCHERY_DAZE, getPlayer())) { if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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 (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) { if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) {
return oldDamage; return oldDamage;
} }

View File

@ -11,7 +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.RandomChanceUtil; import com.gmail.nossr50.util.random.SkillProbabilityType;
import com.gmail.nossr50.util.skills.*; import com.gmail.nossr50.util.skills.*;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -69,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 (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.AXES_AXE_MASTERY, getPlayer())) { if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.AXES_AXE_MASTERY, getPlayer())) {
return 0; return 0;
} }
@ -83,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 (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) { if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) {
return 0; return 0;
} }
@ -119,7 +119,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 (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) { if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) {
SkillUtils.handleDurabilityChange(armor, durabilityDamage, 1); SkillUtils.handleDurabilityChange(armor, durabilityDamage, 1);
} }
} }
@ -137,7 +137,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 (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_GREATER_IMPACT, getPlayer())) { if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.AXES_GREATER_IMPACT, getPlayer())) {
return 0; return 0;
} }

View File

@ -41,7 +41,7 @@ public class ExcavationManager extends SkillManager {
for (ExcavationTreasure treasure : treasures) { for (ExcavationTreasure treasure : treasures) {
if (skillLevel >= treasure.getDropLevel() if (skillLevel >= treasure.getDropLevel()
&& RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), PrimarySkillType.EXCAVATION, treasure.getDropChance())) { && SkillUtils.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(RandomChanceUtil.rollDice(getArchaelogyExperienceOrbChance(), 100)) { if(RandomChanceUtil.rollDice(getArchaelogyExperienceOrbChance(), 100)) {

View File

@ -20,8 +20,6 @@ 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.RandomChanceSkillStatic;
import com.gmail.nossr50.util.random.RandomChanceUtil;
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;
@ -63,11 +61,14 @@ public class FishingManager extends SkillManager {
} }
public boolean canShake(Entity target) { public boolean canShake(Entity target) {
return target instanceof LivingEntity && RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.FISHING_SHAKE) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_SHAKE); return target instanceof LivingEntity && RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.FISHING_SHAKE)
&& Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_SHAKE);
} }
public boolean canMasterAngler() { public boolean canMasterAngler() {
return mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() != null && getSkillLevel() >= RankUtils.getUnlockLevel(SubSkillType.FISHING_MASTER_ANGLER) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_MASTER_ANGLER); return mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() != null
&& getSkillLevel() >= RankUtils.getUnlockLevel(SubSkillType.FISHING_MASTER_ANGLER)
&& Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.FISHING_MASTER_ANGLER);
} }
// public void setFishingRodCastTimestamp() // public void setFishingRodCastTimestamp()
@ -477,8 +478,8 @@ 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(LivingEntity target) { public void shakeCheck(@NotNull LivingEntity target) {
if (RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getShakeChance(), getPlayer(), SubSkillType.FISHING_SHAKE))) { if (SkillUtils.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()) {

View File

@ -21,10 +21,8 @@ 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.RandomChanceSkillStatic;
import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.random.RandomChanceUtil;
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;
@ -589,7 +587,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 (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.HERBALISM_GREEN_THUMB, getPlayer())) { if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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;
} }
@ -604,7 +602,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 (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) { if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) {
return false; return false;
} }
@ -623,7 +621,7 @@ public class HerbalismManager extends SkillManager {
for (HylianTreasure treasure : treasures) { for (HylianTreasure treasure : treasures) {
if (skillLevel >= treasure.getDropLevel() if (skillLevel >= treasure.getDropLevel()
&& RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(treasure.getDropChance(), getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK))) { && RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(treasure.getDropChance(), getPlayer(), SubSkillType.HERBALISM_HYLIAN_LUCK))) {
if (!EventUtils.simulateBlockBreak(blockState.getBlock(), player, false)) { if (!EventUtils.simulateBlockBreak(blockState.getBlock(), player, false)) {
return false; return false;
} }
@ -660,7 +658,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 (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.HERBALISM_SHROOM_THUMB, player)) { if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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;
} }

View File

@ -16,10 +16,8 @@ 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.RandomChanceSkillStatic;
import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.random.RandomChanceUtil;
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;
@ -291,7 +289,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 (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.REPAIR_SUPER_REPAIR, getPlayer())) { if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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;
} }
@ -342,10 +340,10 @@ public class RepairManager extends SkillManager {
Enchantment enchantment = enchant.getKey(); Enchantment enchantment = enchant.getKey();
if (RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getKeepEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING))) { if (RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(getKeepEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING))) {
if (ArcaneForging.arcaneForgingDowngrades && enchantLevel > 1 if (ArcaneForging.arcaneForgingDowngrades && enchantLevel > 1
&& (!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(100 - getDowngradeEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING)))) { && (!RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(100 - getDowngradeEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING)))) {
item.addUnsafeEnchantment(enchantment, enchantLevel - 1); item.addUnsafeEnchantment(enchantment, enchantLevel - 1);
downgraded = true; downgraded = true;
} }

View File

@ -16,7 +16,6 @@ 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.RandomChanceSkillStatic;
import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.random.RandomChanceUtil;
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;
@ -123,7 +122,7 @@ public class SalvageManager extends SkillManager {
for(int x = 0; x < potentialSalvageYield-1; x++) { for(int x = 0; x < potentialSalvageYield-1; x++) {
if(RandomChanceUtil.rollDice(chanceOfSuccess, 100)) { if(RandomChanceUtil.rollDiceSimple(chanceOfSuccess, 100)) {
chanceOfSuccess-=3; chanceOfSuccess-=3;
chanceOfSuccess = Math.max(chanceOfSuccess, 90); chanceOfSuccess = Math.max(chanceOfSuccess, 90);
@ -253,12 +252,12 @@ public class SalvageManager extends SkillManager {
if (!Salvage.arcaneSalvageEnchantLoss if (!Salvage.arcaneSalvageEnchantLoss
|| Permissions.hasSalvageEnchantBypassPerk(player) || Permissions.hasSalvageEnchantBypassPerk(player)
|| RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractFullEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { || RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(getExtractFullEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) {
enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true); enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true);
} }
else if (enchantLevel > 1 else if (enchantLevel > 1
&& Salvage.arcaneSalvageDowngrades && Salvage.arcaneSalvageDowngrades
&& RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractPartialEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { && RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(getExtractPartialEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) {
enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true); enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true);
downgraded = true; downgraded = true;
} else { } else {

View File

@ -8,9 +8,8 @@ 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.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.RandomChanceUtil;
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.event.inventory.FurnaceBurnEvent; import org.bukkit.event.inventory.FurnaceBurnEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -28,7 +27,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)
&& RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SMELTING_SECOND_SMELT, getPlayer()); && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.SMELTING_SECOND_SMELT, getPlayer());
} }
/* /*

View File

@ -11,10 +11,9 @@ 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.RandomChanceUtil;
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;
@ -62,7 +61,7 @@ public class SwordsManager extends SkillManager {
*/ */
public void ruptureCheck(@NotNull LivingEntity target) throws IllegalStateException { public void ruptureCheck(@NotNull LivingEntity target) throws IllegalStateException {
if(BleedTimerTask.isBleedOperationAllowed()) { if(BleedTimerTask.isBleedOperationAllowed()) {
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_RUPTURE, getPlayer())) { if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.SWORDS_RUPTURE, getPlayer())) {
if (target instanceof Player) { if (target instanceof Player) {
Player defender = (Player) target; Player defender = (Player) target;
@ -129,7 +128,7 @@ public class SwordsManager 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 void counterAttackChecks(@NotNull LivingEntity attacker, double damage) { public void counterAttackChecks(@NotNull LivingEntity attacker, double damage) {
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) { if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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");

View File

@ -18,11 +18,10 @@ import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType; import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType;
import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.random.RandomChanceSkillStatic;
import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.random.RandomChanceUtil;
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.SkillActivationType; 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;
@ -147,7 +146,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 (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) { if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) {
return; return;
} }
@ -168,7 +167,7 @@ public class TamingManager extends SkillManager {
*/ */
public double gore(@NotNull LivingEntity target, double damage) { public double gore(@NotNull LivingEntity target, double damage) {
if(BleedTimerTask.isBleedOperationAllowed()) { if(BleedTimerTask.isBleedOperationAllowed()) {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.TAMING_GORE, getPlayer())) { if (!SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.TAMING_GORE, getPlayer())) {
return 0; return 0;
} }
@ -276,7 +275,7 @@ public class TamingManager extends SkillManager {
if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL)) if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL))
return; return;
if(!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(AdvancedConfig.getInstance().getPummelChance(), getPlayer(), SubSkillType.TAMING_PUMMEL))) if(!RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapperStatic(AdvancedConfig.getInstance().getPummelChance(), getPlayer(), SubSkillType.TAMING_PUMMEL)))
return; return;
ParticleEffectUtils.playGreaterImpactEffect(target); ParticleEffectUtils.playGreaterImpactEffect(target);

View File

@ -16,9 +16,9 @@ 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.player.UserManager; import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.random.RandomChanceUtil;
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.SkillActivationType;
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;
@ -72,7 +72,7 @@ public class UnarmedManager extends SkillManager {
} }
public boolean blockCrackerCheck(@NotNull BlockState blockState) { public boolean blockCrackerCheck(@NotNull BlockState blockState) {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) { if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) {
return false; return false;
} }
@ -103,7 +103,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 (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) { if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) {
if (EventUtils.callDisarmEvent(defender).isCancelled()) { if (EventUtils.callDisarmEvent(defender).isCancelled()) {
return; return;
} }
@ -126,7 +126,7 @@ public class UnarmedManager extends SkillManager {
* Check for arrow deflection. * Check for arrow deflection.
*/ */
public boolean deflectCheck() { public boolean deflectCheck() {
if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_ARROW_DEFLECT, getPlayer())) { if (SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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;
} }
@ -149,7 +149,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 (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) { if (!SkillUtils.isSkillRNGSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) {
return 0; return 0;
} }
@ -183,7 +183,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)
&& RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_IRON_GRIP, defender)) { && SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, 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");

View File

@ -17,7 +17,6 @@ import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.random.RandomChanceUtil;
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;
@ -70,11 +69,11 @@ public class WoodcuttingManager extends SkillManager {
} }
private boolean checkHarvestLumberActivation() { private boolean checkHarvestLumberActivation() {
return RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()); return SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer());
} }
private boolean checkCleanCutsActivation() { private boolean checkCleanCutsActivation() {
return RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer()); return SkillUtils.isSkillRNGSuccessful(SkillProbabilityType.DYNAMIC_CONFIGURABLE, SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer());
} }
/** /**
@ -328,7 +327,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(AdvancedConfig.getInstance().isKnockOnWoodXPOrbEnabled()) { if(AdvancedConfig.getInstance().isKnockOnWoodXPOrbEnabled()) {
if(RandomChanceUtil.rollDice(10, 100)) { if(RandomChanceUtil.rollDiceSimple(10, 100)) {
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);
} }

View File

@ -8,7 +8,6 @@ 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.random.RandomChanceSkill;
import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.random.RandomChanceUtil;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@ -55,7 +54,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 (Config.getInstance().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) { if (Config.getInstance().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) {
return RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, true)); return RandomChanceUtil.processProbabilityResults(new SkillProbabilityWrapper(player, subSkillType, true));
} }
return false; return false;

View File

@ -344,4 +344,26 @@ public final class Misc {
experienceOrb.setExperience(orbExpValue); experienceOrb.setExperience(orbExpValue);
} }
} }
// public static void hackyUnitTest(@NotNull McMMOPlayer normalPlayer) {
// mcMMO.p.getLogger().info("Starting hacky unit test...");
// int iterations = 1000000;
// double ratioDivisor = 10000; //10000 because we run the test 1,000,000 times
// double expectedFailRate = 100.0D - RandomChanceUtil.getRandomChanceExecutionSuccess(normalPlayer.getPlayer(), SubSkillType.MINING_MOTHER_LODE, true);
//
// double win = 0, loss = 0;
// for(int x = 0; x < iterations; x++) {
// if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer.getPlayer(), SubSkillType.MINING_MOTHER_LODE, true)) {
// win++;
// } else {
// loss++;
// }
// }
//
// double lossRatio = (loss / ratioDivisor);
// mcMMO.p.getLogger().info("Expected Fail Rate: "+expectedFailRate);
// mcMMO.p.getLogger().info("Loss Ratio for hacky test: "+lossRatio);
//// Assert.assertEquals(lossRatio, expectedFailRate, 0.01D);
// }
} }

View File

@ -0,0 +1,14 @@
package com.gmail.nossr50.util.random;
public interface Probability {
/**
* The value of this Probability
* Should return a result between 0 and 1 (inclusive)
* 1 should represent something that will always succeed
* 0.5 should represent something that succeeds around half the time
* etc
*
* @return the value of probability
*/
double getValue();
}

View File

@ -0,0 +1,77 @@
package com.gmail.nossr50.util.random;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.util.player.UserManager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ProbabilityFactory {
public static @NotNull Probability ofPercentageValue(double percentageValue) {
return new ProbabilityImpl(probabilityFromPercent(percentageValue));
}
public static @NotNull Probability ofSubSkill(@Nullable Player player,
@NotNull SubSkillType subSkillType,
@NotNull SkillProbabilityType skillProbabilityType) throws InvalidStaticChance, RuntimeException {
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;
}
//Probability ceiling is configurable in this type
probabilityCeiling = AdvancedConfig.getInstance().getMaximumProbability(subSkillType);
//The xCeiling is configurable in this type
xCeiling = AdvancedConfig.getInstance().getMaxBonusLevel(subSkillType);
return new ProbabilityImpl(xPos, xCeiling, probabilityCeiling);
case STATIC_CONFIGURABLE:
return ofPercentageValue(getStaticRandomChance(subSkillType));
default:
throw new RuntimeException("No case in switch statement for Skill Probability Type!");
}
}
/**
* Convert a probability from a percentage
* @param percentage value to convert
* @return 0 -> 1 inclusive representation of probability
*/
public static double probabilityFromPercent(double percentage) {
return percentage / 100;
}
/**
* Grabs static activation rolls for Secondary Abilities
*
* @param subSkillType The secondary ability to grab properties of
* @return The static activation roll involved in the RNG calculation
* @throws InvalidStaticChance if the skill has no defined static chance this exception will be thrown and you should know you're a naughty boy
*/
private static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance {
switch (subSkillType) {
case AXES_ARMOR_IMPACT:
return AdvancedConfig.getInstance().getImpactChance();
case AXES_GREATER_IMPACT:
return AdvancedConfig.getInstance().getGreaterImpactChance();
case TAMING_FAST_FOOD_SERVICE:
return AdvancedConfig.getInstance().getFastFoodChance();
default:
throw new InvalidStaticChance();
}
}
}

View File

@ -0,0 +1,63 @@
package com.gmail.nossr50.util.random;
import com.gmail.nossr50.api.exceptions.ValueOutOfBoundsException;
import com.google.common.base.Objects;
public class ProbabilityImpl implements Probability {
private final double probabilityValue;
/**
* Create a probability with a static value
*
* @param staticProbability the value to assign to this probability
*/
public ProbabilityImpl(double staticProbability) throws ValueOutOfBoundsException {
if(staticProbability > 1) {
throw new ValueOutOfBoundsException("Value should never be above 1 for Probability! This suggests a coding mistake, contact the devs!");
} else if (staticProbability < 0) {
throw new ValueOutOfBoundsException("Value should never be negative for Probability! This suggests a coding mistake, contact the devs!");
}
probabilityValue = staticProbability;
}
public ProbabilityImpl(double xPos, double xCeiling, double probabilityCeiling) throws ValueOutOfBoundsException {
if(probabilityCeiling > 100) {
throw new ValueOutOfBoundsException("Probability Ceiling should never be above 100!");
} else if (probabilityCeiling < 0) {
throw new ValueOutOfBoundsException("Probability Ceiling should never be below 0!");
}
//Get the percent success, this will be from 0-100
double probabilityPercent = (probabilityCeiling * (xPos / xCeiling));
//Convert to a 0-1 floating point representation
this.probabilityValue = probabilityPercent / 100.0D;
}
@Override
public double getValue() {
return probabilityValue;
}
@Override
public String toString() {
return "ProbabilityImpl{" +
"probabilityValue=" + probabilityValue +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProbabilityImpl that = (ProbabilityImpl) o;
return Double.compare(that.probabilityValue, probabilityValue) == 0;
}
@Override
public int hashCode() {
return Objects.hashCode(probabilityValue);
}
}

View File

@ -1,18 +0,0 @@
package com.gmail.nossr50.util.random;
public interface RandomChanceExecution {
/**
* Gets the XPos used in the formula for success
*
* @return value of x for our success probability graph
*/
double getXPos();
/**
* The maximum odds for this RandomChanceExecution
* For example, if this value is 10, then 10% odds would be the maximum and would be achieved only when xPos equaled the LinearCurvePeak
*
* @return maximum probability odds from 0.00 (no chance of ever happened) to 100.0 (probability can be guaranteed)
*/
double getProbabilityCap();
}

View File

@ -1,176 +0,0 @@
package com.gmail.nossr50.util.random;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
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;
public class RandomChanceSkill implements RandomChanceExecution {
protected final double probabilityCap;
protected final boolean isLucky;
protected int skillLevel;
protected final double resultModifier;
protected final double maximumBonusLevelCap;
public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, double resultModifier) {
this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR;
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
if (player != null && mcMMOPlayer != null) {
this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill());
} else {
this.skillLevel = 0;
}
if (player != null)
isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
else
isLucky = false;
this.resultModifier = resultModifier;
this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType);
}
public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType) {
this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR;
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
if (player != null && mcMMOPlayer != null) {
this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill());
} else {
this.skillLevel = 0;
}
if (player != null)
isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
else
isLucky = false;
this.resultModifier = 1.0D;
this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType);
}
public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap) {
if (hasCap)
this.probabilityCap = RandomChanceUtil.getMaximumProbability(subSkillType);
else
this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR;
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
if (player != null && mcMMOPlayer != null) {
this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill());
} else {
this.skillLevel = 0;
}
if (player != null)
isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
else
isLucky = false;
this.resultModifier = 1.0D;
this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType);
}
public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap, boolean luckyOverride) {
if (hasCap)
this.probabilityCap = RandomChanceUtil.getMaximumProbability(subSkillType);
else
this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR;
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
if (player != null && mcMMOPlayer != null) {
this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill());
} else {
this.skillLevel = 0;
}
isLucky = luckyOverride;
this.resultModifier = 1.0D;
this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType);
}
public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap, double resultModifier) {
if (hasCap)
this.probabilityCap = RandomChanceUtil.getMaximumProbability(subSkillType);
else
this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR;
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
if (player != null && mcMMOPlayer != null) {
this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill());
} else {
this.skillLevel = 0;
}
if (player != null)
isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
else
isLucky = false;
this.resultModifier = resultModifier;
this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType);
}
/**
* Gets the skill level of the player who owns this RandomChanceSkill
*
* @return the current skill level relating to this RandomChanceSkill
*/
public int getSkillLevel() {
return skillLevel;
}
/**
* Modify the skill level used for this skill's RNG calculations
*
* @param newSkillLevel new skill level
*/
public void setSkillLevel(int newSkillLevel) {
skillLevel = newSkillLevel;
}
/**
* The maximum bonus level for this skill
* This is when the skills level no longer increases the odds of success
* For example, a value of 25 will mean the success chance no longer grows after skill level 25
*
* @return the maximum bonus from skill level for this skill
*/
public double getMaximumBonusLevelCap() {
return maximumBonusLevelCap;
}
/**
* Gets the XPos used in the formula for success
*
* @return value of x for our success probability graph
*/
@Override
public double getXPos() {
return getSkillLevel();
}
/**
* The maximum odds for this RandomChanceExecution
* For example, if this value is 10, then 10% odds would be the maximum and would be achieved only when xPos equaled the LinearCurvePeak
*
* @return maximum probability odds from 0.00 (no chance of ever happened) to 100.0 (probability can be guaranteed)
*/
@Override
public double getProbabilityCap() {
return probabilityCap;
}
public boolean isLucky() {
return isLucky;
}
public double getResultModifier() {
return resultModifier;
}
}

View File

@ -1,61 +0,0 @@
package com.gmail.nossr50.util.random;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class RandomChanceSkillStatic extends RandomChanceSkill {
private final double xPos;
public RandomChanceSkillStatic(double xPos, @Nullable Player player, @NotNull SubSkillType subSkillType) {
super(player, subSkillType);
this.xPos = xPos;
}
public RandomChanceSkillStatic(double xPos, @Nullable Player player, @NotNull SubSkillType subSkillType, boolean luckyOverride) {
super(player, subSkillType, false, luckyOverride);
this.xPos = xPos;
}
public RandomChanceSkillStatic(double xPos, @Nullable Player player, @NotNull SubSkillType subSkillType, double resultModifier) {
super(player, subSkillType, resultModifier);
this.xPos = xPos;
}
/**
* Gets the XPos used in the formula for success
*
* @return value of x for our success probability graph
*/
@Override
public double getXPos() {
return xPos;
}
/**
* The maximum odds for this RandomChanceExecution
* For example, if this value is 10, then 10% odds would be the maximum and would be achieved only when xPos equaled the LinearCurvePeak
*
* @return maximum probability odds from 0.00 (no chance of ever happened) to 100.0 (probability can be guaranteed)
*/
@Override
public double getProbabilityCap() {
return probabilityCap;
}
/**
* The maximum bonus level for this skill
* This is when the skills level no longer increases the odds of success
* For example, a value of 25 will mean the success chance no longer grows after skill level 25
*
* @return the maximum bonus from skill level for this skill
*/
@Override
public double getMaximumBonusLevelCap() {
return 100;
}
}

View File

@ -1,38 +0,0 @@
package com.gmail.nossr50.util.random;
public class RandomChanceStatic implements RandomChanceExecution {
private final double xPos;
private final double probabilityCap;
private final boolean isLucky;
public RandomChanceStatic(double xPos, boolean isLucky) {
this.xPos = xPos;
this.probabilityCap = xPos;
this.isLucky = isLucky;
}
/**
* Gets the XPos used in the formula for success
*
* @return value of x for our success probability graph
*/
@Override
public double getXPos() {
return xPos;
}
/**
* The maximum odds for this RandomChanceExecution
* For example, if this value is 10, then 10% odds would be the maximum and would be achieved only when xPos equaled the LinearCurvePeak
*
* @return maximum probability odds from 0.00 (no chance of ever happened) to 100.0 (probability can be guaranteed)
*/
@Override
public double getProbabilityCap() {
return probabilityCap;
}
public boolean isLucky() {
return isLucky;
}
}

View File

@ -1,325 +1,78 @@
package com.gmail.nossr50.util.random; package com.gmail.nossr50.util.random;
import com.gmail.nossr50.config.AdvancedConfig;
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.events.skills.secondaryabilities.SubSkillEvent; import com.gmail.nossr50.util.skills.SkillUtils;
import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillRandomCheckEvent;
import com.gmail.nossr50.util.EventUtils;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.skills.SkillActivationType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
//TODO: Normalize chance values
//TODO: Test the 2 types of SkillProbabilityTypes
//TODO: Update calls to this class and its members
public class RandomChanceUtil { public class RandomChanceUtil {
public static final @NotNull DecimalFormat percent = new DecimalFormat("##0.00%"); public static final @NotNull DecimalFormat percent = new DecimalFormat("##0.00%");
//public static final DecimalFormat decimal = new DecimalFormat("##0.00");
public static final double LINEAR_CURVE_VAR = 100.0D;
public static final double LUCKY_MODIFIER = 1.333D; public static final double LUCKY_MODIFIER = 1.333D;
/** /**
* This method is the final step in determining if a Sub-Skill / Secondary Skill in mcMMO successfully activates either from chance or otherwise * Simulate an outcome on a probability and return true or false for the result of that outcome
* Random skills check for success based on numbers and then fire a cancellable event, if that event is not cancelled they succeed
* non-RNG skills just fire the cancellable event and succeed if they go uncancelled
* *
* @param skillActivationType this value represents what kind of activation procedures this sub-skill uses * @param probability target probability
* @param subSkillType The identifier for this specific sub-skill * @return true if the probability succeeded, false if it failed
* @param player The owner of this sub-skill
* @return returns true if all conditions are met and the event is not cancelled
*/ */
public static boolean isActivationSuccessful(@NotNull SkillActivationType skillActivationType, @NotNull SubSkillType subSkillType, @Nullable Player player) { public static boolean processProbability(@NotNull Probability probability) {
switch (skillActivationType) { return isSuccessfulRoll(probability.getValue());
case RANDOM_LINEAR_100_SCALE_WITH_CAP:
return checkRandomChanceExecutionSuccess(player, subSkillType, true);
case RANDOM_STATIC_CHANCE:
return checkRandomStaticChanceExecutionSuccess(player, subSkillType);
case ALWAYS_FIRES:
SubSkillEvent event = EventUtils.callSubSkillEvent(player, subSkillType);
return !event.isCancelled();
default:
return false;
}
}
public static double getActivationChance(@NotNull SkillActivationType skillActivationType, @NotNull SubSkillType subSkillType, @Nullable Player player, boolean luckyOverride) {
switch (skillActivationType) {
case RANDOM_LINEAR_100_SCALE_WITH_CAP:
return getRandomChanceExecutionSuccess(player, subSkillType, true, luckyOverride);
case RANDOM_STATIC_CHANCE:
return getRandomStaticChanceExecutionSuccess(player, subSkillType, luckyOverride);
default:
return 0.1337;
}
} }
/** /**
* Checks whether or not the random chance succeeds * Modify and then Simulate an outcome on a probability and return true or false for the result of that outcome
* *
* @return true if the random chance succeeds * @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 checkRandomChanceExecutionSuccess(@NotNull Player player, @NotNull PrimarySkillType primarySkillType, double chance) { public static boolean processProbability(@NotNull Probability probability, double probabilityMultiplier) {
//Check the odds double probabilityValue = probability.getValue() * probabilityMultiplier;
chance *= 100; return isSuccessfulRoll(probabilityValue);
chance = addLuck(player, primarySkillType, chance);
/*
* Stuff like treasures can specify a drop chance from 0.05 to 100
* Because of that we need to use a large int bound and multiply the chance by 100
*/
return rollDice(chance, 10000);
}
public static boolean rollDice(double chanceOfSuccess, int bound) {
return rollDice(chanceOfSuccess, bound, 1.0F);
}
public static boolean rollDice(double chanceOfSuccess, int bound, double resultModifier) {
return chanceOfSuccess > (ThreadLocalRandom.current().nextInt(bound) * resultModifier);
} }
/** /**
* Used for stuff like Excavation, Fishing, etc... * Simulates a "roll of the dice"
* If the value passed is higher than the "random" value, than it is a successful roll
* *
* @param randomChance * @param probabilityValue probability value
* @return * @return true for succeeding, false for failing
*/ */
public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSkillStatic randomChance, double resultModifier) { private static boolean isSuccessfulRoll(double probabilityValue) {
double chanceOfSuccess = calculateChanceOfSuccess(randomChance); return probabilityValue >= ThreadLocalRandom.current().nextDouble(1.0D);
//Check the odds
return rollDice(chanceOfSuccess, 100, resultModifier);
} }
/** /**
* Used for stuff like Excavation, Fishing, etc... * Return a chance of success in "percentage" format, show to the player in UI elements
* *
* @param randomChance * @param player target player
* @return * @param subSkillType target subskill
*/ * @param isLucky whether or not to apply luck modifiers
public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSkillStatic randomChance) {
return checkRandomChanceExecutionSuccess(randomChance, 1.0F);
}
public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSkill randomChance) {
double chanceOfSuccess = calculateChanceOfSuccess(randomChance);
//Check the odds
return rollDice(chanceOfSuccess, 100);
}
/**
* Gets the Static Chance for something to activate
* *
* @param randomChance * @return "percentage" representation of success
* @return
*/ */
public static double getRandomChanceExecutionChance(@NotNull RandomChanceExecution randomChance) { private static double chanceOfSuccessPercentage(@NotNull Player player, @NotNull SubSkillType subSkillType, boolean isLucky) {
return getChanceOfSuccess(randomChance.getXPos(), randomChance.getProbabilityCap(), LINEAR_CURVE_VAR);
}
public static double getRandomChanceExecutionChance(@NotNull RandomChanceExecution randomChance, boolean luckyOverride) {
return getChanceOfSuccess(randomChance.getXPos(), randomChance.getProbabilityCap(), LINEAR_CURVE_VAR);
}
public static double getRandomChanceExecutionChance(@NotNull RandomChanceStatic randomChance) {
double chanceOfSuccess = getChanceOfSuccess(randomChance.getXPos(), randomChance.getProbabilityCap(), LINEAR_CURVE_VAR);
chanceOfSuccess = addLuck(randomChance.isLucky(), chanceOfSuccess);
return chanceOfSuccess;
}
public static double calculateChanceOfSuccess(@NotNull RandomChanceSkill randomChance) {
double skillLevel = randomChance.getSkillLevel();
double maximumProbability = randomChance.getProbabilityCap();
double maximumBonusLevel = randomChance.getMaximumBonusLevelCap();
double chanceOfSuccess;
if (skillLevel >= maximumBonusLevel) {
//Chance of success is equal to the maximum probability if the maximum bonus level has been reached
chanceOfSuccess = maximumProbability;
} else {
//Get chance of success
chanceOfSuccess = getChanceOfSuccess(randomChance.getXPos(), maximumProbability, maximumBonusLevel);
}
//Add Luck
chanceOfSuccess = addLuck(randomChance.isLucky(), chanceOfSuccess);
return chanceOfSuccess;
}
public static double calculateChanceOfSuccess(@NotNull RandomChanceSkillStatic randomChance) {
double chanceOfSuccess = getChanceOfSuccess(randomChance.getXPos(), 100, 100);
//Add Luck
chanceOfSuccess = addLuck(randomChance.isLucky(), chanceOfSuccess);
return chanceOfSuccess;
}
/**
* The formula for RNG success is determined like this
* maximum probability * ( x / maxlevel )
*
* @return the chance of success from 0-100 (100 = guaranteed)
*/
private static int getChanceOfSuccess(double skillLevel, double maxProbability, double maxLevel) {
//return (int) (x / (y / LINEAR_CURVE_VAR));
return (int) (maxProbability * (skillLevel / maxLevel));
// max probability * (weight/maxlevel) = chance of success
}
private static int getChanceOfSuccess(double x, double y) {
return (int) (x / (y / LINEAR_CURVE_VAR));
// max probability * (weight/maxlevel) = chance of success
}
public static double getRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap) {
RandomChanceSkill rcs = new RandomChanceSkill(player, subSkillType, hasCap);
return calculateChanceOfSuccess(rcs);
}
public static double getRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap, boolean luckyOverride) {
RandomChanceSkill rcs = new RandomChanceSkill(player, subSkillType, hasCap, luckyOverride);
return calculateChanceOfSuccess(rcs);
}
public static double getRandomStaticChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean luckyOverride) {
try { try {
return getRandomChanceExecutionChance(new RandomChanceSkillStatic(getStaticRandomChance(subSkillType), player, subSkillType, luckyOverride)); 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() * 100;
//Apply lucky modifier
if(isLucky) {
percentageValue *= LUCKY_MODIFIER;
}
return percentageValue;
} catch (InvalidStaticChance invalidStaticChance) { } catch (InvalidStaticChance invalidStaticChance) {
//Catch invalid static skills
invalidStaticChance.printStackTrace(); invalidStaticChance.printStackTrace();
} return 0;
return 0.1337; //Puts on shades
}
public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap) {
return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, hasCap));
}
public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType) {
return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType));
}
public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap, double resultModifier) {
return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, hasCap, resultModifier));
}
public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, double resultModifier) {
return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, resultModifier));
}
public static boolean checkRandomStaticChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType) {
try {
return checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getStaticRandomChance(subSkillType), player, subSkillType));
} catch (InvalidStaticChance invalidStaticChance) {
//Catch invalid static skills
invalidStaticChance.printStackTrace();
}
return false;
}
/**
* Grabs static activation rolls for Secondary Abilities
*
* @param subSkillType The secondary ability to grab properties of
* @return The static activation roll involved in the RNG calculation
* @throws InvalidStaticChance if the skill has no defined static chance this exception will be thrown and you should know you're a naughty boy
*/
public static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance {
switch (subSkillType) {
case AXES_ARMOR_IMPACT:
return AdvancedConfig.getInstance().getImpactChance();
case AXES_GREATER_IMPACT:
return AdvancedConfig.getInstance().getGreaterImpactChance();
case TAMING_FAST_FOOD_SERVICE:
return AdvancedConfig.getInstance().getFastFoodChance();
default:
throw new InvalidStaticChance();
} }
} }
public static boolean sendSkillEvent(Player player, SubSkillType subSkillType, double activationChance) {
SubSkillRandomCheckEvent event = new SubSkillRandomCheckEvent(player, subSkillType, activationChance);
return !event.isCancelled();
}
public static String @NotNull [] calculateAbilityDisplayValues(@NotNull SkillActivationType skillActivationType, @NotNull Player player, @NotNull SubSkillType subSkillType) {
double successChance = getActivationChance(skillActivationType, subSkillType, player, false);
double successChanceLucky = getActivationChance(skillActivationType, subSkillType, player, true);
String[] displayValues = new String[2];
boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
displayValues[0] = percent.format(Math.min(successChance, 100.0D) / 100.0D);
displayValues[1] = isLucky ? percent.format(Math.min(successChanceLucky, 100.0D) / 100.0D) : null;
return displayValues;
}
public static String @NotNull [] calculateAbilityDisplayValuesStatic(@NotNull Player player, @NotNull PrimarySkillType primarySkillType, double chance) {
RandomChanceStatic rcs = new RandomChanceStatic(chance, false);
double successChance = getRandomChanceExecutionChance(rcs);
RandomChanceStatic rcs_lucky = new RandomChanceStatic(chance, true);
double successChance_lucky = getRandomChanceExecutionChance(rcs_lucky);
String[] displayValues = new String[2];
boolean isLucky = Permissions.lucky(player, primarySkillType);
displayValues[0] = percent.format(Math.min(successChance, 100.0D) / 100.0D);
displayValues[1] = isLucky ? percent.format(Math.min(successChance_lucky, 100.0D) / 100.0D) : null;
return displayValues;
}
public static String @NotNull [] calculateAbilityDisplayValuesCustom(@NotNull SkillActivationType skillActivationType, @NotNull Player player, @NotNull SubSkillType subSkillType, double multiplier) {
double successChance = getActivationChance(skillActivationType, subSkillType, player, false);
double successChanceLucky = getActivationChance(skillActivationType, subSkillType, player, true);
//TODO: Most likely incorrectly displays the value for graceful roll but gonna ignore for now...
successChance *= multiplier; //Currently only used for graceful roll
String[] displayValues = new String[2];
boolean isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
displayValues[0] = percent.format(Math.min(successChance, 100.0D) / 100.0D);
displayValues[1] = isLucky ? percent.format(Math.min(successChanceLucky, 100.0D) / 100.0D) : null;
return displayValues;
}
public static double addLuck(@NotNull Player player, @NotNull PrimarySkillType primarySkillType, double chance) {
if (Permissions.lucky(player, primarySkillType))
return chance * LUCKY_MODIFIER;
else
return chance;
}
public static double addLuck(boolean isLucky, double chance) {
if (isLucky)
return chance * LUCKY_MODIFIER;
else
return chance;
}
public static double getMaximumProbability(@NotNull SubSkillType subSkillType) {
return AdvancedConfig.getInstance().getMaximumProbability(subSkillType);
}
public static double getMaxBonusLevelCap(@NotNull SubSkillType subSkillType) {
return AdvancedConfig.getInstance().getMaxBonusLevel(subSkillType);
}
} }

View File

@ -0,0 +1,6 @@
package com.gmail.nossr50.util.random;
public enum SkillProbabilityType {
DYNAMIC_CONFIGURABLE, //Has multiple values used for calculation (taken from config files)
STATIC_CONFIGURABLE, //A single value used for calculations (taken from config files)
}

View File

@ -14,9 +14,11 @@ import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
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.compat.layers.persistentdata.AbstractPersistentDataLayer; import com.gmail.nossr50.util.compat.layers.persistentdata.AbstractPersistentDataLayer;
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;
@ -334,4 +336,92 @@ 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
*
* @param subSkillType target subskill
* @param player target player, can be null (null players are given odds equivalent to a player with no levels or luck)
* @return true if the Skill RNG succeeds, false if it fails
*/
public static boolean isSkillRNGSuccessful(@NotNull SubSkillType subSkillType, @Nullable Player player) {
try {
//Process probability
Probability probability = getSubSkillProbability(subSkillType, player);
//Player can be null
boolean isLucky = player != null && Permissions.lucky(player, subSkillType.getParentSkill());
if(isLucky) {
return RandomChanceUtil.processProbability(probability, RandomChanceUtil.LUCKY_MODIFIER);
} else {
return RandomChanceUtil.processProbability(probability);
}
} catch (RuntimeException | InvalidStaticChance e) {
e.printStackTrace();
}
return false;
}
/**
* 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 = ProbabilityFactory.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);
}
}
/**
* 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) throws InvalidStaticChance, RuntimeException {
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 ProbabilityFactory.ofSubSkill(player, subSkillType, skillProbabilityType);
}
} }

View File

@ -21,7 +21,7 @@
////TODO: Rewrite the entire com.gmail.nossr50.util.random package, it was written in haste and it disgusts me ////TODO: Rewrite the entire com.gmail.nossr50.util.random package, it was written in haste and it disgusts me
////TODO: Add more tests for the other types of random dice rolls ////TODO: Add more tests for the other types of random dice rolls
//@RunWith(PowerMockRunner.class) //@RunWith(PowerMockRunner.class)
//@PrepareForTest({RandomChanceUtil.class, UserManager.class}) //@PrepareForTest({RandomChanceUtil.class, UserManager.class, PrimarySkillType.class})
//public class RandomChanceTest { //public class RandomChanceTest {
// //
// private Player luckyPlayer; // private Player luckyPlayer;
@ -37,12 +37,12 @@
// //
// @Before // @Before
// public void setUpMock() { // public void setUpMock() {
// primarySkillType = PrimarySkillType.HERBALISM; // primarySkillType = PrimarySkillType.MINING;
// subSkillType = SubSkillType.HERBALISM_GREEN_THUMB; // subSkillType = SubSkillType.MINING_MOTHER_LODE;
// //
// //TODO: Likely needs to be changed per skill if more tests were added // //TODO: Likely needs to be changed per skill if more tests were added
// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaximumProbability", subSkillType.getClass())).toReturn(100D); // PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaximumProbability", subSkillType.getClass())).toReturn(10.0D);
// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaxBonusLevelCap", subSkillType.getClass())).toReturn(1000D); // PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaxBonusLevelCap", subSkillType.getClass())).toReturn(10000D);
// //
// normalPlayer = mock(Player.class); // normalPlayer = mock(Player.class);
// luckyPlayer = mock(Player.class); // luckyPlayer = mock(Player.class);
@ -62,39 +62,39 @@
// Mockito.when(Permissions.lucky(luckyPlayer, primarySkillType)).thenReturn(true); // Mockito.when(Permissions.lucky(luckyPlayer, primarySkillType)).thenReturn(true);
// Mockito.when(Permissions.lucky(normalPlayer, primarySkillType)).thenReturn(false); // Mockito.when(Permissions.lucky(normalPlayer, primarySkillType)).thenReturn(false);
// //
// Mockito.when(mmoPlayerNormal.getSkillLevel(primarySkillType)).thenReturn(800); // Mockito.when(mmoPlayerNormal.getSkillLevel(primarySkillType)).thenReturn(2150);
// Mockito.when(mmoPlayerLucky.getSkillLevel(primarySkillType)).thenReturn(800); // Mockito.when(mmoPlayerLucky.getSkillLevel(primarySkillType)).thenReturn(2150);
// } // }
// //
// @Test // @Test
// public void testLuckyChance() { // public void testLuckyChance() {
// System.out.println(testASCIIHeader); // System.out.println(testASCIIHeader);
// System.out.println("Testing success odds to fall within expected values..."); // System.out.println("Testing success odds to fall within expected values...");
// assertEquals(80D, getSuccessChance(mmoPlayerNormal),0D); // assertEquals(2.15D, getSuccessChance(mmoPlayerNormal),0.00D);
// assertEquals(80D * RandomChanceUtil.LUCKY_MODIFIER, getSuccessChance(mmoPlayerLucky),0D); // assertEquals(2.15D * RandomChanceUtil.LUCKY_MODIFIER, getSuccessChance(mmoPlayerLucky),0.00D);
// } // }
// //
// @Test //// @Test
// public void testNeverFailsSuccessLuckyPlayer() { //// public void testNeverFailsSuccessLuckyPlayer() {
// System.out.println(testASCIIHeader); //// System.out.println(testASCIIHeader);
// System.out.println("Test - Lucky Player with 80% base success should never fail (10,000 iterations)"); //// System.out.println("Test - Lucky Player with 80% base success should never fail (10,000 iterations)");
// for(int x = 0; x < 10000; x++) { //// for(int x = 0; x < 10000; x++) {
// Assert.assertTrue(RandomChanceUtil.checkRandomChanceExecutionSuccess(luckyPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true)); //// Assert.assertTrue(RandomChanceUtil.checkRandomChanceExecutionSuccess(luckyPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true));
// if(x == 10000-1) //// if(x == 10000-1)
// System.out.println("They never failed!"); //// System.out.println("They never failed!");
// } //// }
// } //// }
// //
// @Test // @Test
// public void testFailsAboutExpected() { // public void testFailsAboutExpected() {
// System.out.println(testASCIIHeader); // System.out.println(testASCIIHeader);
// System.out.println("Test - Player with 800 skill should fail about 20% of the time (100,000 iterations)"); // System.out.println("Test - Player with 800 skill should fail about 20% of the time (100,000 iterations)");
// double ratioDivisor = 1000; //1000 because we run the test 100,000 times // double ratioDivisor = 1000; //1000 because we run the test 100,000 times
// double expectedFailRate = 20D; // double expectedFailRate = 100.0D - 2.15D;
// //
// double win = 0, loss = 0; // double win = 0, loss = 0;
// for(int x = 0; x < 100000; x++) { // for(int x = 0; x < 100000; x++) {
// if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true)) { // if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer, SubSkillType.MINING_MOTHER_LODE, true)) {
// win++; // win++;
// } else { // } else {
// loss++; // loss++;
@ -102,7 +102,7 @@
// } // }
// //
// double lossRatio = (loss / ratioDivisor); // double lossRatio = (loss / ratioDivisor);
// Assert.assertEquals(lossRatio, expectedFailRate, 1D); // Assert.assertEquals(lossRatio, expectedFailRate, 0.01D);
// } // }
// //
// private double getSuccessChance(@NotNull McMMOPlayer mmoPlayer) { // private double getSuccessChance(@NotNull McMMOPlayer mmoPlayer) {