Add Maces skill
This commit is contained in:
Robert Alan Chapton
2024-06-30 15:10:29 -07:00
committed by GitHub
parent 02c732bdf2
commit 971e5da0ad
38 changed files with 688 additions and 288 deletions

View File

@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class McrankCommand implements TabExecutor {
public class McRankCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
switch (args.length) {

View File

@ -22,7 +22,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class MctopCommand implements TabExecutor {
public class McTopCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
PrimarySkillType skill = null;
@ -44,6 +44,12 @@ public class MctopCommand implements TabExecutor {
return true;
}
// Check if the command is for Maces but the MC version is not correct
if (skill == PrimarySkillType.MACES
&& !mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 21, 0)) {
return true;
}
display(1, skill, sender, command);
return true;
@ -58,6 +64,12 @@ public class MctopCommand implements TabExecutor {
return true;
}
// Check if the command is for Maces but the MC version is not correct
if (skill == PrimarySkillType.MACES
&& !mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 21, 0)) {
return true;
}
display(Math.abs(Integer.parseInt(args[1])), skill, sender, command);
return true;

View File

@ -1,52 +1,81 @@
//package com.gmail.nossr50.commands.skills;
//
//import com.gmail.nossr50.datatypes.player.McMMOPlayer;
//import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
//import com.gmail.nossr50.util.player.UserManager;
//import com.gmail.nossr50.util.skills.CombatUtils;
//import com.gmail.nossr50.util.skills.SkillUtils;
//import com.gmail.nossr50.util.text.TextComponentFactory;
//import net.kyori.adventure.text.Component;
//import org.bukkit.ChatColor;
//import org.bukkit.entity.Player;
//
//import java.util.ArrayList;
//import java.util.List;
//
//import static com.gmail.nossr50.datatypes.skills.SubSkillType.MACES_MACES_LIMIT_BREAK;
//
//public class MacesCommand extends SkillCommand {
//
// public MacesCommand() {
// super(PrimarySkillType.MACES);
// }
//
// @Override
// protected void dataCalculations(Player player, float skillValue) {}
//
// @Override
// protected void permissionsCheck(Player player) {}
//
// @Override
// protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
// List<String> messages = new ArrayList<>();
//
// if (SkillUtils.canUseSubskill(player, MACES_MACES_LIMIT_BREAK)) {
// messages.add(getStatMessage(MACES_MACES_LIMIT_BREAK,
// String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, MACES_MACES_LIMIT_BREAK, 1000))));
// }
//
// messages.add(ChatColor.GRAY + "The Maces skill is a work in progress and is still being developed," +
// " feedback would be appreciated in the mcMMO discord server.");
// return messages;
// }
//
// @Override
// protected List<Component> getTextComponents(Player player) {
// List<Component> textComponents = new ArrayList<>();
//
// TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.MACES);
//
// return textComponents;
// }
//}
package com.gmail.nossr50.commands.skills;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.maces.MacesManager;
import com.gmail.nossr50.util.skills.CombatUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillUtils;
import com.gmail.nossr50.util.text.TextComponentFactory;
import net.kyori.adventure.text.Component;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import static com.gmail.nossr50.datatypes.skills.SubSkillType.MACES_CRIPPLE;
import static com.gmail.nossr50.datatypes.skills.SubSkillType.MACES_MACES_LIMIT_BREAK;
public class MacesCommand extends SkillCommand {
public MacesCommand() {
super(PrimarySkillType.MACES);
}
String crippleChanceToApply, crippleChanceToApplyLucky, crippleLengthAgainstPlayers, crippleLengthAgainstMobs;
@Override
protected void dataCalculations(Player player, float skillValue) {
if (SkillUtils.canUseSubskill(player, MACES_CRIPPLE)) {
int crippleRank = RankUtils.getRank(player, MACES_CRIPPLE);
crippleLengthAgainstPlayers = String.valueOf(MacesManager.getCrippleTickDuration(true) / 20.0D);
crippleLengthAgainstMobs = String.valueOf(MacesManager.getCrippleTickDuration(false) / 20.0D);
crippleChanceToApply = String.valueOf(mcMMO.p.getAdvancedConfig().getCrippleChanceToApplyOnHit(crippleRank) + "%");
crippleChanceToApplyLucky = String.valueOf(mcMMO.p.getAdvancedConfig().getCrippleChanceToApplyOnHit(crippleRank) * 1.33);
}
}
@Override
protected void permissionsCheck(Player player) {}
@Override
protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
final List<String> messages = new ArrayList<>();
if (SkillUtils.canUseSubskill(player, MACES_MACES_LIMIT_BREAK)) {
messages.add(getStatMessage(MACES_MACES_LIMIT_BREAK,
String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player,
MACES_MACES_LIMIT_BREAK, 1000))));
}
if (SkillUtils.canUseSubskill(player, MACES_CRIPPLE)) {
messages.add(getStatMessage(MACES_CRIPPLE, crippleChanceToApply)
+ (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", crippleChanceToApplyLucky) : ""));
messages.add(getStatMessage(true, true, MACES_CRIPPLE,
crippleLengthAgainstPlayers,
crippleLengthAgainstMobs));
}
if (SkillUtils.canUseSubskill(player, SubSkillType.MACES_CRUSH)) {
messages.add(getStatMessage(SubSkillType.MACES_CRUSH,
String.valueOf(mmoPlayer.getMacesManager().getCrushDamage())));
}
messages.add(ChatColor.GRAY + "The Maces skill is a work in progress and is still being developed," +
" feedback would be appreciated in the mcMMO discord server.");
return messages;
}
@Override
protected List<Component> getTextComponents(Player player) {
List<Component> textComponents = new ArrayList<>();
TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.MACES);
return textComponents;
}
}

View File

@ -11,6 +11,7 @@ import java.util.ArrayList;
import java.util.List;
public class AdvancedConfig extends BukkitConfig {
int[] defaultCrippleValues = new int[]{10, 15, 20, 25};
public AdvancedConfig(File dataFolder) {
super("advanced.yml", dataFolder);
@ -937,4 +938,10 @@ public class AdvancedConfig extends BukkitConfig {
public boolean isKnockOnWoodXPOrbEnabled() {
return config.getBoolean("Skills.Woodcutting.TreeFeller.Knock_On_Wood.Add_XP_Orbs_To_Drops", true);
}
/* MACES */
public double getCrippleChanceToApplyOnHit(int rank) {
String root = "Skills.Maces.Cripple.Chance_To_Apply_On_Hit.Rank_";
return config.getDouble(root + rank, defaultCrippleValues[rank-1]);
}
}

View File

@ -547,6 +547,10 @@ public class GeneralConfig extends BukkitConfig {
return config.getBoolean("Particles.Bleed", true);
}
public boolean getCrippleEffectEnabled() {
return config.getBoolean("Particles.Cripple", true);
}
public boolean getDodgeEffectEnabled() {
return config.getBoolean("Particles.Dodge", true);
}

View File

@ -50,12 +50,12 @@ public class SoundConfig extends BukkitConfig {
public float getVolume(SoundType soundType) {
String key = "Sounds." + soundType.toString() + ".Volume";
return (float) config.getDouble(key);
return (float) config.getDouble(key, 1.0);
}
public float getPitch(SoundType soundType) {
String key = "Sounds." + soundType.toString() + ".Pitch";
return (float) config.getDouble(key);
return (float) config.getDouble(key, 1.0);
}
public boolean getIsEnabled(SoundType soundType) {

View File

@ -112,7 +112,6 @@ public class McMMOPlayer implements Identified {
private int respawnATS;
private int teleportATS;
private long databaseATS;
private double attackStrength; //captured during arm swing events
//private int chimeraWingLastUse;
private Location teleportCommence;
@ -151,7 +150,6 @@ public class McMMOPlayer implements Identified {
experienceBarManager = new ExperienceBarManager(this);
debugMode = false; //Debug mode helps solve support issues, players can toggle it on or off
attackStrength = 1.0D;
this.playerAuthor = new PlayerAuthor(player);
@ -227,7 +225,9 @@ public class McMMOPlayer implements Identified {
skillManagers.put(primarySkillType, new WoodcuttingManager(this));
break;
case MACES:
skillManagers.put(primarySkillType, new MacesManager(this));
if (mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 21, 0)) {
skillManagers.put(primarySkillType, new MacesManager(this));
}
break;
default:
throw new InvalidSkillException("The skill named has no manager! Contact the devs!");
@ -239,7 +239,7 @@ public class McMMOPlayer implements Identified {
}
public double getAttackStrength() {
return attackStrength;
return player.getAttackCooldown();
}
public @NotNull PrimarySkillType getLastSkillShownScoreboard() {

View File

@ -59,6 +59,8 @@ public enum SubSkillType {
/* Maces */
MACES_MACES_LIMIT_BREAK(10),
MACES_CRUSH(4),
MACES_CRIPPLE(4),
/* Mining */
MINING_BIGGER_BOMBS(1),

View File

@ -162,6 +162,9 @@ public class mcMMO extends JavaPlugin {
//Filter out any debug messages (if debug/verbose logging is not enabled)
getLogger().setFilter(new LogFilter(this));
//Platform Manager
platformManager = new PlatformManager();
//Folia lib plugin instance
foliaLib = new FoliaLib(this);
InvalidTickDelayNotifier.disableNotifications = true;
@ -178,9 +181,6 @@ public class mcMMO extends JavaPlugin {
//Store this value so other plugins can check it
isRetroModeEnabled = generalConfig.getIsRetroMode();
//Platform Manager
platformManager = new PlatformManager();
MetadataConstants.MCMMO_METADATA_VALUE = new FixedMetadataValue(this, true);
PluginManager pluginManager = getServer().getPluginManager();

View File

@ -310,6 +310,7 @@ public final class PartyManager {
* @param party The party to remove
* @deprecated Use {@link #disbandParty(McMMOPlayer, Party)}
*/
@Deprecated
public void disbandParty(@NotNull Party party) {
requireNonNull(party, "party cannot be null!");
disbandParty(null, party);

View File

@ -32,7 +32,7 @@ public class McRankCommandAsyncTask extends CancellableRunnable {
public void run() {
Map<PrimarySkillType, Integer> skills = mcMMO.getDatabaseManager().readRank(playerName);
mcMMO.p.getFoliaLib().getImpl().runNextTick(new McrankCommandDisplayTask(skills, sender, playerName, useBoard, useChat));
mcMMO.p.getFoliaLib().getImpl().runNextTick(new McRankCommandDisplayTask(skills, sender, playerName, useBoard, useChat));
}
}

View File

@ -15,13 +15,14 @@ import java.util.Map;
/**
* Display the results of McrankCommandAsyncTask to the sender.
*/
public class McrankCommandDisplayTask extends CancellableRunnable {
public class McRankCommandDisplayTask extends CancellableRunnable {
private final Map<PrimarySkillType, Integer> skills;
private final CommandSender sender;
private final String playerName;
private final boolean useBoard, useChat;
McrankCommandDisplayTask(Map<PrimarySkillType, Integer> skills, CommandSender sender, String playerName, boolean useBoard, boolean useChat) {
McRankCommandDisplayTask(Map<PrimarySkillType, Integer> skills, CommandSender sender, String playerName,
boolean useBoard, boolean useChat) {
this.skills = skills;
this.sender = sender;
this.playerName = playerName;
@ -42,17 +43,17 @@ public class McrankCommandDisplayTask extends CancellableRunnable {
}
private void displayChat() {
// Player player = mcMMO.p.getServer().getPlayerExact(playerName);
Integer rank;
sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Heading"));
sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Player", playerName));
for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) {
// if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, skill)) {
// continue;
// }
// Check if the command is for Maces but the MC version is not correct
if (skill == PrimarySkillType.MACES
&& !mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 21, 0)) {
continue;
}
rank = skills.get(skill);
sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank)));
}

View File

@ -22,6 +22,9 @@ import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import static com.gmail.nossr50.util.random.ProbabilityUtil.isSkillRNGSuccessful;
import static com.gmail.nossr50.util.skills.SkillUtils.handleArmorDurabilityChange;
public class AxesManager extends SkillManager {
public AxesManager(McMMOPlayer mcMMOPlayer) {
super(mcMMOPlayer, PrimarySkillType.AXES);
@ -84,7 +87,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 (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_CRITICAL_STRIKES, mmoPlayer)) {
if (!isSkillRNGSuccessful(SubSkillType.AXES_CRITICAL_STRIKES, mmoPlayer, mmoPlayer.getAttackStrength())) {
return 0;
}
@ -123,8 +126,8 @@ public class AxesManager extends SkillManager {
for (ItemStack armor : equipment.getArmorContents()) {
if (armor != null && ItemUtils.isArmor(armor)) {
if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_ARMOR_IMPACT, mmoPlayer)) {
SkillUtils.handleArmorDurabilityChange(armor, durabilityDamage, 1);
if (isSkillRNGSuccessful(SubSkillType.AXES_ARMOR_IMPACT, mmoPlayer, mmoPlayer.getAttackStrength())) {
handleArmorDurabilityChange(armor, durabilityDamage, 1);
}
}
}
@ -140,15 +143,15 @@ public class AxesManager extends SkillManager {
* @param target The {@link LivingEntity} being affected by the ability
*/
public double greaterImpact(@NotNull LivingEntity target) {
//static chance (3rd param)
if (!ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.AXES_GREATER_IMPACT, mmoPlayer)) {
if (!isSkillRNGSuccessful(SubSkillType.AXES_GREATER_IMPACT, mmoPlayer, mmoPlayer.getAttackStrength())) {
return 0;
}
Player player = getPlayer();
ParticleEffectUtils.playGreaterImpactEffect(target);
target.setVelocity(player.getLocation().getDirection().normalize().multiply(Axes.greaterImpactKnockbackMultiplier));
target.setVelocity(
player.getLocation().getDirection().normalize().multiply(Axes.greaterImpactKnockbackMultiplier));
if (mmoPlayer.useChatNotifications()) {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Axes.Combat.GI.Proc");
@ -170,6 +173,6 @@ public class AxesManager extends SkillManager {
* @param damage The amount of damage initially dealt by the event
*/
public void skullSplitterCheck(@NotNull LivingEntity target, double damage) {
CombatUtils.applyAbilityAoE(getPlayer(), target, damage / Axes.skullSplitterModifier, skill);
CombatUtils.applyAbilityAoE(getPlayer(), target, (damage / Axes.skullSplitterModifier) * mmoPlayer.getAttackStrength(), skill);
}
}

View File

@ -1,11 +1,114 @@
package com.gmail.nossr50.skills.maces;
import com.gmail.nossr50.datatypes.interactions.NotificationType;
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.Permissions;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.random.ProbabilityUtil;
import com.gmail.nossr50.util.skills.ParticleEffectUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Locale;
public class MacesManager extends SkillManager {
private static @Nullable PotionEffectType slowEffectType;
public MacesManager(McMMOPlayer mmoPlayer) {
super(mmoPlayer, PrimarySkillType.MACES);
}
private static @Nullable PotionEffectType mockSpigotMatch(@NotNull String input) {
// Replicates match() behaviour for older versions lacking this API
final String filtered = input.toLowerCase(Locale.ROOT).replaceAll("\\s+", "_");
final NamespacedKey namespacedKey = NamespacedKey.fromString(filtered);
return (namespacedKey != null) ? Registry.EFFECT.get(namespacedKey) : null;
}
/**
* Get the Crush damage bonus.
*
* @return the Crush damage bonus.
*/
public double getCrushDamage() {
if (!Permissions.canUseSubSkill(mmoPlayer.getPlayer(), SubSkillType.MACES_CRUSH))
return 0;
int rank = RankUtils.getRank(getPlayer(), SubSkillType.MACES_CRUSH);
if (rank > 0) {
return (0.5D + (rank * 1.D));
}
return 0;
}
/**
* Process Cripple attack.
*
* @param target The defending entity
*/
public void processCripple(@NotNull LivingEntity target) {
// Lazy initialized to avoid some backwards compatibility issues
if (slowEffectType == null) {
if (mockSpigotMatch("slowness") == null) {
mcMMO.p.getLogger().severe("Unable to find the Slowness PotionEffectType, " +
"mcMMO will not function properly.");
throw new IllegalStateException("Unable to find the Slowness PotionEffectType!");
} else {
slowEffectType = mockSpigotMatch("slowness");
}
}
boolean isPlayerTarget = target instanceof Player;
// Don't apply Cripple if the target is already Slowed
if (slowEffectType == null || target.getPotionEffect(slowEffectType) != null) {
return;
}
if (!Permissions.canUseSubSkill(mmoPlayer.getPlayer(), SubSkillType.MACES_CRIPPLE)) {
return;
}
int crippleRank = RankUtils.getRank(getPlayer(), SubSkillType.MACES_CRIPPLE);
double crippleOdds = (mcMMO.p.getAdvancedConfig().getCrippleChanceToApplyOnHit(crippleRank)
* mmoPlayer.getAttackStrength());
if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.MACES, mmoPlayer, crippleOdds)) {
if (mmoPlayer.useChatNotifications()) {
NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(),
NotificationType.SUBSKILL_MESSAGE, "Maces.SubSkill.Cripple.Activated");
}
// Cripple is success, Cripple the target
target.addPotionEffect(slowEffectType.createEffect(
getCrippleTickDuration(isPlayerTarget),
getCrippleStrength(isPlayerTarget)));
ParticleEffectUtils.playCrippleEffect(target);
}
}
public static int getCrippleTickDuration(boolean isPlayerTarget) {
// TODO: Make configurable
if (isPlayerTarget) {
return 20;
} else {
return 30;
}
}
public static int getCrippleStrength(boolean isPlayerTarget) {
// TODO: Make configurable
return isPlayerTarget ? 1 : 2;
}
}

View File

@ -75,7 +75,8 @@ public class SwordsManager extends SkillManager {
return; //Don't apply bleed
}
double ruptureOdds = mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank());
double ruptureOdds = mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank())
* mmoPlayer.getAttackStrength();
if (ProbabilityUtil.isStaticSkillRNGSuccessful(PrimarySkillType.SWORDS, mmoPlayer, ruptureOdds)) {
if (target instanceof Player defender) {

View File

@ -22,6 +22,8 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import static com.gmail.nossr50.util.random.ProbabilityUtil.isSkillRNGSuccessful;
public class UnarmedManager extends SkillManager {
public UnarmedManager(McMMOPlayer mcMMOPlayer) {
@ -98,7 +100,8 @@ public class UnarmedManager extends SkillManager {
* @param defender The defending player
*/
public void disarmCheck(@NotNull Player defender) {
if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.UNARMED_DISARM, mmoPlayer) && !hasIronGrip(defender)) {
if (isSkillRNGSuccessful(SubSkillType.UNARMED_DISARM, mmoPlayer, mmoPlayer.getAttackStrength())
&& !hasIronGrip(defender)) {
if (EventUtils.callDisarmEvent(defender).isCancelled()) {
return;
}
@ -121,7 +124,7 @@ public class UnarmedManager extends SkillManager {
* Check for arrow deflection.
*/
public boolean deflectCheck() {
if (ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.UNARMED_ARROW_DEFLECT, mmoPlayer)) {
if (isSkillRNGSuccessful(SubSkillType.UNARMED_ARROW_DEFLECT, mmoPlayer)) {
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Combat.ArrowDeflect");
return true;
}
@ -178,7 +181,7 @@ public class UnarmedManager extends SkillManager {
private boolean hasIronGrip(@NotNull Player defender) {
if (!Misc.isNPCEntityExcludingVillagers(defender)
&& Permissions.isSubSkillEnabled(defender, SubSkillType.UNARMED_IRON_GRIP)
&& ProbabilityUtil.isSkillRNGSuccessful(SubSkillType.UNARMED_IRON_GRIP, UserManager.getPlayer(defender))) {
&& isSkillRNGSuccessful(SubSkillType.UNARMED_IRON_GRIP, UserManager.getPlayer(defender))) {
NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Defender");
NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Attacker");

View File

@ -32,95 +32,47 @@ public final class CommandRegistrationManager {
private static final String permissionsMessage = LocaleLoader.getString("mcMMO.NoPermission");
private static void registerSkillCommands() {
for (PrimarySkillType skill : PrimarySkillType.values()) {
if (skill == PrimarySkillType.MACES)
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
if (primarySkillType == PrimarySkillType.MACES
&& !mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 21, 0)) {
continue;
}
String commandName = skill.toString().toLowerCase(Locale.ENGLISH);
String localizedName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill).toLowerCase(Locale.ENGLISH);
final String commandName = primarySkillType.toString().toLowerCase(Locale.ENGLISH);
final String localizedName = mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType).toLowerCase(Locale.ENGLISH);
PluginCommand command;
final PluginCommand command = mcMMO.p.getCommand(commandName);
if (command == null) {
mcMMO.p.getLogger().severe("Command not found: " + commandName);
continue;
}
command = mcMMO.p.getCommand(commandName);
command.setDescription(LocaleLoader.getString("Commands.Description.Skill", StringUtils.getCapitalized(localizedName)));
command.setPermission("mcmmo.commands." + commandName);
command.setPermissionMessage(permissionsMessage);
command.setUsage(LocaleLoader.getString("Commands.Usage.0", commandName));
command.setUsage(command.getUsage() + "\n" + LocaleLoader.getString("Commands.Usage.2", commandName, "?", "[" + LocaleLoader.getString("Commands.Usage.Page") + "]"));
switch (skill) {
case ACROBATICS:
command.setExecutor(new AcrobaticsCommand());
break;
case ALCHEMY:
command.setExecutor(new AlchemyCommand());
break;
case ARCHERY:
command.setExecutor(new ArcheryCommand());
break;
case AXES:
command.setExecutor(new AxesCommand());
break;
case CROSSBOWS:
command.setExecutor(new CrossbowsCommand());
break;
case EXCAVATION:
command.setExecutor(new ExcavationCommand());
break;
case FISHING:
command.setExecutor(new FishingCommand());
break;
case HERBALISM:
command.setExecutor(new HerbalismCommand());
break;
case MACES:
// command.setExecutor(new MacesCommand());
break;
case MINING:
command.setExecutor(new MiningCommand());
break;
case REPAIR:
command.setExecutor(new RepairCommand());
break;
case SALVAGE:
command.setExecutor(new SalvageCommand());
break;
case SMELTING:
command.setExecutor(new SmeltingCommand());
break;
case SWORDS:
command.setExecutor(new SwordsCommand());
break;
case TAMING:
command.setExecutor(new TamingCommand());
break;
case TRIDENTS:
command.setExecutor(new TridentsCommand());
break;
case UNARMED:
command.setExecutor(new UnarmedCommand());
break;
case WOODCUTTING:
command.setExecutor(new WoodcuttingCommand());
break;
default:
throw new IllegalStateException("Unexpected value: " + skill);
switch (primarySkillType) {
case ACROBATICS -> command.setExecutor(new AcrobaticsCommand());
case ALCHEMY -> command.setExecutor(new AlchemyCommand());
case ARCHERY -> command.setExecutor(new ArcheryCommand());
case AXES -> command.setExecutor(new AxesCommand());
case CROSSBOWS -> command.setExecutor(new CrossbowsCommand());
case EXCAVATION -> command.setExecutor(new ExcavationCommand());
case FISHING -> command.setExecutor(new FishingCommand());
case HERBALISM -> command.setExecutor(new HerbalismCommand());
case MACES -> command.setExecutor(new MacesCommand());
case MINING -> command.setExecutor(new MiningCommand());
case REPAIR -> command.setExecutor(new RepairCommand());
case SALVAGE -> command.setExecutor(new SalvageCommand());
case SMELTING -> command.setExecutor(new SmeltingCommand());
case SWORDS -> command.setExecutor(new SwordsCommand());
case TAMING -> command.setExecutor(new TamingCommand());
case TRIDENTS -> command.setExecutor(new TridentsCommand());
case UNARMED -> command.setExecutor(new UnarmedCommand());
case WOODCUTTING -> command.setExecutor(new WoodcuttingCommand());
default -> throw new IllegalStateException("Unexpected value: " + primarySkillType);
}
}
}
@ -263,7 +215,7 @@ public final class CommandRegistrationManager {
command.setPermission("mcmmo.commands.mcrank;mcmmo.commands.mcrank.others;mcmmo.commands.mcrank.others.far;mcmmo.commands.mcrank.others.offline");
command.setPermissionMessage(permissionsMessage);
command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcrank", "[" + LocaleLoader.getString("Commands.Usage.Player") + "]"));
command.setExecutor(new McrankCommand());
command.setExecutor(new McRankCommand());
}
private static void registerMcstatsCommand() {
@ -281,7 +233,7 @@ public final class CommandRegistrationManager {
command.setPermission("mcmmo.commands.mctop"); // Only need the main one, not the individual skill ones
command.setPermissionMessage(permissionsMessage);
command.setUsage(LocaleLoader.getString("Commands.Usage.2", "mctop", "[" + LocaleLoader.getString("Commands.Usage.Skill") + "]", "[" + LocaleLoader.getString("Commands.Usage.Page") + "]"));
command.setExecutor(new MctopCommand());
command.setExecutor(new McTopCommand());
}
private static void registerMcpurgeCommand() {

View File

@ -216,13 +216,14 @@ public final class CommandUtils {
return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), profile.getXpToLevel(skill));
}
private static void printGroupedSkillData(Player inspectTarget, CommandSender display, String header, List<PrimarySkillType> skillGroup) {
private static void printGroupedSkillData(Player inspectTarget, CommandSender display,
String header, List<PrimarySkillType> skillGroup) {
if (UserManager.getPlayer(inspectTarget) == null)
return;
PlayerProfile profile = UserManager.getPlayer(inspectTarget).getProfile();
final PlayerProfile profile = UserManager.getPlayer(inspectTarget).getProfile();
List<String> displayData = new ArrayList<>();
final List<String> displayData = new ArrayList<>();
displayData.add(header);
for (PrimarySkillType primarySkillType : skillGroup) {

View File

@ -28,15 +28,10 @@ public class PlatformBuilder {
}
public @Nullable Platform build() {
switch(serverSoftwareType) {
case PAPER:
case SPIGOT:
case CRAFT_BUKKIT:
return createBukkitPlatform();
default:
return null;
}
return switch (serverSoftwareType) {
case PAPER, SPIGOT, CRAFT_BUKKIT -> createBukkitPlatform();
default -> null;
};
}
private BukkitPlatform createBukkitPlatform() {

View File

@ -85,14 +85,11 @@ public class PlatformManager {
}
public String getServerSoftwareStr() {
switch(getServerSoftware()) {
case PAPER:
return "Paper";
case SPIGOT:
return "Spigot";
default:
return "CraftBukkit";
}
return switch (getServerSoftware()) {
case PAPER -> "Paper";
case SPIGOT -> "Spigot";
default -> "CraftBukkit";
};
}
public @Nullable CompatibilityManager getCompatibilityManager() {

View File

@ -94,4 +94,17 @@ public interface Probability {
double probabilityValue = getValue() * probabilityMultiplier;
return isSuccessfulRoll(probabilityValue);
}
/**
* Modify and then Simulate an outcome on a probability and return true or false for the result of that outcome.
*
* @param probabilityMultiplier probability will be multiplied by this before success is checked
* @param finalProbabilityMultiplier probability will be multiplied by this after the first multiplier,
* should be between 0 and 1
* @return true if the probability succeeded, false if it failed
*/
default boolean evaluate(double probabilityMultiplier, double finalProbabilityMultiplier) {
double probabilityValue = getValue() * probabilityMultiplier;
return isSuccessfulRoll(probabilityValue * finalProbabilityMultiplier);
}
}

View File

@ -188,6 +188,45 @@ public class ProbabilityUtil {
}
}
/**
* This is one of several Skill RNG evaluation methods.
* This one specifically allows for a probability multiplier to be passed in.
* This probability multiplier is applied after any lucky modifiers, affecting the final result.
* <p>
* This helper method is for specific {@link SubSkillType},
* which help mcMMO understand where the RNG values used in our calculations come from this {@link SubSkillType}
* <p>
* 1) Determine where the RNG values come from for the passed {@link SubSkillType}
* NOTE: In the config file, there are values which are static and which are more dynamic,
* this is currently a bit hardcoded and will need to be updated manually
* <p>
* 2) Determine whether to use Lucky multiplier and influence the outcome
* <p>
* 3)
* Creates a {@link Probability} and pipes it to {@link ProbabilityUtil} which processes the result and returns it
* <p>
* This also calls a {@link SubSkillEvent} which can be cancelled, if it is cancelled this will return false
* The outcome of the probability can also be modified by this event that is called
*
* @param subSkillType target subskill
* @param mmoPlayer 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 McMMOPlayer mmoPlayer,
double probabilityMultiplier) {
final Probability probability = getSkillProbability(subSkillType, mmoPlayer);
//Luck
boolean isLucky = mmoPlayer != null && Permissions.lucky(mmoPlayer.getPlayer(), subSkillType.getParentSkill());
if (isLucky) {
return probability.evaluate(LUCKY_MODIFIER, probabilityMultiplier);
} else {
return probability.evaluate();
}
}
/**
* Returns the {@link Probability} for a specific {@link SubSkillType} for a specific {@link Player}.
* This does not take into account perks such as lucky for the player.

View File

@ -13,6 +13,7 @@ import com.gmail.nossr50.runnables.skills.AwardCombatXpTask;
import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager;
import com.gmail.nossr50.skills.archery.ArcheryManager;
import com.gmail.nossr50.skills.axes.AxesManager;
import com.gmail.nossr50.skills.maces.MacesManager;
import com.gmail.nossr50.skills.swords.SwordsManager;
import com.gmail.nossr50.skills.taming.TamingManager;
import com.gmail.nossr50.skills.tridents.TridentsManager;
@ -20,6 +21,7 @@ import com.gmail.nossr50.skills.unarmed.UnarmedManager;
import com.gmail.nossr50.util.*;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.player.UserManager;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.attribute.Attribute;
@ -58,7 +60,7 @@ public final class CombatUtils {
return;
}
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded
if (mcMMOPlayer == null) {
@ -72,10 +74,6 @@ public final class CombatUtils {
mcMMOPlayer.checkAbilityActivation(PrimarySkillType.SWORDS);
}
if (target.getHealth() - event.getFinalDamage() > 0) {
swordsManager.processRupture(target);
}
//Add Stab Damage
if (swordsManager.canUseStab()) {
boostedDamage += (swordsManager.getStabDamage() * mcMMOPlayer.getAttackStrength());
@ -86,18 +84,27 @@ public final class CombatUtils {
}
if (canUseLimitBreak(player, target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) {
boostedDamage += (getLimitBreakDamage(player, target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength());
boostedDamage += (getLimitBreakDamage
(player, target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength());
}
event.setDamage(boostedDamage);
if (target.getHealth() - event.getFinalDamage() > 0) {
swordsManager.processRupture(target);
}
processCombatXP(mcMMOPlayer, target, PrimarySkillType.SWORDS);
printFinalDamageDebug(player, event, mcMMOPlayer);
}
private static void printFinalDamageDebug(@NotNull Player player, @NotNull EntityDamageByEntityEvent event, @NotNull McMMOPlayer mcMMOPlayer, @Nullable String @Nullable ... extraInfoLines) {
private static void printFinalDamageDebug(@NotNull Player player, @NotNull EntityDamageByEntityEvent event,
@NotNull McMMOPlayer mcMMOPlayer,
@Nullable String @Nullable ...extraInfoLines) {
if (mcMMOPlayer.isDebugMode()) {
player.sendMessage("Final Damage value after mcMMO modifiers: "+ event.getFinalDamage());
player.sendMessage("Your current attack strength: "+ player.getAttackCooldown());
if (extraInfoLines != null) {
for(String str : extraInfoLines) {
if (str != null)
@ -114,14 +121,14 @@ public final class CombatUtils {
double boostedDamage = event.getDamage();
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded
if (mcMMOPlayer == null) {
return;
}
TridentsManager tridentsManager = mcMMOPlayer.getTridentsManager();
final TridentsManager tridentsManager = mcMMOPlayer.getTridentsManager();
// if (tridentsManager.canActivateAbility()) {
// mcMMOPlayer.checkAbilityActivation(PrimarySkillType.TRIDENTS);
@ -132,7 +139,8 @@ public final class CombatUtils {
}
if (canUseLimitBreak(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) {
boostedDamage += (getLimitBreakDamage(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength());
boostedDamage += (getLimitBreakDamage(
player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength());
}
event.setDamage(boostedDamage);
@ -148,21 +156,21 @@ public final class CombatUtils {
double boostedDamage = event.getDamage();
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded
if (mcMMOPlayer == null) {
return;
}
TridentsManager tridentsManager = mcMMOPlayer.getTridentsManager();
final TridentsManager tridentsManager = mcMMOPlayer.getTridentsManager();
if (SkillUtils.canUseSubskill(player, SubSkillType.TRIDENTS_IMPALE)) {
boostedDamage += (tridentsManager.impaleDamageBonus() * mcMMOPlayer.getAttackStrength());
boostedDamage += (tridentsManager.impaleDamageBonus());
}
if (canUseLimitBreak(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)) {
boostedDamage += (getLimitBreakDamage(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength());
boostedDamage += (getLimitBreakDamage(player, target, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK));
}
event.setDamage(boostedDamage);
@ -175,7 +183,7 @@ public final class CombatUtils {
@NotNull EntityDamageByEntityEvent event, @NotNull Arrow arrow) {
double initialDamage = event.getDamage();
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded
if (mcMMOPlayer == null) {
@ -210,60 +218,73 @@ public final class CombatUtils {
delayArrowMetaCleanup(arrow);
}
private static void processMacesCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) {
private static void processMacesCombat(@NotNull LivingEntity target,
@NotNull Player player,
@NotNull EntityDamageByEntityEvent event) {
if (event.getCause() == DamageCause.THORNS) {
return;
}
double boostedDamage = event.getDamage();
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded
if (mcMMOPlayer == null) {
return;
}
// MacesManager macesManager = mcMMOPlayer.getMacesManager();
final MacesManager macesManager = mcMMOPlayer.getMacesManager();
// Apply Limit Break DMG
if (canUseLimitBreak(player, target, SubSkillType.MACES_MACES_LIMIT_BREAK)) {
boostedDamage += (getLimitBreakDamage(player, target, SubSkillType.MACES_MACES_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength());
boostedDamage += (getLimitBreakDamage(
player, target, SubSkillType.MACES_MACES_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength());
}
event.setDamage(boostedDamage);
processCombatXP(mcMMOPlayer, target, PrimarySkillType.MACES);
// Apply Crush DMG
boostedDamage += (macesManager.getCrushDamage() * mcMMOPlayer.getAttackStrength());
event.setDamage(boostedDamage);
// Apply Cripple
if (target.getHealth() - event.getFinalDamage() > 0) {
macesManager.processCripple(target);
}
processCombatXP(mcMMOPlayer, target, PrimarySkillType.MACES);
printFinalDamageDebug(player, event, mcMMOPlayer);
}
private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) {
private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player,
@NotNull EntityDamageByEntityEvent event) {
if (event.getCause() == DamageCause.THORNS) {
return;
}
double boostedDamage = event.getDamage();
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded
if (mcMMOPlayer == null) {
return;
}
AxesManager axesManager = mcMMOPlayer.getAxesManager();
final AxesManager axesManager = mcMMOPlayer.getAxesManager();
if (axesManager.canActivateAbility()) {
mcMMOPlayer.checkAbilityActivation(PrimarySkillType.AXES);
}
if (axesManager.canUseAxeMastery()) {
boostedDamage+=axesManager.axeMastery();
boostedDamage += axesManager.axeMastery() * mcMMOPlayer.getAttackStrength();
}
if (axesManager.canImpact(target)) {
axesManager.impactCheck(target);
} else if (axesManager.canGreaterImpact(target)) {
boostedDamage+=axesManager.greaterImpact(target);
boostedDamage += axesManager.greaterImpact(target) * mcMMOPlayer.getAttackStrength();
}
if (axesManager.canUseSkullSplitter(target)) {
@ -291,14 +312,14 @@ public final class CombatUtils {
double boostedDamage = event.getDamage();
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded
if (mcMMOPlayer == null) {
return;
}
UnarmedManager unarmedManager = mcMMOPlayer.getUnarmedManager();
final UnarmedManager unarmedManager = mcMMOPlayer.getUnarmedManager();
if (unarmedManager.canActivateAbility()) {
mcMMOPlayer.checkAbilityActivation(PrimarySkillType.UNARMED);
@ -317,7 +338,8 @@ public final class CombatUtils {
}
if (canUseLimitBreak(player, target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) {
boostedDamage+=(getLimitBreakDamage(player, target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength());
boostedDamage+=(getLimitBreakDamage(
player, target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength());
}
event.setDamage(boostedDamage);
@ -331,14 +353,14 @@ public final class CombatUtils {
double boostedDamage = initialDamage;
if (master != null && master.isOnline() && master.isValid()) {
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(master);
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(master);
//Make sure the profiles been loaded
if (mcMMOPlayer == null) {
return;
}
TamingManager tamingManager = mcMMOPlayer.getTamingManager();
final TamingManager tamingManager = mcMMOPlayer.getTamingManager();
if (tamingManager.canUseFastFoodService()) {
tamingManager.fastFoodService(wolf, event.getDamage());
@ -364,7 +386,7 @@ public final class CombatUtils {
@NotNull EntityDamageByEntityEvent event, @NotNull Arrow arrow) {
double initialDamage = event.getDamage();
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
//Make sure the profiles been loaded
if (mcMMOPlayer == null) {
@ -372,7 +394,7 @@ public final class CombatUtils {
return;
}
ArcheryManager archeryManager = mcMMOPlayer.getArcheryManager();
final ArcheryManager archeryManager = mcMMOPlayer.getArcheryManager();
double boostedDamage = event.getDamage();
@ -416,7 +438,9 @@ public final class CombatUtils {
*
* @param event The event to run the combat checks on.
*/
public static void processCombatAttack(@NotNull EntityDamageByEntityEvent event, @NotNull Entity painSourceRoot, @NotNull LivingEntity target) {
public static void processCombatAttack(@NotNull EntityDamageByEntityEvent event,
@NotNull Entity painSourceRoot,
@NotNull LivingEntity target) {
Entity painSource = event.getDamager();
EntityType entityType = painSource.getType();
@ -435,8 +459,8 @@ public final class CombatUtils {
return;
}
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
AcrobaticsManager acrobaticsManager = mcMMOPlayer.getAcrobaticsManager();
final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
final AcrobaticsManager acrobaticsManager = mcMMOPlayer.getAcrobaticsManager();
if (acrobaticsManager.canDodge(target)) {
event.setDamage(acrobaticsManager.dodgeCheck(painSourceRoot, event.getDamage()));
@ -447,7 +471,7 @@ public final class CombatUtils {
return;
}
SwordsManager swordsManager = mcMMOPlayer.getSwordsManager();
final SwordsManager swordsManager = mcMMOPlayer.getSwordsManager();
if (swordsManager.canUseCounterAttack(painSource)) {
swordsManager.counterAttackChecks((LivingEntity) painSource, event.getDamage());
@ -456,7 +480,6 @@ public final class CombatUtils {
}
if (painSourceRoot instanceof Player player && entityType == EntityType.PLAYER) {
if (!UserManager.hasPlayerDataKey(player)) {
return;
}
@ -811,7 +834,7 @@ public final class CombatUtils {
NotificationManager.sendPlayerInformation((Player)entity, NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.SS.Struck");
}
McMMOPlayer mmoAttacker = UserManager.getPlayer(attacker);
final McMMOPlayer mmoAttacker = UserManager.getPlayer(attacker);
if (mmoAttacker != null) {
mmoAttacker.getSwordsManager().processRupture(livingEntity);

View File

@ -1,13 +1,14 @@
package com.gmail.nossr50.util.skills;
import com.gmail.nossr50.datatypes.interactions.NotificationType;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.sounds.SoundManager;
import com.gmail.nossr50.util.sounds.SoundType;
import org.apache.commons.lang3.RandomUtils;
import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.LivingEntity;
@ -29,7 +30,26 @@ public final class ParticleEffectUtils {
return;
}
livingEntity.getWorld().playEffect(getParticleLocation(livingEntity), Effect.STEP_SOUND, Material.REDSTONE_WIRE);
livingEntity.getWorld().playEffect(getParticleLocation(livingEntity),
Effect.STEP_SOUND, Material.REDSTONE_WIRE);
}
public static void playCrippleEffect(@NotNull LivingEntity livingEntity) {
if (!mcMMO.p.getGeneralConfig().getCrippleEffectEnabled()) {
return;
}
SoundManager.sendCategorizedSound(livingEntity.getLocation(), SoundType.CRIPPLE, SoundCategory.PLAYERS, 0.2F);
livingEntity.getWorld().playEffect(getParticleLocation(livingEntity), Effect.ANVIL_BREAK, null, 20);
if (livingEntity instanceof Player player) {
final McMMOPlayer mmoPlayer = UserManager.getPlayer(player);
boolean useChatNotification = mmoPlayer == null || mmoPlayer.useChatNotifications();
if (useChatNotification) {
NotificationManager.sendPlayerInformation(
player, NotificationType.SUBSKILL_MESSAGE, "Maces.SubSkill.Cripple.Proc");
}
}
}
private static @NotNull Location getParticleLocation(@NotNull LivingEntity livingEntity) {

View File

@ -23,8 +23,8 @@ import java.util.*;
public class SkillTools {
private final mcMMO pluginRef;
//TODO: Figure out which ones we don't need, this was copy pasted from a diff branch
// TODO: Java has immutable types now, switch to those
// TODO: Figure out which ones we don't need, this was copy pasted from a diff branch
public final @NotNull ImmutableList<String> LOCALIZED_SKILL_NAMES;
public final @NotNull ImmutableList<String> FORMATTED_SUBSKILL_NAMES;
public final @NotNull ImmutableSet<String> EXACT_SUBSKILL_NAMES;
@ -156,14 +156,28 @@ public class SkillTools {
* Build categorized skill lists
*/
COMBAT_SKILLS = ImmutableList.of(
PrimarySkillType.ARCHERY,
PrimarySkillType.AXES,
PrimarySkillType.CROSSBOWS,
PrimarySkillType.SWORDS,
PrimarySkillType.TAMING,
PrimarySkillType.TRIDENTS,
PrimarySkillType.UNARMED);
// We are in a game version with Maces
if (mcMMO.getCompatibilityManager().getMinecraftGameVersion().isAtLeast(1, 21, 0)) {
COMBAT_SKILLS = ImmutableList.of(
PrimarySkillType.ARCHERY,
PrimarySkillType.AXES,
PrimarySkillType.CROSSBOWS,
PrimarySkillType.MACES,
PrimarySkillType.SWORDS,
PrimarySkillType.TAMING,
PrimarySkillType.TRIDENTS,
PrimarySkillType.UNARMED);
} else {
// No Maces in this version
COMBAT_SKILLS = ImmutableList.of(
PrimarySkillType.ARCHERY,
PrimarySkillType.AXES,
PrimarySkillType.CROSSBOWS,
PrimarySkillType.SWORDS,
PrimarySkillType.TAMING,
PrimarySkillType.TRIDENTS,
PrimarySkillType.UNARMED);
}
GATHERING_SKILLS = ImmutableList.of(
PrimarySkillType.EXCAVATION,
PrimarySkillType.FISHING,

View File

@ -9,21 +9,54 @@ import org.bukkit.World;
import org.bukkit.entity.Player;
public class SoundManager {
public static Sound CRIPPLE_SOUND;
static {
try {
CRIPPLE_SOUND = Sound.valueOf("ITEM_MACE_SMASH_GROUND");
} catch (IllegalArgumentException e) {
CRIPPLE_SOUND = Sound.BLOCK_ANVIL_PLACE;
}
}
/**
* Sends a sound to the player
* @param soundType the type of sound
*/
public static void sendSound(Player player, Location location, SoundType soundType) {
if (SoundConfig.getInstance().getIsEnabled(soundType))
player.playSound(location, getSound(soundType), SoundCategory.MASTER, getVolume(soundType), getPitch(soundType));
player.playSound(location, getSound(soundType),
SoundCategory.MASTER, getVolume(soundType), getPitch(soundType));
}
public static void sendCategorizedSound(Player player, Location location, SoundType soundType, SoundCategory soundCategory) {
public static void sendCategorizedSound(Location location, SoundType soundType, SoundCategory soundCategory) {
if (SoundConfig.getInstance().getIsEnabled(soundType)) {
final World world = location.getWorld();
if (world != null) {
world.playSound(location, getSound(soundType), soundCategory,
getVolume(soundType), getPitch(soundType));
}
}
}
public static void sendCategorizedSound(Location location, SoundType soundType, SoundCategory soundCategory,
float pitchModifier) {
if (SoundConfig.getInstance().getIsEnabled(soundType)) {
final World world = location.getWorld();
if (world != null) {
float totalPitch = Math.min(2.0F, (getPitch(soundType) + pitchModifier));
world.playSound(location, getSound(soundType), soundCategory, getVolume(soundType), totalPitch);
}
}
}
public static void sendCategorizedSound(Player player, Location location,
SoundType soundType, SoundCategory soundCategory) {
if (SoundConfig.getInstance().getIsEnabled(soundType))
player.playSound(location, getSound(soundType), soundCategory, getVolume(soundType), getPitch(soundType));
}
public static void sendCategorizedSound(Player player, Location location, SoundType soundType, SoundCategory soundCategory, float pitchModifier) {
public static void sendCategorizedSound(Player player, Location location,
SoundType soundType, SoundCategory soundCategory, float pitchModifier) {
float totalPitch = Math.min(2.0F, (getPitch(soundType) + pitchModifier));
if (SoundConfig.getInstance().getIsEnabled(soundType))
@ -74,6 +107,7 @@ public class SoundManager {
case DEFLECT_ARROWS, BLEED -> Sound.ENTITY_ENDER_EYE_DEATH;
case GLASS -> Sound.BLOCK_GLASS_BREAK;
case ITEM_CONSUMED -> Sound.ITEM_BOTTLE_EMPTY;
case CRIPPLE -> CRIPPLE_SOUND;
};
}

View File

@ -16,6 +16,7 @@ public enum SoundType {
BLEED,
GLASS,
ITEM_CONSUMED,
CRIPPLE,
TIRED;
public boolean usesCustomPitch() {

View File

@ -633,4 +633,11 @@ Skills:
ChanceMax: 100.0
MaxBonusLevel:
Standard: 100
RetroMode: 1000
RetroMode: 1000
Maces:
Cripple:
Chance_To_Apply_On_Hit:
Rank_1: 10
Rank_2: 15
Rank_3: 20
Rank_4: 33

View File

@ -694,6 +694,7 @@ Particles:
Flux: true
Greater_Impact: true
Call_of_the_Wild: true
Cripple: true
# These settings determine if fireworks should get launched when a player levels-up,
# this will happen by default for every 100 levels.

View File

@ -458,12 +458,22 @@ Tridents.SubSkill.TridentAbility.Name=WIP
Tridents.Listener=Tridents:
#MACES
Commands.McTop.MacesNotSupported=[[GREEN]]Maces are not supported in this version of Minecraft.
Maces.SkillName=MACES
Maces.Ability.Lower=&7You lower your mace.
Maces.Ability.Ready=&3You &6ready&3 your Mace.
Maces.SubSkill.MacesLimitBreak.Name=Maces Limit Break
Maces.SubSkill.MacesLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE.
Maces.SubSkill.MacesLimitBreak.Stat=Limit Break Max DMG
Maces.SubSkill.Crush.Name=Crush
Maces.SubSkill.Crush.Description=Adds bonus damage to your attacks.
Maces.SubSkill.Crush.Stat=Crush Damage
Maces.SubSkill.Cripple.Proc=**CRIPPLED**
Maces.SubSkill.Cripple.Activated=CRIPPLED TARGET!
Maces.SubSkill.Cripple.Name=Cripple
Maces.SubSkill.Cripple.Description=Adds a chance to cripple your target.
Maces.SubSkill.Cripple.Stat=Cripple Chance
Maces.SubSkill.Cripple.Stat.Extra=[[DARK_AQUA]]Cripple Duration: &e{0}s&a vs Players, &e{1}s&a vs Mobs.
Maces.Listener=Maces:
#SWORDS
@ -899,6 +909,7 @@ Commands.XPGain.Crossbows=Attacking Monsters
Commands.XPGain.Excavation=Digging and finding treasures
Commands.XPGain.Fishing=Fishing (Go figure!)
Commands.XPGain.Herbalism=Harvesting Herbs
Commands.XPGain.Maces=Attacking Monsters
Commands.XPGain.Mining=Mining Stone & Ore
Commands.XPGain.Repair=Repairing
Commands.XPGain.Swords=Attacking Monsters
@ -1038,11 +1049,11 @@ Guides.Woodcutting.Section.1=&3How does Tree Feller work?\n&eTree Feller is an a
Guides.Woodcutting.Section.2=&3How does Leaf Blower work?\n&eLeaf Blower is a passive ability that will cause leaf\n&eblocks to break instantly when hit with an axe. By default,\n&ethis ability unlocks at level 100.
Guides.Woodcutting.Section.3=&3How do Double Drops work?\n&eThis passive ability gives you a chance to obtain an extra\n&eblock for every log you chop.
# Crossbows
Guides.Crossbows.Section.0=&3About Crossbows:\n&eCrossbows is all about shooting with your crossbow.\n\n&3XP GAIN:\n&eXP is gained whenever you shoot mobs with a crossbow.
Guides.Crossbows.Section.0=&3About Crossbows:\n&eCrossbows is all about shooting with your crossbow.\n\n&3XP GAIN:\n&eXP is gained whenever you shoot mobs with a crossbow.\nThis is a WIP skill and more information will be added soon.
Guides.Crossbows.Section.1=&3How does Trickshot work?\n&eTrickshot is an passive ability, you shoot your bolts at a shallow angle with a crossbow to attempt a Trickshot. This will cause the arrow to ricochet off of blocks and potentially hit a target. The number of potential bounces from a ricochet depend on the rank of Trickshot.
# Tridents
Guides.Tridents.Section.0=&3About Tridents:\n&eTridents skill involves impaling foes with your trident.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a trident.
Guides.Tridents.Section.0=&3About Tridents:\n&eTridents skill involves impaling foes with your trident.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a trident.\nThis is a WIP skill and more information will be added soon.
Guides.Maces.Section.0=&3About Maces:\n&eMaces is all about smashing your foes with a mace.\n\n&3XP GAIN:\n&eXP is gained whenever you hit mobs with a mace.\nThis is a WIP skill and more information will be added soon.
#INSPECT
Inspect.Offline= &cYou do not have permission to inspect offline players!

View File

@ -248,6 +248,7 @@ permissions:
mcmmo.ability.excavation.all: true
mcmmo.ability.fishing.all: true
mcmmo.ability.herbalism.all: true
mcmmo.ability.maces.all: true
mcmmo.ability.mining.all: true
mcmmo.ability.repair.all: true
mcmmo.ability.salvage.all: true
@ -479,6 +480,23 @@ permissions:
description: Allows access to the Hylian Luck ability
mcmmo.ability.herbalism.shroomthumb:
description: Allows access to the Shroom Thumb ability
mcmmo.ability.maces.*:
default: false
description: Allows access to all Maces abilities
children:
mcmmo.ability.mining.all: true
mcmmo.ability.maces.all:
description: Allows access to all Maces abilities
children:
mcmmo.ability.maces.crush: true
mcmmo.ability.maces.cripple: true
mcmmo.ability.maces.maceslimitbreak: true
mcmmo.ability.maces.maceslimitbreak:
description: Allows access to Maces Limit Break subskill
mcmmo.ability.maces.crush:
description: Allows access to the Crush ability
mcmmo.ability.maces.cripple:
description: Allows access to the Cripple ability
mcmmo.ability.mining.*:
default: false
description: Allows access to all Mining abilities
@ -870,6 +888,7 @@ permissions:
mcmmo.commands.mcscoreboard: true
mcmmo.commands.mcstats: true
mcmmo.commands.mctop.all: true
mcmmo.commands.maces: true
mcmmo.commands.mining: true
mcmmo.commands.party.all: true
mcmmo.commands.ptp.all: true
@ -1047,6 +1066,7 @@ permissions:
mcmmo.commands.mctop.excavation: true
mcmmo.commands.mctop.fishing: true
mcmmo.commands.mctop.herbalism: true
mcmmo.commands.mctop.maces: true
mcmmo.commands.mctop.mining: true
mcmmo.commands.mctop.repair: true
mcmmo.commands.mctop.salvage: true
@ -1074,6 +1094,8 @@ permissions:
description: Allows access to the mctop command for fishing
mcmmo.commands.mctop.herbalism:
description: Allows access to the mctop command for herbalism
mcmmo.commands.mctop.maces:
description: Allows access to the mctop command for maces
mcmmo.commands.mctop.mining:
description: Allows access to the mctop command for mining
mcmmo.commands.mctop.repair:
@ -1234,6 +1256,9 @@ permissions:
mcmmo.commands.skillreset.taming: true
mcmmo.commands.skillreset.unarmed: true
mcmmo.commands.skillreset.woodcutting: true
mcmmo.commands.skillreset.crossbows: true
mcmmo.commands.skillreset.tridents: true
mcmmo.commands.skillreset.maces: true
mcmmo.commands.skillreset:
description: Allows access to the skillreset command
mcmmo.commands.skillreset.acrobatics:
@ -1252,6 +1277,12 @@ permissions:
description: Allows access to the skillreset command for herbalism
mcmmo.commands.skillreset.mining:
description: Allows access to the skillreset command for mining
mcmmo.commands.skillreset.crossbows:
description: Allows access to the skillreset command for crossbows
mcmmo.commands.skillreset.tridents:
description: Allows access to the skillreset command for tridents
mcmmo.commands.skillreset.maces:
description: Allows access to the skillreset command for maces
mcmmo.commands.skillreset.others.*:
default: false
description: Implies access to all mcmmo.commands.skillreset.others permissions
@ -1276,6 +1307,9 @@ permissions:
mcmmo.commands.skillreset.others.taming: true
mcmmo.commands.skillreset.others.unarmed: true
mcmmo.commands.skillreset.others.woodcutting: true
mcmmo.commands.skillreset.others.crossbows: true
mcmmo.commands.skillreset.others.tridents: true
mcmmo.commands.skillreset.others.maces: true
mcmmo.commands.skillreset.others:
description: Allows access to the skillreset command for other players
mcmmo.commands.skillreset.others.acrobatics:
@ -1308,6 +1342,12 @@ permissions:
description: Allows access to the skillreset command for unarmed for other players
mcmmo.commands.skillreset.others.woodcutting:
description: Allows access to the skillreset command for woodcutting for other players
mcmmo.commands.skillreset.others.crossbows:
description: Allows access to the skillreset command for crossbows for other players
mcmmo.commands.skillreset.others.tridents:
description: Allows access to the skillreset command for tridents for other players
mcmmo.commands.skillreset.others.maces:
description: Allows access to the skillreset command for maces for other players
mcmmo.commands.skillreset.repair:
description: Allows access to the skillreset command for repair
mcmmo.commands.skillreset.salvage:
@ -1332,23 +1372,6 @@ permissions:
description: Allows access to the taming command
mcmmo.commands.unarmed:
description: Allows access to the unarmed command
# mcmmo.commands.vampirism.*:
# default: false
# description: Implies access to all mcmmo.commands.vampirism permissions
# children:
# mcmmo.commands.vampirism.all: true
# mcmmo.commands.vampirism.all:
# description: Implies access to all mcmmo.commands.vampirism permissions
# children:
# mcmmo.commands.vampirism: true
# mcmmo.commands.vampirism.modify: true
# mcmmo.commands.vampirism.toggle: true
# mcmmo.commands.vampirism:
# description: Allows access to the vampirism command
# mcmmo.commands.vampirism.modify:
# description: Allows access to the vampirism command to modify the vampirism rate
# mcmmo.commands.vampirism.toggle:
# description: Allows access to the vampirism command to toggle vampirism on/off
mcmmo.commands.woodcutting:
description: Allows access to the woodcutting command
mcmmo.commands.xprate.*:
@ -1482,6 +1505,7 @@ permissions:
mcmmo.perks.lucky.excavation: true
mcmmo.perks.lucky.fishing: true
mcmmo.perks.lucky.herbalism: true
mcmmo.perks.lucky.maces: true
mcmmo.perks.lucky.mining: true
mcmmo.perks.lucky.repair: true
mcmmo.perks.lucky.salvage: true
@ -1490,6 +1514,8 @@ permissions:
mcmmo.perks.lucky.taming: true
mcmmo.perks.lucky.unarmed: true
mcmmo.perks.lucky.woodcutting: true
mcmmo.perks.lucky.crossbows: true
mcmmo.perks.lucky.tridents: true
mcmmo.perks.lucky.acrobatics:
default: false
description: Gives Acrobatics abilities & skills a 33.3% better chance to activate.
@ -1514,6 +1540,9 @@ permissions:
mcmmo.perks.lucky.herbalism:
default: false
description: Gives Herbalism abilities & skills a 33.3% better chance to activate.
mcmmo.perks.lucky.maces:
default: false
description: Gives Mining abilities & skills a 33.3% better chance to activate.
mcmmo.perks.lucky.mining:
default: false
description: Gives Mining abilities & skills a 33.3% better chance to activate.
@ -1580,6 +1609,7 @@ permissions:
mcmmo.perks.xp.150percentboost.excavation: true
mcmmo.perks.xp.150percentboost.fishing: true
mcmmo.perks.xp.150percentboost.herbalism: true
mcmmo.perks.xp.150percentboost.maces: true
mcmmo.perks.xp.150percentboost.mining: true
mcmmo.perks.xp.150percentboost.repair: true
mcmmo.perks.xp.150percentboost.smelting: true
@ -1612,6 +1642,9 @@ permissions:
mcmmo.perks.xp.150percentboost.herbalism:
default: false
description: Multiplies incoming Herbalism XP by 2.5
mcmmo.perks.xp.150percentboost.maces:
default: false
description: Multiplies incoming Maces XP by 2.5
mcmmo.perks.xp.150percentboost.mining:
default: false
description: Multiplies incoming Mining XP by 2.5
@ -1658,6 +1691,7 @@ permissions:
mcmmo.perks.xp.50percentboost.excavation: true
mcmmo.perks.xp.50percentboost.fishing: true
mcmmo.perks.xp.50percentboost.herbalism: true
mcmmo.perks.xp.50percentboost.maces: true
mcmmo.perks.xp.50percentboost.mining: true
mcmmo.perks.xp.50percentboost.repair: true
mcmmo.perks.xp.50percentboost.smelting: true
@ -1690,6 +1724,9 @@ permissions:
mcmmo.perks.xp.50percentboost.herbalism:
default: false
description: Multiplies incoming Herbalism XP by 1.5
mcmmo.perks.xp.50percentboost.maces:
default: false
description: Multiplies incoming Maces XP by 1.5
mcmmo.perks.xp.50percentboost.mining:
default: false
description: Multiplies incoming Mining XP by 1.5
@ -1736,6 +1773,7 @@ permissions:
mcmmo.perks.xp.25percentboost.excavation: true
mcmmo.perks.xp.25percentboost.fishing: true
mcmmo.perks.xp.25percentboost.herbalism: true
mcmmo.perks.xp.25percentboost.maces: true
mcmmo.perks.xp.25percentboost.mining: true
mcmmo.perks.xp.25percentboost.repair: true
mcmmo.perks.xp.25percentboost.smelting: true
@ -1768,6 +1806,9 @@ permissions:
mcmmo.perks.xp.25percentboost.herbalism:
default: false
description: Multiplies incoming Herbalism XP by 1.25
mcmmo.perks.xp.25percentboost.maces:
default: false
description: Multiplies incoming Maces XP by 1.25
mcmmo.perks.xp.25percentboost.mining:
default: false
description: Multiplies incoming Mining XP by 1.25
@ -1814,6 +1855,7 @@ permissions:
mcmmo.perks.xp.10percentboost.excavation: true
mcmmo.perks.xp.10percentboost.fishing: true
mcmmo.perks.xp.10percentboost.herbalism: true
mcmmo.perks.xp.10percentboost.maces: true
mcmmo.perks.xp.10percentboost.mining: true
mcmmo.perks.xp.10percentboost.repair: true
mcmmo.perks.xp.10percentboost.smelting: true
@ -1846,6 +1888,9 @@ permissions:
mcmmo.perks.xp.10percentboost.herbalism:
default: false
description: Multiplies incoming Herbalism XP by 1.1
mcmmo.perks.xp.10percentboost.maces:
default: false
description: Multiplies incoming Maces XP by 1.1
mcmmo.perks.xp.10percentboost.mining:
default: false
description: Multiplies incoming Mining XP by 1.1
@ -1892,6 +1937,7 @@ permissions:
mcmmo.perks.xp.customboost.excavation: true
mcmmo.perks.xp.customboost.fishing: true
mcmmo.perks.xp.customboost.herbalism: true
mcmmo.perks.xp.customboost.maces: true
mcmmo.perks.xp.customboost.mining: true
mcmmo.perks.xp.customboost.repair: true
mcmmo.perks.xp.customboost.smelting: true
@ -1924,6 +1970,9 @@ permissions:
mcmmo.perks.xp.customboost.herbalism:
default: false
description: Multiplies incoming Herbalism XP by the boost amount defined in the experience config
mcmmo.perks.xp.customboost.maces:
default: false
description: Multiplies incoming Maces XP by the boost amount defined in the experience config
mcmmo.perks.xp.customboost.mining:
default: false
description: Multiplies incoming Mining XP by the boost amount defined in the experience config
@ -1970,6 +2019,7 @@ permissions:
mcmmo.perks.xp.double.excavation: true
mcmmo.perks.xp.double.fishing: true
mcmmo.perks.xp.double.herbalism: true
mcmmo.perks.xp.double.maces: true
mcmmo.perks.xp.double.mining: true
mcmmo.perks.xp.double.repair: true
mcmmo.perks.xp.double.smelting: true
@ -2002,6 +2052,9 @@ permissions:
mcmmo.perks.xp.double.herbalism:
default: false
description: Doubles incoming Herbalism XP
mcmmo.perks.xp.double.maces:
default: false
description: Doubles incoming Maces XP
mcmmo.perks.xp.double.mining:
default: false
description: Doubles incoming Mining XP
@ -2048,6 +2101,7 @@ permissions:
mcmmo.perks.xp.quadruple.excavation: true
mcmmo.perks.xp.quadruple.fishing: true
mcmmo.perks.xp.quadruple.herbalism: true
mcmmo.perks.xp.quadruple.maces: true
mcmmo.perks.xp.quadruple.mining: true
mcmmo.perks.xp.quadruple.repair: true
mcmmo.perks.xp.quadruple.smelting: true
@ -2080,6 +2134,9 @@ permissions:
mcmmo.perks.xp.quadruple.herbalism:
default: false
description: Quadruples incoming Herbalism XP
mcmmo.perks.xp.quadruple.maces:
default: false
description: Quadruples incoming Maces XP
mcmmo.perks.xp.quadruple.mining:
default: false
description: Quadruples incoming Mining XP
@ -2127,6 +2184,7 @@ permissions:
mcmmo.perks.xp.triple.fishing: true
mcmmo.perks.xp.triple.herbalism: true
mcmmo.perks.xp.triple.mining: true
mcmmo.perks.xp.triple.maces: true
mcmmo.perks.xp.triple.repair: true
mcmmo.perks.xp.triple.smelting: true
mcmmo.perks.xp.triple.swords: true
@ -2158,6 +2216,9 @@ permissions:
mcmmo.perks.xp.triple.herbalism:
default: false
description: Triples incoming Herbalism XP
mcmmo.perks.xp.triple.maces:
default: false
description: Triples incoming Maces XP
mcmmo.perks.xp.triple.mining:
default: false
description: Triples incoming Mining XP
@ -2203,6 +2264,7 @@ permissions:
mcmmo.skills.excavation: true
mcmmo.skills.fishing: true
mcmmo.skills.herbalism: true
mcmmo.skill.maces: true
mcmmo.skills.mining: true
mcmmo.skills.repair: true
mcmmo.skills.salvage: true
@ -2283,6 +2345,11 @@ permissions:
children:
mcmmo.ability.taming.all: true
mcmmo.commands.taming: true
mcmmo.skills.maces:
description: Allows access to the Maces skill
children:
mcmmo.ability.maces.all: true
mcmmo.commands.maces: true
mcmmo.skills.tridents:
description: Allows access to the Tridents skill
children:

View File

@ -284,4 +284,12 @@ Repairables:
ItemMaterialCategory: OTHER
RepairMaterial: PRISMARINE_CRYSTALS
MinimumQuantity: 16
MaximumDurability: 250
MACE:
MinimumLevel: 0
XpMultiplier: 3
ItemType: TOOL
ItemMaterialCategory: OTHER
RepairMaterial: BREEZE_ROD
MinimumQuantity: 4
MaximumDurability: 250

View File

@ -444,28 +444,51 @@ Salvage:
Rank_7: 850
Rank_8: 1000
Maces:
Standard:
Rank_1: 10
Rank_2: 20
Rank_3: 30
Rank_4: 40
Rank_5: 50
Rank_6: 60
Rank_7: 70
Rank_8: 80
Rank_9: 90
Rank_10: 100
RetroMode:
Rank_1: 100
Rank_2: 200
Rank_3: 300
Rank_4: 400
Rank_5: 500
Rank_6: 600
Rank_7: 700
Rank_8: 800
Rank_9: 900
Rank_10: 1000
MacesLimitBreak:
Standard:
Rank_1: 10
Rank_2: 20
Rank_3: 30
Rank_4: 40
Rank_5: 50
Rank_6: 60
Rank_7: 70
Rank_8: 80
Rank_9: 90
Rank_10: 100
RetroMode:
Rank_1: 100
Rank_2: 200
Rank_3: 300
Rank_4: 400
Rank_5: 500
Rank_6: 600
Rank_7: 700
Rank_8: 800
Rank_9: 900
Rank_10: 1000
Cripple:
Standard:
Rank_1: 5
Rank_2: 20
Rank_3: 40
Rank_4: 80
RetroMode:
Rank_1: 50
Rank_2: 200
Rank_3: 400
Rank_4: 800
Crush:
Standard:
Rank_1: 10
Rank_2: 25
Rank_3: 75
Rank_4: 90
RetroMode:
Rank_1: 100
Rank_2: 250
Rank_3: 750
Rank_4: 900
Mining:
MotherLode:
Standard:

View File

@ -67,4 +67,8 @@ Sounds:
BLEED:
Enable: true
Volume: 2.0
Pitch: 2.0
Pitch: 2.0
CRIPPLE:
Enable: true
Volume: 1.0
Pitch: 0.5