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.Stat' 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)

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.locale.LocaleLoader;
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.skills.SkillActivationType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
@ -31,7 +29,7 @@ public class AcrobaticsCommand extends SkillCommand {
protected void dataCalculations(Player player, float skillValue) {
// ACROBATICS_DODGE
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];
dodgeChanceLucky = dodgeStrings[1];
}
@ -61,18 +59,18 @@ public class AcrobaticsCommand extends SkillCommand {
double rollChance, graceChance;
//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
RandomChanceSkill grace_rcs = new RandomChanceSkill(player, SubSkillType.ACROBATICS_ROLL);
grace_rcs.setSkillLevel(grace_rcs.getSkillLevel() * 2); //Double Odds
SkillProbabilityWrapper grace_rcs = new SkillProbabilityWrapper(player, SubSkillType.ACROBATICS_ROLL);
grace_rcs.setxPos(grace_rcs.getxPos() * 2); //Double Odds
//Chance Stat Calculations
rollChance = RandomChanceUtil.getRandomChanceExecutionChance(roll_rcs);
graceChance = RandomChanceUtil.getRandomChanceExecutionChance(grace_rcs);
//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
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.util.Permissions;
import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
@ -33,14 +32,14 @@ public class ArcheryCommand extends SkillCommand {
protected void dataCalculations(Player player, float skillValue) {
// ARCHERY_ARROW_RETRIEVAL
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];
retrieveChanceLucky = retrieveStrings[1];
}
// ARCHERY_DAZE
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];
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.skills.CombatUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
@ -48,7 +47,7 @@ public class AxesCommand extends SkillCommand {
// CRITICAL HIT
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];
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.util.Permissions;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.Material;
@ -45,7 +44,7 @@ public class HerbalismCommand extends SkillCommand {
// DOUBLE DROPS
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];
doubleDropChanceLucky = doubleDropStrings[1];
}
@ -66,21 +65,21 @@ public class HerbalismCommand extends SkillCommand {
if (canGreenThumbBlocks || canGreenThumbPlants) {
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];
greenThumbChanceLucky = greenThumbStrings[1];
}
// HYLIAN LUCK
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];
hylianLuckChanceLucky = hylianLuckStrings[1];
}
// SHROOM THUMB
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];
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.player.UserManager;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
@ -32,7 +31,7 @@ public class MiningCommand extends SkillCommand {
private boolean canSuperBreaker;
private boolean canDoubleDrop;
private boolean canTripleDrop;
private boolean canMotherLode;
private boolean canBlast;
private boolean canBiggerBombs;
private boolean canDemoExpert;
@ -56,16 +55,15 @@ public class MiningCommand extends SkillCommand {
}
// Mastery TRIPLE DROPS
if (canTripleDrop) {
String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.MINING_MOTHER_LODE);
if (canMotherLode) {
String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillProbabilityType.DYNAMIC_CONFIGURABLE, player, SubSkillType.MINING_MOTHER_LODE);
tripleDropChance = masteryTripleDropStrings[0];
tripleDropChanceLucky = masteryTripleDropStrings[1];
}
// DOUBLE DROPS
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];
doubleDropChanceLucky = doubleDropStrings[1];
}
@ -84,7 +82,7 @@ public class MiningCommand extends SkillCommand {
canBlast = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_BLAST_MINING) && Permissions.remoteDetonation(player);
canDemoExpert = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_DEMOLITIONS_EXPERTISE) && Permissions.demolitionsExpertise(player);
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);
}
@ -113,7 +111,7 @@ public class MiningCommand extends SkillCommand {
//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)
+ (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.player.UserManager;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.Material;
@ -68,7 +67,7 @@ public class RepairCommand extends SkillCommand {
// SUPER REPAIR
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];
superRepairChanceLucky = superRepairStrings[1];
}

View File

@ -219,7 +219,7 @@ public abstract class SkillCommand implements TabExecutor {
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);
}

View File

@ -6,7 +6,6 @@ import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
@ -39,14 +38,14 @@ public class SmeltingCommand extends SkillCommand {
// FLUX MINING
/*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_fluxMiningChanceLucky = fluxMiningStrings[1];
}*/
// SECOND SMELT
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_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.skills.CombatUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
@ -37,7 +36,7 @@ public class SwordsCommand extends SkillCommand {
protected void dataCalculations(Player player, float skillValue) {
// SWORDS_COUNTER_ATTACK
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];
counterChanceLucky = counterStrings[1];
}
@ -46,7 +45,7 @@ public class SwordsCommand extends SkillCommand {
if (canBleed) {
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];
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.skills.taming.Taming;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.EntityType;
@ -35,7 +34,7 @@ public class TamingCommand extends SkillCommand {
@Override
protected void dataCalculations(Player player, float skillValue) {
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];
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.skills.CombatUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
@ -40,7 +39,7 @@ public class UnarmedCommand extends SkillCommand {
protected void dataCalculations(Player player, float skillValue) {
// UNARMED_ARROW_DEFLECT
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];
deflectChanceLucky = deflectStrings[1];
}
@ -54,7 +53,7 @@ public class UnarmedCommand extends SkillCommand {
// UNARMED_DISARM
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];
disarmChanceLucky = disarmStrings[1];
}
@ -66,7 +65,7 @@ public class UnarmedCommand extends SkillCommand {
// IRON GRIP
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];
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.util.Permissions;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
@ -43,7 +42,7 @@ public class WoodcuttingCommand extends SkillCommand {
//Clean Cuts
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];
tripleDropChanceLucky = tripleDropStrings[1];
}
@ -57,7 +56,7 @@ public class WoodcuttingCommand extends SkillCommand {
}
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];
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.player.NotificationManager;
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.SkillProbabilityType;
import com.gmail.nossr50.util.skills.PerksUtils;
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.SoundType;
@ -125,14 +124,14 @@ public class Roll extends AcrobaticsSubSkill {
float skillValue = playerProfile.getSkillLevel(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];
rollChanceLucky = rollStrings[1];
/*
* 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];
gracefulRollChanceLucky = gracefulRollStrings[1];
@ -199,7 +198,7 @@ public class Roll extends AcrobaticsSubSkill {
double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold());
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");
SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS);
//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) {
double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold() * 2);
RandomChanceSkill rcs = new RandomChanceSkill(player, subSkillType);
rcs.setSkillLevel(rcs.getSkillLevel() * 2); //Double the effective odds
SkillProbabilityWrapper rcs = new SkillProbabilityWrapper(player, subSkillType);
rcs.setxPos(rcs.getxPos() * 2); //Double the effective odds
if (!isFatal(player, modifiedDamage)
&& RandomChanceUtil.checkRandomChanceExecutionSuccess(rcs))
&& RandomChanceUtil.processProbabilityResults(rcs))
{
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Ability.Proc");
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;
//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;
rollHalfMaxSkill.setSkillLevel(halfMaxSkillValue);
rollHalfMaxSkill.setxPos(halfMaxSkillValue);
//Chance to graceful roll at full skill
RandomChanceSkill rollGraceHalfMaxSkill = new RandomChanceSkill(null, subSkillType);
rollGraceHalfMaxSkill.setSkillLevel(halfMaxSkillValue * 2); //Double the effective odds
SkillProbabilityWrapper rollGraceHalfMaxSkill = new SkillProbabilityWrapper(null, subSkillType);
rollGraceHalfMaxSkill.setxPos(halfMaxSkillValue * 2); //Double the effective odds
//Chance to roll per level
RandomChanceSkill rollOneSkillLevel = new RandomChanceSkill(null, subSkillType);
rollGraceHalfMaxSkill.setSkillLevel(1); //Level 1 skill
SkillProbabilityWrapper rollOneSkillLevel = new SkillProbabilityWrapper(null, subSkillType);
rollGraceHalfMaxSkill.setxPos(1); //Level 1 skill
//Chance Stat Calculations
rollChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollHalfMaxSkill);
@ -408,10 +407,10 @@ public class Roll extends AcrobaticsSubSkill {
{
double playerChanceRoll, playerChanceGrace;
RandomChanceSkill roll = new RandomChanceSkill(player, getSubSkillType());
RandomChanceSkill graceful = new RandomChanceSkill(player, getSubSkillType());
SkillProbabilityWrapper roll = new SkillProbabilityWrapper(player, getSubSkillType());
SkillProbabilityWrapper graceful = new SkillProbabilityWrapper(player, getSubSkillType());
graceful.setSkillLevel(graceful.getSkillLevel() * 2); //Double odds
graceful.setxPos(graceful.getxPos() * 2); //Double odds
//Calculate
playerChanceRoll = RandomChanceUtil.getRandomChanceExecutionChance(roll);

View File

@ -1,26 +1,37 @@
package com.gmail.nossr50.datatypes.treasure;
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.jetbrains.annotations.NotNull;
public abstract class Treasure {
private int xp;
private double dropChance;
private @NotNull Probability dropProbability;
private int dropLevel;
private ItemStack drop;
private @NotNull ItemStack drop;
public Treasure(ItemStack drop, int xp, double dropChance, int dropLevel) {
this.drop = drop;
this.xp = xp;
this.dropChance = dropChance;
this.dropProbability = new ProbabilityImpl(ProbabilityFactory.probabilityFromPercent(dropChance));
this.dropLevel = dropLevel;
}
public ItemStack getDrop() {
public @NotNull Probability getDropProbability() {
return dropProbability;
}
public @NotNull ItemStack getDrop() {
return drop;
}
public void setDrop(ItemStack drop) {
public void setDrop(@NotNull ItemStack drop) {
this.drop = drop;
}
@ -36,8 +47,9 @@ public abstract class Treasure {
return dropChance;
}
public void setDropChance(Double dropChance) {
public void setDropChance(double dropChance) {
this.dropChance = dropChance;
this.dropProbability = new ProbabilityImpl(ProbabilityFactory.probabilityFromPercent(dropChance));
}
public int getDropLevel() {
@ -51,4 +63,28 @@ public abstract class Treasure {
public void setDropLevel(int 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.player.NotificationManager;
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.SkillActivationType;
import com.gmail.nossr50.util.skills.SkillUtils;
import com.gmail.nossr50.worldguard.WorldGuardManager;
import com.gmail.nossr50.worldguard.WorldGuardUtils;
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);
}
}

View File

@ -12,10 +12,8 @@ import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.Permissions;
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.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
@ -88,7 +86,7 @@ public class AcrobaticsManager extends SkillManager {
double modifiedDamage = Acrobatics.calculateModifiedDodgeDamage(damage, Acrobatics.dodgeDamageModifier);
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);
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.Permissions;
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.SkillActivationType;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
@ -88,7 +88,7 @@ public class ArcheryManager extends SkillManager {
* @param defender The {@link Player} being affected by the ability
*/
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;
}
@ -116,7 +116,7 @@ public class ArcheryManager extends SkillManager {
* @param oldDamage The raw damage value of this arrow before we modify it
*/
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;
}

View File

@ -11,7 +11,7 @@ import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.ItemUtils;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.random.RandomChanceUtil;
import com.gmail.nossr50.util.random.SkillProbabilityType;
import com.gmail.nossr50.util.skills.*;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@ -69,7 +69,7 @@ public class AxesManager extends SkillManager {
* Handle the effects of the Axe Mastery ability
*/
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;
}
@ -83,7 +83,7 @@ public class AxesManager extends SkillManager {
* @param damage The amount of damage initially dealt by the event
*/
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;
}
@ -119,7 +119,7 @@ public class AxesManager extends SkillManager {
for (ItemStack armor : target.getEquipment().getArmorContents()) {
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);
}
}
@ -137,7 +137,7 @@ public class AxesManager extends SkillManager {
*/
public double greaterImpact(@NotNull LivingEntity target) {
//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;
}

View File

@ -41,7 +41,7 @@ public class ExcavationManager extends SkillManager {
for (ExcavationTreasure treasure : treasures) {
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
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.compat.layers.skills.MasterAnglerCompatibilityLayer;
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.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
@ -63,11 +61,14 @@ public class FishingManager extends SkillManager {
}
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() {
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()
@ -477,8 +478,8 @@ public class FishingManager extends SkillManager {
*
* @param target The {@link LivingEntity} affected by the ability
*/
public void shakeCheck(LivingEntity target) {
if (RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getShakeChance(), getPlayer(), SubSkillType.FISHING_SHAKE))) {
public void shakeCheck(@NotNull LivingEntity target) {
if (SkillUtils.isStaticSkillRNGSuccessful(PrimarySkillType.FISHING, getPlayer(), getShakeChance())) {
List<ShakeTreasure> possibleDrops = Fishing.findPossibleDrops(target);
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.util.*;
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.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.SoundType;
@ -589,7 +587,7 @@ public class HerbalismManager extends SkillManager {
* @return true if the ability was successful, false otherwise
*/
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");
return false;
}
@ -604,7 +602,7 @@ public class HerbalismManager extends SkillManager {
* @return true if the ability was successful, false otherwise
*/
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;
}
@ -623,7 +621,7 @@ public class HerbalismManager extends SkillManager {
for (HylianTreasure treasure : treasures) {
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)) {
return false;
}
@ -660,7 +658,7 @@ public class HerbalismManager extends SkillManager {
playerInventory.removeItem(new ItemStack(Material.RED_MUSHROOM));
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");
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.Permissions;
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.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.SoundType;
@ -291,7 +289,7 @@ public class RepairManager extends SkillManager {
if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.REPAIR_SUPER_REPAIR))
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");
return true;
}
@ -342,10 +340,10 @@ public class RepairManager extends SkillManager {
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
&& (!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);
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.Permissions;
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.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
@ -123,7 +122,7 @@ public class SalvageManager extends SkillManager {
for(int x = 0; x < potentialSalvageYield-1; x++) {
if(RandomChanceUtil.rollDice(chanceOfSuccess, 100)) {
if(RandomChanceUtil.rollDiceSimple(chanceOfSuccess, 100)) {
chanceOfSuccess-=3;
chanceOfSuccess = Math.max(chanceOfSuccess, 90);
@ -253,12 +252,12 @@ public class SalvageManager extends SkillManager {
if (!Salvage.arcaneSalvageEnchantLoss
|| 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);
}
else if (enchantLevel > 1
&& 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);
downgraded = true;
} 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.skills.SkillManager;
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.SkillActivationType;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.bukkit.event.inventory.FurnaceBurnEvent;
import org.bukkit.inventory.ItemStack;
@ -28,7 +27,7 @@ public class SmeltingManager extends SkillManager {
public boolean isSecondSmeltSuccessful() {
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.Permissions;
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.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@ -62,7 +61,7 @@ public class SwordsManager extends SkillManager {
*/
public void ruptureCheck(@NotNull LivingEntity target) throws IllegalStateException {
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) {
Player defender = (Player) target;
@ -129,7 +128,7 @@ public class SwordsManager extends SkillManager {
* @param damage The amount of damage initially dealt by the event
*/
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());
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.compat.layers.persistentdata.MobMetaFlagType;
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.ParticleEffectUtils;
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.SoundType;
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
*/
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;
}
@ -168,7 +167,7 @@ public class TamingManager extends SkillManager {
*/
public double gore(@NotNull LivingEntity target, double damage) {
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;
}
@ -276,7 +275,7 @@ public class TamingManager extends SkillManager {
if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL))
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;
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.player.NotificationManager;
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.SkillActivationType;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Item;
@ -72,7 +72,7 @@ public class UnarmedManager extends SkillManager {
}
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;
}
@ -103,7 +103,7 @@ public class UnarmedManager extends SkillManager {
* @param defender The defending player
*/
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()) {
return;
}
@ -126,7 +126,7 @@ public class UnarmedManager extends SkillManager {
* Check for arrow deflection.
*/
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");
return true;
}
@ -149,7 +149,7 @@ public class UnarmedManager extends SkillManager {
* Handle the effects of the Iron Arm ability
*/
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;
}
@ -183,7 +183,7 @@ public class UnarmedManager extends SkillManager {
private boolean hasIronGrip(@NotNull Player defender) {
if (!Misc.isNPCEntityExcludingVillagers(defender)
&& 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(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.skills.CombatUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@ -70,11 +69,11 @@ public class WoodcuttingManager extends SkillManager {
}
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() {
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(AdvancedConfig.getInstance().isKnockOnWoodXPOrbEnabled()) {
if(RandomChanceUtil.rollDice(10, 100)) {
if(RandomChanceUtil.rollDiceSimple(10, 100)) {
int randOrbCount = Math.max(1, Misc.getRandom().nextInt(100));
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.skills.repair.Repair;
import com.gmail.nossr50.skills.salvage.Salvage;
import com.gmail.nossr50.util.random.RandomChanceSkill;
import com.gmail.nossr50.util.random.RandomChanceUtil;
import org.bukkit.Material;
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) {
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;

View File

@ -344,4 +344,26 @@ public final class Misc {
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;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillEvent;
import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillRandomCheckEvent;
import com.gmail.nossr50.util.EventUtils;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat;
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 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;
/**
* This method is the final step in determining if a Sub-Skill / Secondary Skill in mcMMO successfully activates either from chance or otherwise
* 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
* Simulate an outcome on a probability and return true or false for the result of that outcome
*
* @param skillActivationType this value represents what kind of activation procedures this sub-skill uses
* @param subSkillType The identifier for this specific sub-skill
* @param player The owner of this sub-skill
* @return returns true if all conditions are met and the event is not cancelled
* @param probability target probability
* @return true if the probability succeeded, false if it failed
*/
public static boolean isActivationSuccessful(@NotNull SkillActivationType skillActivationType, @NotNull SubSkillType subSkillType, @Nullable Player player) {
switch (skillActivationType) {
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;
}
public static boolean processProbability(@NotNull Probability probability) {
return isSuccessfulRoll(probability.getValue());
}
/**
* 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) {
//Check the odds
chance *= 100;
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);
public static boolean processProbability(@NotNull Probability probability, double probabilityMultiplier) {
double probabilityValue = probability.getValue() * probabilityMultiplier;
return isSuccessfulRoll(probabilityValue);
}
/**
* 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
* @return
* @param probabilityValue probability value
* @return true for succeeding, false for failing
*/
public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSkillStatic randomChance, double resultModifier) {
double chanceOfSuccess = calculateChanceOfSuccess(randomChance);
//Check the odds
return rollDice(chanceOfSuccess, 100, resultModifier);
private static boolean isSuccessfulRoll(double probabilityValue) {
return probabilityValue >= ThreadLocalRandom.current().nextDouble(1.0D);
}
/**
* Used for stuff like Excavation, Fishing, etc...
* Return a chance of success in "percentage" format, show to the player in UI elements
*
* @param randomChance
* @return
*/
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 player target player
* @param subSkillType target subskill
* @param isLucky whether or not to apply luck modifiers
*
* @param randomChance
* @return
* @return "percentage" representation of success
*/
public static double getRandomChanceExecutionChance(@NotNull RandomChanceExecution randomChance) {
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) {
private static double chanceOfSuccessPercentage(@NotNull Player player, @NotNull SubSkillType subSkillType, boolean isLucky) {
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 invalid static skills
invalidStaticChance.printStackTrace();
}
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();
return 0;
}
}
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.util.ItemUtils;
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.player.NotificationManager;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.random.*;
import com.gmail.nossr50.util.text.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -334,4 +336,92 @@ public final class SkillUtils {
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: Add more tests for the other types of random dice rolls
//@RunWith(PowerMockRunner.class)
//@PrepareForTest({RandomChanceUtil.class, UserManager.class})
//@PrepareForTest({RandomChanceUtil.class, UserManager.class, PrimarySkillType.class})
//public class RandomChanceTest {
//
// private Player luckyPlayer;
@ -37,12 +37,12 @@
//
// @Before
// public void setUpMock() {
// primarySkillType = PrimarySkillType.HERBALISM;
// subSkillType = SubSkillType.HERBALISM_GREEN_THUMB;
// primarySkillType = PrimarySkillType.MINING;
// subSkillType = SubSkillType.MINING_MOTHER_LODE;
//
// //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, "getMaxBonusLevelCap", subSkillType.getClass())).toReturn(1000D);
// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaximumProbability", subSkillType.getClass())).toReturn(10.0D);
// PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaxBonusLevelCap", subSkillType.getClass())).toReturn(10000D);
//
// normalPlayer = mock(Player.class);
// luckyPlayer = mock(Player.class);
@ -62,39 +62,39 @@
// Mockito.when(Permissions.lucky(luckyPlayer, primarySkillType)).thenReturn(true);
// Mockito.when(Permissions.lucky(normalPlayer, primarySkillType)).thenReturn(false);
//
// Mockito.when(mmoPlayerNormal.getSkillLevel(primarySkillType)).thenReturn(800);
// Mockito.when(mmoPlayerLucky.getSkillLevel(primarySkillType)).thenReturn(800);
// Mockito.when(mmoPlayerNormal.getSkillLevel(primarySkillType)).thenReturn(2150);
// Mockito.when(mmoPlayerLucky.getSkillLevel(primarySkillType)).thenReturn(2150);
// }
//
// @Test
// public void testLuckyChance() {
// System.out.println(testASCIIHeader);
// System.out.println("Testing success odds to fall within expected values...");
// assertEquals(80D, getSuccessChance(mmoPlayerNormal),0D);
// assertEquals(80D * RandomChanceUtil.LUCKY_MODIFIER, getSuccessChance(mmoPlayerLucky),0D);
// assertEquals(2.15D, getSuccessChance(mmoPlayerNormal),0.00D);
// assertEquals(2.15D * RandomChanceUtil.LUCKY_MODIFIER, getSuccessChance(mmoPlayerLucky),0.00D);
// }
//
// @Test
// public void testNeverFailsSuccessLuckyPlayer() {
// System.out.println(testASCIIHeader);
// System.out.println("Test - Lucky Player with 80% base success should never fail (10,000 iterations)");
// for(int x = 0; x < 10000; x++) {
// Assert.assertTrue(RandomChanceUtil.checkRandomChanceExecutionSuccess(luckyPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true));
// if(x == 10000-1)
// System.out.println("They never failed!");
// }
// }
//// @Test
//// public void testNeverFailsSuccessLuckyPlayer() {
//// System.out.println(testASCIIHeader);
//// System.out.println("Test - Lucky Player with 80% base success should never fail (10,000 iterations)");
//// for(int x = 0; x < 10000; x++) {
//// Assert.assertTrue(RandomChanceUtil.checkRandomChanceExecutionSuccess(luckyPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true));
//// if(x == 10000-1)
//// System.out.println("They never failed!");
//// }
//// }
//
// @Test
// public void testFailsAboutExpected() {
// System.out.println(testASCIIHeader);
// 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 expectedFailRate = 20D;
// double expectedFailRate = 100.0D - 2.15D;
//
// double win = 0, loss = 0;
// 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++;
// } else {
// loss++;
@ -102,7 +102,7 @@
// }
//
// double lossRatio = (loss / ratioDivisor);
// Assert.assertEquals(lossRatio, expectedFailRate, 1D);
// Assert.assertEquals(lossRatio, expectedFailRate, 0.01D);
// }
//
// private double getSuccessChance(@NotNull McMMOPlayer mmoPlayer) {