Endgame Update (#4840)

General
Added Crossbows Skill, this skill is a WIP and feedback on discord is appreciated.
Added Tridents Skill, this skill is a WIP and feedback on discord is appreciated.
Added the "endgame" triple drop subskill 'Mother Lode' to Mining
Added the "endgame" triple drop subskill 'Clean Cuts' to Woodcutting
Added the "endgame" triple drop subskill 'Verdant Bounty' to Herbalism
Added /mmopower command which simply shows your power level (aliases /mmopowerlevel /powerlevel)

Config
Added 'Send_To_Console' settings to chat.yml to toggle sending party or admin chat messages to console.
Replaced 'Experience_Formula.Modifier' in experience.yml with 'Experience_Formula.Skill_Multiplier' which is easier to understand and less prone to divide by zero bugs.
child.yml config is gone now, feel free to delete it.

Tweaks
Tree Feller now drops 90% less non-wood block rewards (leaves/etc) on average from Knock on Wood.
Treasure drop rate from Shake, Fishing, Hylian, and Excavation now benefit from the Luck perk.
Updated advanced.yml with entries for the new skills

Permission nodes
Added 'mcmmo.commands.mmopower' permission node for the new /mmopower command
Added 'mcmmo.commands.crossbows' permission node
Added 'mcmmo.ability.crossbows.crossbowslimitbreak' permission node
Added 'mcmmo.ability.crossbows.trickshot' permission node
Added 'mcmmo.ability.herbalism.verdantbounty' permission node
Added 'mcmmo.ability.mining.motherlode' permission node
Added 'mcmmo.ability.woodcutting.cleancuts' permission node

Locale
Added locale entries for motherlode, cleancuts, and verdant bounty.

Codebase
Major rewrite for how random chance was handled in the code.
Many skills with RNG elements now send out a SubSkillEvent (which can be used to modify probability or cancel the results), some skills without RNG still send out this event when activated, this event is cancellable so it can be used to make a skill fail.
A lot of new unit tests were added to help keep mcMMO stable as part of this update, of course, more could always be added.

NOTES:
One feature of this update is to provide an endgame benefits to some skills that you can grind for a long time, ideally for a long while. I will likely expand upon this idea in future updates.
A few skills have these endgame-oriented subskills, these new subskills provide a small benefit at first that grows and scales up to level 10,000 (or 1,000 for Standard mode which no one uses) and does not have ranks (other than the initial rank to unlock it).
These endgame sub skills unlock at level 1000 for users with default mcMMO settings, or 100 for those using the optional Standard scaling.
You can tweak the benefits of these skills in advanced.yml, the default settings are meant to be a good starting point.

Crossbows and Tridents are WIP skills, I would like feedback on discord about them.

More info on the new Triple Drop skills (Mother Lode, Clean Cuts, Verdant Bounty):
Currently these start at about 5%  chance and can reach a maximum 50% chance if a player acquired 10,000 skill, you can adjust this in advanced.yml
These skills respect double drop settings from config.yml just like the corresponding Double Drop skills do, if a double drop is disabled for an item, then it's disabled for triple drops too.
I added a new Power Level Command, for now this just shows you your current power level. If I ever add features based on power level, this command will likely display output related to those features.

Regarding Maces, I will likely add that as a WIP skill when the next Minecraft update drops.
This commit is contained in:
Robert Alan Chapton
2024-03-30 06:09:59 -07:00
committed by GitHub
parent bead5feb14
commit 2594dc1bca
141 changed files with 3586 additions and 1991 deletions

View File

@@ -14,10 +14,9 @@ import com.gmail.nossr50.util.MetadataConstants;
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.random.ProbabilityUtil;
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;
@@ -94,7 +93,8 @@ 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)
&& ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ACROBATICS_DODGE, player)) {
ParticleEffectUtils.playDodgeEffect(player);
if (mmoPlayer.useChatNotifications()) {

View File

@@ -10,9 +10,8 @@ import com.gmail.nossr50.util.MetadataConstants;
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.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
@@ -53,7 +52,7 @@ public class ArcheryManager extends SkillManager {
* @param target The {@link LivingEntity} damaged by the arrow
* @param arrow The {@link Entity} who shot the arrow
*/
public double distanceXpBonusMultiplier(LivingEntity target, Entity arrow) {
public static double distanceXpBonusMultiplier(LivingEntity target, Entity arrow) {
//Hacky Fix - some plugins spawn arrows and assign them to players after the ProjectileLaunchEvent fires
if(!arrow.hasMetadata(MetadataConstants.METADATA_KEY_ARROW_DISTANCE))
return 1;
@@ -89,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 (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.ARCHERY_DAZE, getPlayer())) {
return 0;
}
@@ -118,10 +117,10 @@ public class ArcheryManager extends SkillManager {
* @param oldDamage The raw damage value of this arrow before we modify it
*/
public double skillShot(double oldDamage) {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) {
if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.ARCHERY_SKILL_SHOT, getPlayer())) {
return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage);
} else {
return oldDamage;
}
return Archery.getSkillShotBonusDamage(getPlayer(), oldDamage);
}
}

View File

@@ -11,8 +11,11 @@ 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.*;
import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.ParticleEffectUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@@ -66,11 +69,11 @@ 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())) {
return 0;
if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.AXES_AXE_MASTERY, getPlayer())) {
return Axes.getAxeMasteryBonusDamage(getPlayer());
}
return Axes.getAxeMasteryBonusDamage(getPlayer());
return 0;
}
/**
@@ -80,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 (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) {
return 0;
}
@@ -115,7 +118,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 (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) {
SkillUtils.handleArmorDurabilityChange(armor, durabilityDamage, 1);
}
}
@@ -133,7 +136,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 (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_GREATER_IMPACT, getPlayer())) {
return 0;
}

View File

@@ -1,64 +0,0 @@
package com.gmail.nossr50.skills.child;
import com.gmail.nossr50.config.BukkitConfig;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.LogUtils;
import com.gmail.nossr50.util.text.StringUtils;
import org.bukkit.configuration.file.YamlConfiguration;
import java.util.EnumSet;
import java.util.Locale;
public class ChildConfig extends BukkitConfig {
public ChildConfig() {
super("child.yml");
loadKeys();
}
@Override
protected void loadKeys() {
config.setDefaults(YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader("child.yml")));
FamilyTree.clearRegistrations(); // when reloading, need to clear statics
for (PrimarySkillType skill : mcMMO.p.getSkillTools().CHILD_SKILLS) {
LogUtils.debug(mcMMO.p.getLogger(), "Finding parents of " + skill.name());
EnumSet<PrimarySkillType> parentSkills = EnumSet.noneOf(PrimarySkillType.class);
boolean useDefaults = false; // If we had an error we back out and use defaults
for (String name : config.getStringList(StringUtils.getCapitalized(skill.name()))) {
try {
PrimarySkillType parentSkill = PrimarySkillType.valueOf(name.toUpperCase(Locale.ENGLISH));
FamilyTree.enforceNotChildSkill(parentSkill);
parentSkills.add(parentSkill);
}
catch (IllegalArgumentException ex) {
mcMMO.p.getLogger().warning(name + " is not a valid skill type, or is a child skill!");
useDefaults = true;
break;
}
}
if (useDefaults) {
parentSkills.clear();
for (String name : config.getDefaults().getStringList(StringUtils.getCapitalized(skill.name()))) {
/* We do less checks in here because it's from inside our jar.
* If they're dedicated enough to have modified it, they can have the errors it may produce.
* Alternatively, this can be used to allow child skills to be parent skills, provided there are no circular dependencies this is an advanced sort of configuration.
*/
parentSkills.add(PrimarySkillType.valueOf(name.toUpperCase(Locale.ENGLISH)));
}
}
// Register them
for (PrimarySkillType parentSkill : parentSkills) {
LogUtils.debug(mcMMO.p.getLogger(), "Registering " + parentSkill.name() + " as parent of " + skill.name());
FamilyTree.registerParent(skill, parentSkill);
}
}
FamilyTree.closeRegistration();
}
}

View File

@@ -1,54 +0,0 @@
package com.gmail.nossr50.skills.child;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.util.skills.SkillTools;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Set;
public class FamilyTree {
private static final HashMap<PrimarySkillType, Set<PrimarySkillType>> tree = new HashMap<>();
public static Set<PrimarySkillType> getParents(PrimarySkillType childSkill) {
enforceChildSkill(childSkill);
// We do not check if we have the child skill in question, as not having it would mean we did something wrong, and an NPE is desired.
return tree.get(childSkill);
}
protected static void registerParent(PrimarySkillType childSkill, PrimarySkillType parentSkill) {
enforceChildSkill(childSkill);
enforceNotChildSkill(parentSkill);
if (!tree.containsKey(childSkill)) {
tree.put(childSkill, EnumSet.noneOf(PrimarySkillType.class));
}
tree.get(childSkill).add(parentSkill);
}
protected static void closeRegistration() {
for (PrimarySkillType childSkill : tree.keySet()) {
Set<PrimarySkillType> immutableSet = Collections.unmodifiableSet(tree.get(childSkill));
tree.put(childSkill, immutableSet);
}
}
protected static void clearRegistrations() {
tree.clear();
}
protected static void enforceChildSkill(PrimarySkillType skill) {
if (!SkillTools.isChildSkill(skill)) {
throw new IllegalArgumentException(skill.name() + " is not a child skill!");
}
}
protected static void enforceNotChildSkill(PrimarySkillType skill) {
if (SkillTools.isChildSkill(skill)) {
throw new IllegalArgumentException(skill.name() + " is a child skill!");
}
}
}

View File

@@ -0,0 +1,41 @@
package com.gmail.nossr50.skills.crossbows;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.util.player.UserManager;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.plugin.Plugin;
import static com.gmail.nossr50.util.skills.ProjectileUtils.getNormal;
/**
* Util class for crossbows.
*/
public class Crossbows {
/**
* Process events that may happen from a crossbow hitting an entity.
*
* @param event the projectile hit event
* @param pluginRef the plugin ref
* @param arrow the arrow
*/
public static void processCrossbows(ProjectileHitEvent event, Plugin pluginRef, Arrow arrow) {
if (arrow.getShooter() instanceof Player) {
McMMOPlayer mmoPlayer = UserManager.getPlayer((Player) arrow.getShooter());
if (mmoPlayer == null)
return;
processTrickShot(event, pluginRef, arrow, mmoPlayer);
}
}
private static void processTrickShot(ProjectileHitEvent event, Plugin pluginRef, Arrow arrow, McMMOPlayer mmoPlayer) {
if(event.getHitBlock() != null && event.getHitBlockFace() != null) {
mmoPlayer.getCrossbowsManager().handleRicochet(
pluginRef,
arrow,
getNormal(event.getHitBlockFace()));
}
}
}

View File

@@ -0,0 +1,108 @@
package com.gmail.nossr50.skills.crossbows;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.MetadataConstants;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.ProjectileUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import org.bukkit.Location;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.Plugin;
import org.bukkit.projectiles.ProjectileSource;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import static com.gmail.nossr50.util.skills.CombatUtils.delayArrowMetaCleanup;
public class CrossbowsManager extends SkillManager {
public CrossbowsManager(McMMOPlayer mmoPlayer) {
super(mmoPlayer, PrimarySkillType.CROSSBOWS);
}
public void handleRicochet(@NotNull Plugin pluginRef, @NotNull Arrow arrow, @NotNull Vector hitBlockNormal) {
if(!arrow.isShotFromCrossbow())
return;
// Check player permission
if (!Permissions.trickShot(mmoPlayer.getPlayer())) {
return;
}
// TODO: Add an event for this for plugins to hook into
spawnReflectedArrow(pluginRef, arrow, arrow.getLocation(), hitBlockNormal);
}
private void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow,
@NotNull Location origin, @NotNull Vector normal) {
int bounceCount = 0;
if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT)) {
bounceCount = originalArrow.getMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT).get(0).asInt();
if (bounceCount >= getTrickShotMaxBounceCount()) {
return;
}
}
final ProjectileSource originalArrowShooter = originalArrow.getShooter();
final Vector arrowInBlockVector = originalArrow.getVelocity();
final Vector reflectedDirection = arrowInBlockVector.subtract(normal.multiply(2 * arrowInBlockVector.dot(normal)));
final Vector inverseNormal = normal.multiply(-1);
// check the angle of the arrow against the inverse normal to see if the angle was too shallow
// only checks angle on the first bounce
if (bounceCount == 0 && arrowInBlockVector.angle(inverseNormal) < Math.PI / 4) {
return;
}
// Spawn new arrow with the reflected direction
Arrow spawnedArrow = originalArrow.getWorld().spawnArrow(origin, reflectedDirection, 1, 1);
ProjectileUtils.copyArrowMetadata(pluginRef, originalArrow, spawnedArrow);
originalArrow.remove();
// copy metadata from old arrow
spawnedArrow.setShooter(originalArrowShooter);
spawnedArrow.setMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT,
new FixedMetadataValue(pluginRef, bounceCount + 1));
spawnedArrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW,
new FixedMetadataValue(pluginRef, originalArrowShooter));
// Don't allow multi-shot or infinite arrows to be picked up
if (spawnedArrow.hasMetadata(MetadataConstants.METADATA_KEY_MULTI_SHOT_ARROW)
|| spawnedArrow.hasMetadata(MetadataConstants.METADATA_KEY_INF_ARROW)) {
spawnedArrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED);
}
// Schedule cleanup of metadata in case metadata cleanup fails
delayArrowMetaCleanup(spawnedArrow);
}
public int getTrickShotMaxBounceCount() {
return RankUtils.getRank(mmoPlayer, SubSkillType.CROSSBOWS_TRICK_SHOT);
}
public double getPoweredShotBonusDamage(Player player, double oldDamage)
{
double damageBonusPercent = getDamageBonusPercent(player);
double newDamage = oldDamage + (oldDamage * damageBonusPercent);
return Math.min(newDamage, (oldDamage + mcMMO.p.getAdvancedConfig().getPoweredShotDamageMax()));
}
public double getDamageBonusPercent(Player player) {
return ((RankUtils.getRank(player, SubSkillType.CROSSBOWS_POWERED_SHOT)) * (mcMMO.p.getAdvancedConfig().getPoweredShotRankDamageMultiplier()) / 100.0D);
}
public double poweredShot(double oldDamage) {
if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.CROSSBOWS_POWERED_SHOT, getPlayer())) {
return getPoweredShotBonusDamage(getPlayer(), oldDamage);
} else {
return oldDamage;
}
}
}

View File

@@ -2,6 +2,7 @@ package com.gmail.nossr50.skills.excavation;
import com.gmail.nossr50.api.ItemSpawnReason;
import com.gmail.nossr50.datatypes.experience.XPGainReason;
import com.gmail.nossr50.datatypes.experience.XPGainSource;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
@@ -10,15 +11,19 @@ import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.random.RandomChanceUtil;
import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.bukkit.Location;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.VisibleForTesting;
import java.util.List;
import static java.util.Objects.requireNonNull;
public class ExcavationManager extends SkillManager {
public ExcavationManager(McMMOPlayer mcMMOPlayer) {
super(mcMMOPlayer, PrimarySkillType.EXCAVATION);
@@ -31,9 +36,9 @@ public class ExcavationManager extends SkillManager {
*/
public void excavationBlockCheck(BlockState blockState) {
int xp = Excavation.getBlockXP(blockState);
requireNonNull(blockState, "excavationBlockCheck: blockState cannot be null");
if (Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.EXCAVATION_ARCHAEOLOGY)) {
List<ExcavationTreasure> treasures = Excavation.getTreasures(blockState);
List<ExcavationTreasure> treasures = getTreasures(blockState);
if (!treasures.isEmpty()) {
int skillLevel = getSkillLevel();
@@ -41,21 +46,35 @@ public class ExcavationManager extends SkillManager {
for (ExcavationTreasure treasure : treasures) {
if (skillLevel >= treasure.getDropLevel()
&& RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), PrimarySkillType.EXCAVATION, treasure.getDropChance())) {
//Spawn Vanilla XP orbs if a dice roll succeeds
if(RandomChanceUtil.rollDice(getArchaelogyExperienceOrbChance(), 100)) {
Misc.spawnExperienceOrb(location, getExperienceOrbsReward());
}
xp += treasure.getXp();
Misc.spawnItem(getPlayer(), location, treasure.getDrop(), ItemSpawnReason.EXCAVATION_TREASURE);
&& ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), treasure.getDropProbability())) {
processExcavationBonusesOnBlock(blockState, treasure, location);
}
}
}
}
applyXpGain(xp, XPGainReason.PVE);
applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF);
}
@VisibleForTesting
public List<ExcavationTreasure> getTreasures(@NotNull BlockState blockState) {
requireNonNull(blockState, "blockState cannot be null");
return Excavation.getTreasures(blockState);
}
@VisibleForTesting
public void processExcavationBonusesOnBlock(BlockState blockState, ExcavationTreasure treasure, Location location) {
//Spawn Vanilla XP orbs if a dice roll succeeds
if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.EXCAVATION, getPlayer(), getArchaelogyExperienceOrbChance())) {
Misc.spawnExperienceOrb(location, getExperienceOrbsReward());
}
int xp = 0;
xp += treasure.getXp();
Misc.spawnItem(getPlayer(), location, treasure.getDrop(), ItemSpawnReason.EXCAVATION_TREASURE);
if (xp > 0) {
applyXpGain(xp, XPGainReason.PVE, XPGainSource.SELF);
}
}
public int getExperienceOrbsReward() {

View File

@@ -18,8 +18,7 @@ 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.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
@@ -61,11 +60,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 +479,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 (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.FISHING, getPlayer(), getShakeChance())) {
List<ShakeTreasure> possibleDrops = Fishing.findPossibleDrops(target);
if (possibleDrops == null || possibleDrops.isEmpty()) {

View File

@@ -20,10 +20,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.random.ProbabilityUtil;
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;
@@ -650,7 +648,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 (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, getPlayer())) {
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.GTh.Fail");
return false;
}
@@ -665,7 +663,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 (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) {
return false;
}
@@ -684,7 +682,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))) {
&& ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.HERBALISM, player, treasure.getDropChance())) {
if (!EventUtils.simulateBlockBreak(blockState.getBlock(), player)) {
return false;
}
@@ -721,7 +719,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 (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_SHROOM_THUMB, player)) {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Herbalism.Ability.ShroomThumb.Fail");
return false;
}
@@ -805,7 +803,7 @@ public class HerbalismManager extends SkillManager {
return false;
}
if (!greenTerra && !RandomChanceUtil.checkRandomChanceExecutionSuccess(player, SubSkillType.HERBALISM_GREEN_THUMB, true)) {
if (!greenTerra && !ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.HERBALISM_GREEN_THUMB, player)) {
return false;
}

View File

@@ -13,7 +13,7 @@ import com.gmail.nossr50.runnables.skills.AbilityCooldownTask;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.*;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.random.RandomChanceUtil;
import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.apache.commons.lang.math.RandomUtils;
@@ -35,7 +35,7 @@ public class MiningManager extends SkillManager {
public static final String BUDDING_AMETHYST = "budding_amethyst";
public MiningManager(McMMOPlayer mcMMOPlayer) {
public MiningManager(@NotNull McMMOPlayer mcMMOPlayer) {
super(mcMMOPlayer, PrimarySkillType.MINING);
}
@@ -70,6 +70,11 @@ public class MiningManager extends SkillManager {
return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS);
}
public boolean canMotherLode() {
return Permissions.canUseSubSkill(getPlayer(), SubSkillType.MINING_MOTHER_LODE);
}
/**
* Process double drops & XP gain for Mining.
*
@@ -96,9 +101,32 @@ public class MiningManager extends SkillManager {
if(silkTouch && !mcMMO.p.getAdvancedConfig().getDoubleDropSilkTouchEnabled())
return;
//Mining mastery allows for a chance of triple drops
if(canMotherLode()) {
//Triple Drops failed so do a normal double drops check
if(!processTripleDrops(blockState)) {
processDoubleDrops(blockState);
}
} else {
//If the user has no mastery, proceed with normal double drop routine
processDoubleDrops(blockState);
}
}
private boolean processTripleDrops(@NotNull BlockState blockState) {
//TODO: Make this readable
if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS, true)) {
boolean useTriple = mmoPlayer.getAbilityMode(mcMMO.p.getSkillTools().getSuperAbility(skill)) && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops();
if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.MINING_MOTHER_LODE, getPlayer())) {
BlockUtils.markDropsAsBonus(blockState, 2);
return true;
} else {
return false;
}
}
private void processDoubleDrops(@NotNull BlockState blockState) {
//TODO: Make this readable
if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.MINING_DOUBLE_DROPS, getPlayer())) {
boolean useTriple = mmoPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER) && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops();
BlockUtils.markDropsAsBonus(blockState, useTriple);
}
}

View File

@@ -14,10 +14,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.random.ProbabilityUtil;
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;
@@ -322,7 +320,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 (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.REPAIR_SUPER_REPAIR, getPlayer())) {
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Repair.Skills.FeltEasy");
return true;
}
@@ -373,10 +371,10 @@ public class RepairManager extends SkillManager {
Enchantment enchantment = enchant.getKey();
if (RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getKeepEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING))) {
if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), getKeepEnchantChance())) {
if (ArcaneForging.arcaneForgingDowngrades && enchantLevel > 1
&& (!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(100 - getDowngradeEnchantChance(), getPlayer(), SubSkillType.REPAIR_ARCANE_FORGING)))) {
&& (!ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.REPAIR, getPlayer(), 100 - getDowngradeEnchantChance()))) {
item.addUnsafeEnchantment(enchantment, enchantLevel - 1);
downgraded = true;
}

View File

@@ -14,8 +14,7 @@ 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.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
import com.gmail.nossr50.util.sounds.SoundManager;
@@ -121,7 +120,7 @@ public class SalvageManager extends SkillManager {
for(int x = 0; x < potentialSalvageYield-1; x++) {
if(RandomChanceUtil.rollDice(chanceOfSuccess, 100)) {
if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, chanceOfSuccess)) {
chanceOfSuccess-=3;
chanceOfSuccess = Math.max(chanceOfSuccess, 90);
@@ -252,12 +251,12 @@ public class SalvageManager extends SkillManager {
if (!Salvage.arcaneSalvageEnchantLoss
|| Permissions.hasSalvageEnchantBypassPerk(player)
|| RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractFullEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) {
|| ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractFullEnchantChance())) {
enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true);
}
else if (enchantLevel > 1
&& Salvage.arcaneSalvageDowngrades
&& RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractPartialEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) {
&& ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SALVAGE, player, getExtractPartialEnchantChance())) {
enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true);
downgraded = true;
} else {

View File

@@ -8,9 +8,8 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.random.RandomChanceUtil;
import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import org.bukkit.block.Furnace;
import org.bukkit.event.inventory.FurnaceBurnEvent;
import org.bukkit.event.inventory.FurnaceSmeltEvent;
@@ -25,7 +24,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());
&& ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.SMELTING_SECOND_SMELT, getPlayer());
}
/**

View File

@@ -14,10 +14,9 @@ import com.gmail.nossr50.util.ItemUtils;
import com.gmail.nossr50.util.MetadataConstants;
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.ProbabilityUtil;
import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@@ -76,7 +75,8 @@ public class SwordsManager extends SkillManager {
return; //Don't apply bleed
}
if (RandomChanceUtil.rollDice(mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank()), 100)) {
double ruptureOdds = mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank());
if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SWORDS, this.getPlayer(), ruptureOdds)) {
if (target instanceof Player defender) {
@@ -141,7 +141,8 @@ 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 (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) {
CombatUtils.dealDamage(attacker, damage / Swords.counterAttackModifier, getPlayer());
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.Countered");

View File

@@ -15,11 +15,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.RandomChanceSkillStatic;
import com.gmail.nossr50.util.random.RandomChanceUtil;
import com.gmail.nossr50.util.random.ProbabilityUtil;
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.sounds.SoundManager;
import com.gmail.nossr50.util.sounds.SoundType;
import com.gmail.nossr50.util.text.StringUtils;
@@ -145,7 +143,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 (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) {
return;
}
@@ -165,12 +163,6 @@ public class TamingManager extends SkillManager {
* @param damage The initial damage
*/
public double gore(@NotNull LivingEntity target, double damage) {
// if (target instanceof Player) {
// NotificationManager.sendPlayerInformation((Player)target, NotificationType.SUBSKILL_MESSAGE, "Combat.StruckByGore");
// }
//
// NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.Gore");
damage = (damage * Taming.goreModifier) - damage;
return damage;
@@ -270,7 +262,7 @@ public class TamingManager extends SkillManager {
if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL))
return;
if(!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(mcMMO.p.getAdvancedConfig().getPummelChance(), getPlayer(), SubSkillType.TAMING_PUMMEL)))
if(!ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.TAMING, getPlayer(), mcMMO.p.getAdvancedConfig().getPummelChance()))
return;
ParticleEffectUtils.playGreaterImpactEffect(target);
@@ -380,17 +372,12 @@ public class TamingManager extends SkillManager {
}
private void spawnCOTWEntity(CallOfTheWildType callOfTheWildType, Location spawnLocation, EntityType entityType) {
switch(callOfTheWildType) {
case CAT:
switch (callOfTheWildType) {
case CAT ->
//Entity type is needed for cats because in 1.13 and below we spawn ocelots, in 1.14 and above we spawn cats
spawnCat(spawnLocation, entityType);
break;
case HORSE:
spawnHorse(spawnLocation);
break;
case WOLF:
spawnWolf(spawnLocation);
break;
spawnCat(spawnLocation, entityType);
case HORSE -> spawnHorse(spawnLocation);
case WOLF -> spawnWolf(spawnLocation);
}
}

View File

@@ -0,0 +1,35 @@
package com.gmail.nossr50.skills.tridents;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.datatypes.skills.ToolType;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.skills.RankUtils;
public class TridentsManager extends SkillManager {
public TridentsManager(McMMOPlayer mmoPlayer) {
super(mmoPlayer, PrimarySkillType.TRIDENTS);
}
/**
* Checks if the player can activate the Super Ability for Tridents
* @return true if the player can activate the Super Ability, false otherwise
*/
public boolean canActivateAbility() {
return mmoPlayer.getToolPreparationMode(ToolType.TRIDENTS) && Permissions.tridentsSuper(getPlayer());
}
public double impaleDamageBonus() {
int rank = RankUtils.getRank(getPlayer(), SubSkillType.TRIDENTS_IMPALE);
if(rank > 1) {
return (1.0D + (rank * .5D));
} else if(rank == 1) {
return 1.0D;
}
return 0.0D;
}
}

View File

@@ -12,9 +12,8 @@ import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.*;
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.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Item;
@@ -68,7 +67,7 @@ public class UnarmedManager extends SkillManager {
}
public boolean blockCrackerCheck(@NotNull BlockState blockState) {
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) {
if (!ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) {
return false;
}
@@ -99,7 +98,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 (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) {
if (EventUtils.callDisarmEvent(defender).isCancelled()) {
return;
}
@@ -122,7 +121,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 (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.UNARMED_ARROW_DEFLECT, getPlayer())) {
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.ArrowDeflect");
return true;
}
@@ -145,11 +144,11 @@ 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())) {
return 0;
if (ProbabilityUtil.isNonRNGSkillActivationSuccessful(SubSkillType.UNARMED_STEEL_ARM_STYLE, getPlayer())) {
return getSteelArmStyleDamage();
}
return getSteelArmStyleDamage();
return 0;
}
public double getSteelArmStyleDamage() {
@@ -179,7 +178,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)) {
&& ProbabilityUtil.isSkillRNGSuccessful(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

@@ -14,10 +14,9 @@ import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.*;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.random.RandomChanceUtil;
import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.skills.SkillUtils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@@ -35,7 +34,9 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
//TODO: Seems to not be using the item drop event for bonus drops, may want to change that.. or may not be able to be changed?
public class WoodcuttingManager extends SkillManager {
private boolean treeFellerReachedThreshold = false;
private static int treeFellerThreshold; //TODO: Shared setting, will be removed in 2.2
@@ -68,21 +69,46 @@ public class WoodcuttingManager extends SkillManager {
&& ItemUtils.isAxe(heldItem);
}
private boolean checkHarvestLumberActivation(@NotNull Material material) {
private boolean checkHarvestLumberActivation(Material material) {
return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
&& RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
&& RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer())
&& ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer())
&& mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material);
}
private boolean checkCleanCutsActivation(Material material) {
return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
&& RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)
&& ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.WOODCUTTING_CLEAN_CUTS, getPlayer())
&& mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material);
}
/**
* Begins Woodcutting
* Processes bonus drops for a block
*
* @param blockState Block being broken
*/
public void processHarvestLumber(@NotNull BlockState blockState) {
if (checkHarvestLumberActivation(blockState.getType())) {
spawnHarvestLumberBonusDrops(blockState);
public void processBonusDropCheck(@NotNull BlockState blockState) {
//TODO: Why isn't this using the item drop event? Potentially because of Tree Feller? This should be adjusted either way.
if(mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, blockState.getType())) {
//Mastery enabled for player
if(Permissions.canUseSubSkill(getPlayer(), SubSkillType.WOODCUTTING_CLEAN_CUTS)) {
if(checkCleanCutsActivation(blockState.getType())) {
//Triple drops
spawnHarvestLumberBonusDrops(blockState);
spawnHarvestLumberBonusDrops(blockState);
} else {
//Harvest Lumber Check
if(checkHarvestLumberActivation(blockState.getType())) {
spawnHarvestLumberBonusDrops(blockState);
}
}
//No Mastery (no Clean Cuts)
} else if (Permissions.canUseSubSkill(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER)) {
if(checkHarvestLumberActivation(blockState.getType())) {
spawnHarvestLumberBonusDrops(blockState);
}
}
}
}
@@ -295,24 +321,23 @@ public class WoodcuttingManager extends SkillManager {
Misc.spawnItemsFromCollection(getPlayer(), Misc.getBlockCenter(blockState), block.getDrops(itemStack), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK);
//Bonus Drops / Harvest lumber checks
processHarvestLumber(blockState);
processBonusDropCheck(blockState);
} else if (BlockUtils.isNonWoodPartOfTree(blockState)) {
//Drop displaced non-woodcutting XP blocks
if(RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) {
// 90% of the time do not drop leaf blocks
if (ThreadLocalRandom.current().nextInt(100) > 90) {
Misc.spawnItemsFromCollection(getPlayer(), Misc.getBlockCenter(blockState), block.getDrops(itemStack), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK);
}
//Drop displaced non-woodcutting XP blocks
if(RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) {
if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) {
if(mcMMO.p.getAdvancedConfig().isKnockOnWoodXPOrbEnabled()) {
if(RandomChanceUtil.rollDice(10, 100)) {
if(ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.WOODCUTTING, player, 10)) {
int randOrbCount = Math.max(1, Misc.getRandom().nextInt(100));
Misc.spawnExperienceOrb(blockState.getLocation(), randOrbCount);
}
}
}
} else {
Misc.spawnItemsFromCollection(getPlayer(), Misc.getBlockCenter(blockState), block.getDrops(itemStack), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK, 1);
}
}
@@ -381,6 +406,10 @@ public class WoodcuttingManager extends SkillManager {
* @param blockState Block being broken
*/
protected void spawnHarvestLumberBonusDrops(@NotNull BlockState blockState) {
Misc.spawnItemsFromCollection(getPlayer(), Misc.getBlockCenter(blockState), blockState.getBlock().getDrops(getPlayer().getInventory().getItemInMainHand()), ItemSpawnReason.BONUS_DROPS);
Misc.spawnItemsFromCollection(
getPlayer(),
Misc.getBlockCenter(blockState),
blockState.getBlock().getDrops(getPlayer().getInventory().getItemInMainHand()),
ItemSpawnReason.BONUS_DROPS);
}
}