Introduction of new Alchemy skill!

This commit is contained in:
Eric Hildebrand
2013-11-15 18:21:00 -05:00
committed by TfT_02
parent 9afa8efd7d
commit 8f83e328b0
32 changed files with 2194 additions and 21 deletions

View File

@ -0,0 +1,99 @@
package com.gmail.nossr50.commands.skills;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.entity.Player;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.skills.alchemy.Alchemy.Tier;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.player.UserManager;
public class AlchemyCommand extends SkillCommand {
private String brewSpeed;
private String brewSpeedLucky;
private int tier;
private int ingredientCount;
private String ingredientList;
private boolean canCatalysis;
private boolean canConcoctions;
public AlchemyCommand() {
super(SkillType.ALCHEMY);
}
protected String[] calculateAbilityDisplayValues(Player player, float skillValue, boolean isLucky) {
String[] displayValues = new String[2];
displayValues[0] = decimal.format(UserManager.getPlayer(player).getAlchemyManager().getBrewSpeed()) + "x";
displayValues[1] = isLucky ? decimal.format(UserManager.getPlayer(player).getAlchemyManager().getBrewSpeedLucky()) + "x" : null;
return displayValues;
}
@Override
protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
// CATALYSIS
if (canCatalysis) {
String[] catalysisStrings = calculateAbilityDisplayValues(player, skillValue, isLucky);
brewSpeed = catalysisStrings[0];
brewSpeedLucky = catalysisStrings[1];
}
// CONCOCTIONS
if (canConcoctions) {
tier = UserManager.getPlayer(player).getAlchemyManager().getTier();
ingredientCount = UserManager.getPlayer(player).getAlchemyManager().getIngredients().size();
ingredientList = UserManager.getPlayer(player).getAlchemyManager().getIngredientList();
}
}
@Override
protected void permissionsCheck(Player player) {
canCatalysis = Permissions.catalysis(player);
canConcoctions = Permissions.concoctions(player);
}
@Override
protected List<String> effectsDisplay() {
List<String> messages = new ArrayList<String>();
if (canCatalysis) {
messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Alchemy.Effect.0"), LocaleLoader.getString("Alchemy.Effect.1")));
}
if (canConcoctions) {
messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Alchemy.Effect.2"), LocaleLoader.getString("Alchemy.Effect.3")));
}
return messages;
}
@Override
protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
List<String> messages = new ArrayList<String>();
if (canCatalysis) {
int unlockLevel = AdvancedConfig.getInstance().getCatalysisUnlockLevel();
if (skillValue < unlockLevel) {
messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Alchemy.Ability.Locked.0", unlockLevel)));
}
else {
messages.add(LocaleLoader.getString("Alchemy.Catalysis.Speed", brewSpeed) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", brewSpeedLucky) : ""));
}
}
if (canConcoctions) {
messages.add(LocaleLoader.getString("Alchemy.Concoctions.Rank", tier, Tier.values().length));
messages.add(LocaleLoader.getString("Alchemy.Concoctions.Ingredients", ingredientCount, ingredientList));
}
return messages;
}
}

View File

@ -6,6 +6,7 @@ import java.util.List;
import com.gmail.nossr50.datatypes.skills.SecondaryAbility;
import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.skills.alchemy.Alchemy;
import com.gmail.nossr50.skills.fishing.Fishing;
import com.gmail.nossr50.skills.mining.BlastMining;
import com.gmail.nossr50.skills.repair.ArcaneForging;
@ -79,6 +80,38 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
reason.add("Skills.Acrobatics.GracefulRoll.DamageThreshold should be at least 0!");
}
/* ALCHEMY */
if (getCatalysisUnlockLevel() < 0) {
reason.add("Skills.Alchemy.Catalysis.UnlockLevel should be at least 0!");
}
if (getCatalysisMaxBonusLevel() <= getCatalysisUnlockLevel()) {
reason.add("Skills.Alchemy.Catalysis.MaxBonusLevel should be greater than Skills.Alchemy.Catalysis.UnlockLevel!");
}
if (getCatalysisMinSpeed() <= 0) {
reason.add("Skills.Alchemy.Catalysis.MinSpeed must be greater than 0!");
}
if (getCatalysisMaxSpeed() < getCatalysisMinSpeed()) {
reason.add("Skills.Alchemy.Catalysis.MaxSpeed should be at least Skills.Alchemy.Catalysis.MinSpeed!");
}
List<Alchemy.Tier> alchemyTierList = Arrays.asList(Alchemy.Tier.values());
for (Alchemy.Tier tier : alchemyTierList) {
if (getConcoctionsTierLevel(tier) < 0) {
reason.add("Skills.Alchemy.Rank_Levels.Rank_" + tier.toNumerical() + " should be at least 0!");
}
if (tier != Alchemy.Tier.fromNumerical(Alchemy.Tier.values().length)) {
Alchemy.Tier nextTier = alchemyTierList.get(alchemyTierList.indexOf(tier) - 1);
if (getConcoctionsTierLevel(tier) >= getConcoctionsTierLevel(nextTier)) {
reason.add("Skills.Alchemy.Rank_Levels.Rank_" + tier.toNumerical() + " should be less than Skills.Alchemy.Rank_Levels.Rank_" + nextTier.toNumerical() + "!");
}
}
}
/* ARCHERY */
if (getSkillShotIncreaseLevel() < 1) {
reason.add("Skills.Archery.SkillShot.IncreaseLevel should be at least 1!");
@ -624,6 +657,14 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
public double getGracefulRollDamageThreshold() { return config.getDouble("Skills.Acrobatics.GracefulRoll.DamageThreshold", 14.0D); }
/* ALCHEMY */
public int getCatalysisUnlockLevel() { return config.getInt("Skills.Alchemy.Catalysis.UnlockLevel", 100); }
public int getCatalysisMaxBonusLevel() { return config.getInt("Skills.Alchemy.Catalysis.MaxBonusLevel", 1000); }
public double getCatalysisMinSpeed() { return config.getDouble("Skills.Alchemy.Catalysis.MinSpeed", 1.0D); }
public double getCatalysisMaxSpeed() { return config.getDouble("Skills.Alchemy.Catalysis.MaxSpeed", 4.0D); }
public int getConcoctionsTierLevel(Alchemy.Tier tier) { return config.getInt("Skills.Alchemy.Rank_Levels.Rank_" + tier.toNumerical()); }
/* ARCHERY */
public int getSkillShotIncreaseLevel() { return config.getInt("Skills.Archery.SkillShot.IncreaseLevel", 50); }
public double getSkillShotIncreasePercentage() { return config.getDouble("Skills.Archery.SkillShot.IncreasePercentage", 0.1D); }

View File

@ -403,6 +403,10 @@ public class Config extends AutoUpdateConfigLoader {
public boolean getDodgeLightningDisabled() { return config.getBoolean("Skills.Acrobatics.Prevent_Dodge_Lightning", false); }
public boolean getPreventXPAfterTeleport() { return config.getBoolean("Skills.Acrobatics.Prevent_XP_After_Teleport", true); }
/* Alchemy */
public boolean getEnabledForHoppers() { return config.getBoolean("Skills.Alchemy.Enabled_for_Hoppers", true); }
public boolean getPreventHopperTransfer() { return config.getBoolean("Skills.Alchemy.Prevent_Hopper_Transfer", false); }
/* Fishing */
public boolean getFishingDropsEnabled() { return config.getBoolean("Skills.Fishing.Drops_Enabled", true); }

View File

@ -76,6 +76,11 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
* XP SETTINGS
*/
/* Alchemy */
if (getPotionXP() <= 0) {
reason.add("Experience.Alchemy.Potion should be greater than 0!");
}
/* Combat XP Multipliers */
if (getAnimalsXP() < 0) {
reason.add("Experience.Combat.Multiplier.Animals should be at least 0!");
@ -199,6 +204,9 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
public double getFeatherFallXPModifier() { return config.getDouble("Experience.Acrobatics.FeatherFall_Multiplier", 2.0); }
/* Alchemy */
public double getPotionXP() { return config.getDouble("Experience.Alchemy.Potion", 150D); }
/* Fishing */
public int getFishingBaseXP() { return config.getInt("Experience.Fishing.Base", 800); }
public int getFishingShakeXP() { return config.getInt("Experience.Fishing.Shake", 50); }

View File

@ -0,0 +1,188 @@
package com.gmail.nossr50.config.potion;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.config.ConfigLoader;
import com.gmail.nossr50.datatypes.AlchemyPotion;
public class PotionConfig extends ConfigLoader {
private static PotionConfig instance;
public List<ItemStack> concoctionsIngredientsTierOne = new ArrayList<ItemStack>();
public List<ItemStack> concoctionsIngredientsTierTwo = new ArrayList<ItemStack>();
public List<ItemStack> concoctionsIngredientsTierThree = new ArrayList<ItemStack>();
public List<ItemStack> concoctionsIngredientsTierFour = new ArrayList<ItemStack>();
public List<ItemStack> concoctionsIngredientsTierFive = new ArrayList<ItemStack>();
public List<ItemStack> concoctionsIngredientsTierSix = new ArrayList<ItemStack>();
public List<ItemStack> concoctionsIngredientsTierSeven = new ArrayList<ItemStack>();
public List<ItemStack> concoctionsIngredientsTierEight = new ArrayList<ItemStack>();
public Map<Short, AlchemyPotion> potionMap = new HashMap<Short, AlchemyPotion>();
private PotionConfig() {
super("potions.yml");
loadKeys();
}
public static PotionConfig getInstance() {
if (instance == null) {
instance = new PotionConfig();
}
return instance;
}
@Override
protected void loadKeys() {
loadConcoctions();
loadPotionMap();
}
private void loadConcoctions() {
ConfigurationSection concoctionSection = config.getConfigurationSection("Concoctions");
loadConcoctionsTier(concoctionsIngredientsTierOne, concoctionSection.getStringList("Tier_One_Ingredients"));
loadConcoctionsTier(concoctionsIngredientsTierTwo, concoctionSection.getStringList("Tier_Two_Ingredients"));
loadConcoctionsTier(concoctionsIngredientsTierThree, concoctionSection.getStringList("Tier_Three_Ingredients"));
loadConcoctionsTier(concoctionsIngredientsTierFour, concoctionSection.getStringList("Tier_Four_Ingredients"));
loadConcoctionsTier(concoctionsIngredientsTierFive, concoctionSection.getStringList("Tier_Five_Ingredients"));
loadConcoctionsTier(concoctionsIngredientsTierSix, concoctionSection.getStringList("Tier_Six_Ingredients"));
loadConcoctionsTier(concoctionsIngredientsTierSeven, concoctionSection.getStringList("Tier_Seven_Ingredients"));
loadConcoctionsTier(concoctionsIngredientsTierEight, concoctionSection.getStringList("Tier_Eight_Ingredients"));
concoctionsIngredientsTierTwo.addAll(concoctionsIngredientsTierOne);
concoctionsIngredientsTierThree.addAll(concoctionsIngredientsTierTwo);
concoctionsIngredientsTierFour.addAll(concoctionsIngredientsTierThree);
concoctionsIngredientsTierFive.addAll(concoctionsIngredientsTierFour);
concoctionsIngredientsTierSix.addAll(concoctionsIngredientsTierFive);
concoctionsIngredientsTierSeven.addAll(concoctionsIngredientsTierSix);
concoctionsIngredientsTierEight.addAll(concoctionsIngredientsTierSeven);
}
private void loadConcoctionsTier(List<ItemStack> ingredientList, List<String> ingredientStrings) {
if (ingredientStrings != null && ingredientStrings.size() > 0) {
for (String ingredientString : ingredientStrings) {
ItemStack ingredient = loadIngredient(ingredientString);
if (ingredient != null) {
ingredientList.add(ingredient);
}
}
}
}
/**
* Find the Potions configuration section and load all defined potions.
*/
private void loadPotionMap() {
ConfigurationSection potionSection = config.getConfigurationSection("Potions");
int pass = 0;
int fail = 0;
for (String dataValue : potionSection.getKeys(false)) {
AlchemyPotion potion = loadPotion(potionSection.getConfigurationSection(dataValue));
if (potion != null) {
potionMap.put(potion.getDataValue(), potion);
pass++;
}
else {
fail++;
}
}
mcMMO.p.getLogger().info("Loaded " + pass + " Alchemy potions, skipped " + fail + ".");
}
/**
* Parse a ConfigurationSection representing a AlchemyPotion.
* Returns null if input cannot be parsed.
*
* @param potion_section ConfigurationSection to be parsed.
* @return Parsed AlchemyPotion.
*/
private AlchemyPotion loadPotion(ConfigurationSection potion_section) {
try {
short dataValue = Short.parseShort(potion_section.getName());
String name = potion_section.getString("Name");
List<String> lore = new ArrayList<String>();
if (potion_section.contains("Lore")) {
for (String line : potion_section.getStringList("Lore")) {
lore.add(line);
}
}
List<PotionEffect> effects = new ArrayList<PotionEffect>();
if (potion_section.contains("Effects")) {
for (String effect : potion_section.getStringList("Effects")) {
String[] parts = effect.split(" ");
PotionEffectType type = parts.length > 0 ? PotionEffectType.getByName(parts[0]) : null;
int amplifier = parts.length > 1 ? Integer.parseInt(parts[1]) : 0;
int duration = parts.length > 2 ? Integer.parseInt(parts[2]) : 0;
if (type != null) {
effects.add(new PotionEffect(type, duration, amplifier));
}
else {
mcMMO.p.getLogger().warning("Failed to parse effect for potion " + name + ": " + effect);
}
}
}
Map<ItemStack, Short> children = new HashMap<ItemStack, Short>();
if (potion_section.contains("Children")) {
for (String child : potion_section.getConfigurationSection("Children").getKeys(false)) {
ItemStack ingredient = loadIngredient(child);
if (ingredient != null) {
children.put(ingredient, Short.parseShort(potion_section.getConfigurationSection("Children").getString(child)));
}
else {
mcMMO.p.getLogger().warning("Failed to parse child for potion " + name + ": " + child);
}
}
}
return new AlchemyPotion(dataValue, name, lore, effects, children);
}
catch (Exception e) {
mcMMO.p.getLogger().warning("Failed to load Alchemy potion: " + potion_section.getName());
return null;
}
}
/**
* Parse a string representation of an ingredient.
* Format: '&lt;MATERIAL&gt;[:data]'
* Returns null if input cannot be parsed.
*
* @param ingredient String representing an ingredient.
* @return Parsed ingredient.
*/
private ItemStack loadIngredient(String ingredient) {
if (ingredient == null || ingredient.isEmpty()) {
return null;
}
String[] parts = ingredient.split(":");
Material material = parts.length > 0 ? Material.getMaterial(parts[0]) : null;
short data = parts.length > 1 ? Short.parseShort(parts[1]) : 0;
if (material != null) {
return new ItemStack(material, 1, data);
}
return null;
}
}

View File

@ -265,6 +265,8 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
writer.append(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR).append(":");
MobHealthbarType mobHealthbarType = profile.getMobHealthbarType();
writer.append(mobHealthbarType == null ? Config.getInstance().getMobHealthbarDefault().toString() : mobHealthbarType.toString()).append(":");
writer.append(profile.getSkillLevel(SkillType.ALCHEMY)).append(":");
writer.append(profile.getSkillXpLevel(SkillType.ALCHEMY)).append(":");
writer.append("\r\n");
}
}
@ -354,7 +356,9 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
out.append("0:"); // Blast Mining
out.append(String.valueOf(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR)).append(":"); // LastLogin
out.append(Config.getInstance().getMobHealthbarDefault().toString()).append(":"); // Mob Healthbar HUD
out.append("0:"); // Alchemy
out.append("0:"); // AlchemyXp
// Add more in the same format as the line above
out.newLine();
@ -503,6 +507,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
List<PlayerStat> unarmed = new ArrayList<PlayerStat>();
List<PlayerStat> taming = new ArrayList<PlayerStat>();
List<PlayerStat> fishing = new ArrayList<PlayerStat>();
List<PlayerStat> alchemy = new ArrayList<PlayerStat>();
BufferedReader in = null;
String playerName = null;
@ -520,6 +525,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
Map<SkillType, Integer> skills = getSkillMapFromLine(data);
powerLevel += putStat(acrobatics, playerName, skills.get(SkillType.ACROBATICS));
powerLevel += putStat(alchemy, playerName, skills.get(SkillType.ALCHEMY));
powerLevel += putStat(archery, playerName, skills.get(SkillType.ARCHERY));
powerLevel += putStat(axes, playerName, skills.get(SkillType.AXES));
powerLevel += putStat(excavation, playerName, skills.get(SkillType.EXCAVATION));
@ -557,6 +563,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
Collections.sort(acrobatics, c);
Collections.sort(taming, c);
Collections.sort(fishing, c);
Collections.sort(alchemy, c);
Collections.sort(powerLevels, c);
playerStatHash.put(SkillType.MINING, mining);
@ -571,6 +578,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
playerStatHash.put(SkillType.ACROBATICS, acrobatics);
playerStatHash.put(SkillType.TAMING, taming);
playerStatHash.put(SkillType.FISHING, fishing);
playerStatHash.put(SkillType.ALCHEMY, alchemy);
}
/**
@ -623,7 +631,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
}
// If they're valid, rewrite them to the file.
if (character.length > 38) {
if (character.length > 40) {
writer.append(line).append("\r\n");
continue;
}
@ -675,6 +683,15 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
oldVersion = "1.4.06";
}
}
if (character.length <= 40) {
// Addition of Alchemy
// Version 1.4.08
newLine.append("0").append(":");
newLine.append("0").append(":");
if (oldVersion == null) {
oldVersion = "1.4.08";
}
}
if (oldVersion != null) {
mcMMO.p.debug("Updating database line for player " + character[0] + " from before version " + oldVersion);
@ -771,6 +788,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
skillsXp.put(SkillType.AXES, (float) Integer.valueOf(character[21]));
skillsXp.put(SkillType.ACROBATICS, (float) Integer.valueOf(character[22]));
skillsXp.put(SkillType.FISHING, (float) Integer.valueOf(character[35]));
skillsXp.put(SkillType.ALCHEMY, (float) Integer.valueOf(character[40]));
// Taming - Unused
skillsDATS.put(AbilityType.SUPER_BREAKER, Integer.valueOf(character[32]));
@ -810,6 +828,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
skills.put(SkillType.AXES, Integer.valueOf(character[13]));
skills.put(SkillType.ACROBATICS, Integer.valueOf(character[14]));
skills.put(SkillType.FISHING, Integer.valueOf(character[34]));
skills.put(SkillType.ALCHEMY, Integer.valueOf(character[39]));
return skills;
}

View File

@ -152,7 +152,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
+ " taming = ?, mining = ?, repair = ?, woodcutting = ?"
+ ", unarmed = ?, herbalism = ?, excavation = ?"
+ ", archery = ?, swords = ?, axes = ?, acrobatics = ?"
+ ", fishing = ? WHERE user_id = ?",
+ ", fishing = ?, alchemy = ? WHERE user_id = ?",
profile.getSkillLevel(SkillType.TAMING),
profile.getSkillLevel(SkillType.MINING),
profile.getSkillLevel(SkillType.REPAIR),
@ -165,13 +165,14 @@ public final class SQLDatabaseManager implements DatabaseManager {
profile.getSkillLevel(SkillType.AXES),
profile.getSkillLevel(SkillType.ACROBATICS),
profile.getSkillLevel(SkillType.FISHING),
profile.getSkillLevel(SkillType.ALCHEMY),
userId);
success &= saveIntegers(
"UPDATE " + tablePrefix + "experience SET "
+ " taming = ?, mining = ?, repair = ?, woodcutting = ?"
+ ", unarmed = ?, herbalism = ?, excavation = ?"
+ ", archery = ?, swords = ?, axes = ?, acrobatics = ?"
+ ", fishing = ? WHERE user_id = ?",
+ ", fishing = ?, alchemy = ? WHERE user_id = ?",
profile.getSkillXpLevel(SkillType.TAMING),
profile.getSkillXpLevel(SkillType.MINING),
profile.getSkillXpLevel(SkillType.REPAIR),
@ -184,6 +185,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
profile.getSkillXpLevel(SkillType.AXES),
profile.getSkillXpLevel(SkillType.ACROBATICS),
profile.getSkillXpLevel(SkillType.FISHING),
profile.getSkillXpLevel(SkillType.ALCHEMY),
userId);
return success;
}
@ -192,7 +194,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
List<PlayerStat> stats = new ArrayList<PlayerStat>();
if (checkConnected()) {
String query = skill == null ? "taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing" : skill.name().toLowerCase();
String query = skill == null ? "taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy" : skill.name().toLowerCase();
ResultSet resultSet = null;
PreparedStatement statement = null;
@ -271,9 +273,9 @@ public final class SQLDatabaseManager implements DatabaseManager {
}
String sql = "SELECT COUNT(*) AS rank FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " +
"WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing > 0 " +
"AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing > " +
"(SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing " +
"WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > 0 " +
"AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > " +
"(SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " +
"FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE user = ?)";
PreparedStatement statement = connection.prepareStatement(sql);
@ -286,11 +288,11 @@ public final class SQLDatabaseManager implements DatabaseManager {
statement.close();
sql = "SELECT user, taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing " +
sql = "SELECT user, taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " +
"FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " +
"WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing > 0 " +
"AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing = " +
"(SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing " +
"WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > 0 " +
"AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy = " +
"(SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " +
"FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE user = ?) ORDER BY user";
statement = connection.prepareStatement(sql);
@ -359,8 +361,8 @@ public final class SQLDatabaseManager implements DatabaseManager {
try {
statement = connection.prepareStatement(
"SELECT "
+ "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, "
+ "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, "
+ "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, "
+ "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, "
+ "c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, "
+ "h.mobhealthbar "
+ "FROM " + tablePrefix + "users u "
@ -435,8 +437,8 @@ public final class SQLDatabaseManager implements DatabaseManager {
try {
statement = connection.prepareStatement(
"SELECT "
+ "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, "
+ "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, "
+ "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, "
+ "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, "
+ "c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, "
+ "h.mobhealthbar "
+ "FROM " + tablePrefix + "users u "
@ -687,6 +689,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
+ "`axes` int(10) unsigned NOT NULL DEFAULT '0',"
+ "`acrobatics` int(10) unsigned NOT NULL DEFAULT '0',"
+ "`fishing` int(10) unsigned NOT NULL DEFAULT '0',"
+ "`alchemy` int(10) unsigned NOT NULL DEFAULT '0',"
+ "PRIMARY KEY (`user_id`)) "
+ "DEFAULT CHARSET=latin1;");
write("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "experience` ("
@ -703,6 +706,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
+ "`axes` int(10) unsigned NOT NULL DEFAULT '0',"
+ "`acrobatics` int(10) unsigned NOT NULL DEFAULT '0',"
+ "`fishing` int(10) unsigned NOT NULL DEFAULT '0',"
+ "`alchemy` int(10) unsigned NOT NULL DEFAULT '0',"
+ "PRIMARY KEY (`user_id`)) "
+ "DEFAULT CHARSET=latin1;");
@ -728,6 +732,10 @@ public final class SQLDatabaseManager implements DatabaseManager {
sql = "SELECT * FROM `" + tablePrefix + "experience` ORDER BY `" + tablePrefix + "experience`.`fishing` ASC LIMIT 0 , 30";
break;
case ALCHEMY:
sql = "SELECT * FROM `" + tablePrefix + "experience` ORDER BY `" + tablePrefix + "experience`.`alchemy` ASC LIMIT 0 , 30";
break;
case INDEX:
if (read("SHOW INDEX FROM " + tablePrefix + "skills").size() != 13 && checkConnected()) {
mcMMO.p.getLogger().info("Indexing tables, this may take a while on larger databases");
@ -830,6 +838,12 @@ public final class SQLDatabaseManager implements DatabaseManager {
write("ALTER TABLE `" + tablePrefix + "huds` ADD `mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "' ;");
break;
case ALCHEMY:
mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Alchemy...");
write("ALTER TABLE `"+tablePrefix + "skills` ADD `alchemy` int(10) NOT NULL DEFAULT '0' ;");
write("ALTER TABLE `"+tablePrefix + "experience` ADD `alchemy` int(10) NOT NULL DEFAULT '0' ;");
break;
default:
break;
}
@ -1199,6 +1213,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
skills.put(SkillType.AXES, result.getInt(OFFSET_SKILLS + 10));
skills.put(SkillType.ACROBATICS, result.getInt(OFFSET_SKILLS + 11));
skills.put(SkillType.FISHING, result.getInt(OFFSET_SKILLS + 12));
skills.put(SkillType.ALCHEMY, result.getInt(OFFSET_SKILLS + 13));
skillsXp.put(SkillType.TAMING, result.getFloat(OFFSET_XP + 1));
skillsXp.put(SkillType.MINING, result.getFloat(OFFSET_XP + 2));
@ -1212,6 +1227,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
skillsXp.put(SkillType.AXES, result.getFloat(OFFSET_XP + 10));
skillsXp.put(SkillType.ACROBATICS, result.getFloat(OFFSET_XP + 11));
skillsXp.put(SkillType.FISHING, result.getFloat(OFFSET_XP + 12));
skillsXp.put(SkillType.ALCHEMY, result.getFloat(OFFSET_XP + 13));
// Taming - Unused - result.getInt(OFFSET_DATS + 1)
skillsDATS.put(AbilityType.SUPER_BREAKER, result.getInt(OFFSET_DATS + 2));

View File

@ -0,0 +1,101 @@
package com.gmail.nossr50.datatypes;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;
public class AlchemyPotion {
private short dataValue;
private String name;
private List<String> lore;
private List<PotionEffect> effects;
private Map<ItemStack, Short> children;
public AlchemyPotion(short dataValue, String name, List<String> lore, List<PotionEffect> effects, Map<ItemStack, Short> children) {
this.dataValue = dataValue;
this.lore = lore;
this.name = name;
this.effects = effects;
this.children = children;
}
public String toString() {
return "AlchemyPotion{" + dataValue + "," + name + ",Effects[" + effects.size() + "], Children[" + children.size() + "]}";
}
public ItemStack toItemStack() {
return toItemStack(1);
}
public ItemStack toItemStack(int amount) {
ItemStack potion = new ItemStack(Material.POTION, amount, this.getDataValue());
PotionMeta meta = (PotionMeta) potion.getItemMeta();
meta.setDisplayName(this.getName());
if (this.getLore() != null && !this.getLore().isEmpty()) {
meta.setLore(this.getLore());
}
if (!this.getEffects().isEmpty()) {
for (PotionEffect effect : this.getEffects()) {
meta.addCustomEffect(effect, true);
}
}
potion.setItemMeta(meta);
return potion;
}
public short getDataValue() {
return dataValue;
}
public void setDataValue(short data_value) {
this.dataValue = data_value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getLore() {
return lore;
}
public void setLore(List<String> lore) {
this.lore = lore;
}
public List<PotionEffect> getEffects() {
return effects;
}
public void setEffects(List<PotionEffect> effects) {
this.effects = effects;
}
public Map<ItemStack, Short> getChildren() {
return children;
}
public void setChildren(Map<ItemStack, Short> children) {
this.children = children;
}
public Short getChildDataValue(ItemStack ingredient) {
if (!children.isEmpty()) {
for (Entry<ItemStack, Short> child : children.entrySet()) {
if (ingredient.isSimilar(child.getKey())) {
return child.getValue();
}
}
}
return -1;
}
}

View File

@ -7,6 +7,7 @@ public enum DatabaseUpdateType {
MOB_HEALTHBARS,
PARTY_NAMES,
KILL_ORPHANS,
DROPPED_SPOUT
DROPPED_SPOUT,
ALCHEMY
;
}

View File

@ -31,6 +31,7 @@ import com.gmail.nossr50.runnables.skills.AbilityDisableTask;
import com.gmail.nossr50.runnables.skills.ToolLowerTask;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager;
import com.gmail.nossr50.skills.alchemy.AlchemyManager;
import com.gmail.nossr50.skills.archery.ArcheryManager;
import com.gmail.nossr50.skills.axes.AxesManager;
import com.gmail.nossr50.skills.child.FamilyTree;
@ -192,6 +193,10 @@ public class McMMOPlayer {
return (AcrobaticsManager) skillManagers.get(SkillType.ACROBATICS);
}
public AlchemyManager getAlchemyManager() {
return (AlchemyManager) skillManagers.get(SkillType.ALCHEMY);
}
public ArcheryManager getArcheryManager() {
return (ArcheryManager) skillManagers.get(SkillType.ARCHERY);
}

View File

@ -15,6 +15,7 @@ import com.gmail.nossr50.config.experience.ExperienceConfig;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager;
import com.gmail.nossr50.skills.alchemy.AlchemyManager;
import com.gmail.nossr50.skills.archery.ArcheryManager;
import com.gmail.nossr50.skills.axes.AxesManager;
import com.gmail.nossr50.skills.excavation.ExcavationManager;
@ -35,6 +36,7 @@ import com.google.common.collect.ImmutableList;
public enum SkillType {
ACROBATICS(AcrobaticsManager.class, Color.WHITE, ImmutableList.of(SecondaryAbility.DODGE, SecondaryAbility.GRACEFUL_ROLL, SecondaryAbility.ROLL)),
ALCHEMY(AlchemyManager.class, Color.FUCHSIA, null),
ARCHERY(ArcheryManager.class, Color.MAROON, ImmutableList.of(SecondaryAbility.DAZE, SecondaryAbility.RETRIEVE, SecondaryAbility.SKILL_SHOT)),
AXES(AxesManager.class, Color.AQUA, AbilityType.SKULL_SPLITTER, ToolType.AXE, ImmutableList.of(SecondaryAbility.ARMOR_IMPACT, SecondaryAbility.AXE_MASTERY, SecondaryAbility.CRITICAL_HIT, SecondaryAbility.GREATER_IMPACT)),
EXCAVATION(ExcavationManager.class, Color.fromRGB(139, 69, 19), AbilityType.GIGA_DRILL_BREAKER, ToolType.SHOVEL, ImmutableList.of(SecondaryAbility.EXCAVATION_TREASURE_HUNTER)),
@ -61,7 +63,7 @@ public enum SkillType {
public static final List<SkillType> COMBAT_SKILLS = ImmutableList.of(ARCHERY, AXES, SWORDS, TAMING, UNARMED);
public static final List<SkillType> GATHERING_SKILLS = ImmutableList.of(EXCAVATION, FISHING, HERBALISM, MINING, WOODCUTTING);
public static final List<SkillType> MISC_SKILLS = ImmutableList.of(ACROBATICS, REPAIR, SMELTING);
public static final List<SkillType> MISC_SKILLS = ImmutableList.of(ACROBATICS, ALCHEMY, REPAIR, SMELTING);
static {
List<SkillType> childSkills = new ArrayList<SkillType>();

View File

@ -0,0 +1,37 @@
package com.gmail.nossr50.events.skills.alchemy;
import org.bukkit.block.Block;
import org.bukkit.block.BrewingStand;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent;
public class McMMOPlayerBrewEvent extends McMMOPlayerSkillEvent implements Cancellable {
private Block brewingStand;
private boolean cancelled;
public McMMOPlayerBrewEvent(Player player, Block brewingStand) {
super(player, SkillType.ALCHEMY);
this.brewingStand = brewingStand;
cancelled = false;
}
public boolean isCancelled() {
return cancelled;
}
public void setCancelled(boolean newValue) {
this.cancelled = newValue;
}
public Block getBrewingStandBlock() {
return brewingStand;
}
public BrewingStand getBrewingStand() {
return brewingStand.getState() instanceof BrewingStand ? (BrewingStand) brewingStand.getState() : null;
}
}

View File

@ -0,0 +1,35 @@
package com.gmail.nossr50.events.skills.alchemy;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent;
public class McMMOPlayerCatalysisEvent extends McMMOPlayerSkillEvent implements Cancellable {
private double speed;
private boolean cancelled;
public McMMOPlayerCatalysisEvent(Player player, double speed) {
super(player, SkillType.ALCHEMY);
this.speed = speed;
cancelled = false;
}
public boolean isCancelled() {
return cancelled;
}
public void setCancelled(boolean newValue) {
this.cancelled = newValue;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
}

View File

@ -8,6 +8,7 @@ import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.BrewingStand;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -30,6 +31,7 @@ import com.gmail.nossr50.datatypes.skills.ToolType;
import com.gmail.nossr50.events.fake.FakeBlockBreakEvent;
import com.gmail.nossr50.events.fake.FakeBlockDamageEvent;
import com.gmail.nossr50.runnables.StickyPistonTrackerTask;
import com.gmail.nossr50.skills.alchemy.Alchemy;
import com.gmail.nossr50.skills.excavation.ExcavationManager;
import com.gmail.nossr50.skills.herbalism.HerbalismManager;
import com.gmail.nossr50.skills.mining.MiningManager;
@ -135,6 +137,11 @@ public class BlockListener implements Listener {
return;
}
/* ALCHEMY - Cancel any brew in progress for that BrewingStand */
if (blockState instanceof BrewingStand && Alchemy.brewingStandMap.containsKey(event.getBlock())) {
Alchemy.brewingStandMap.get(event.getBlock()).cancelBrew();
}
Player player = event.getPlayer();
if (Misc.isNPCEntity(player) || player.getGameMode() == GameMode.CREATIVE) {

View File

@ -28,9 +28,12 @@ import org.bukkit.event.entity.EntityTameEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.entity.ExplosionPrimeEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.potion.PotionEffect;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.config.AdvancedConfig;
@ -592,4 +595,23 @@ public class EntityListener implements Listener {
event.setCancelled(true);
}
}
/**
* Handle PotionSplash events in order to fix broken Splash Potion of Saturation.
*
* @param event The event to process
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPotionSplash(PotionSplashEvent event) {
for (PotionEffect effect : ((PotionMeta) event.getEntity().getItem().getItemMeta()).getCustomEffects()) {
// (effect.getType() == PotionEffectType.SATURATION) is seemingly broken, so we use deprecated method for now.
if (effect.getType().getId() == 23) {
for (LivingEntity entity : event.getAffectedEntities()) {
int duration = (int) (effect.getDuration() * event.getIntensity(entity));
entity.addPotionEffect(new PotionEffect(effect.getType(), duration, effect.getAmplifier(), effect.isAmbient()));
}
}
return;
}
}
}

View File

@ -2,8 +2,10 @@ package com.gmail.nossr50.listeners;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.BrewingStand;
import org.bukkit.block.Furnace;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
@ -16,16 +18,21 @@ import org.bukkit.event.inventory.FurnaceExtractEvent;
import org.bukkit.event.inventory.FurnaceSmeltEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.FurnaceInventory;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.MetadataValue;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.datatypes.skills.SecondaryAbility;
import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.runnables.PlayerUpdateInventoryTask;
import com.gmail.nossr50.skills.alchemy.AlchemyPotionBrewer;
import com.gmail.nossr50.util.ItemUtils;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.Permissions;
@ -129,6 +136,48 @@ public class InventoryListener implements Listener {
event.setExpToDrop(UserManager.getPlayer(player).getSmeltingManager().vanillaXPBoost(event.getExpToDrop()));
}
@EventHandler(ignoreCancelled = true)
public void onAlchemyClickEvent(InventoryClickEvent event) {
if (event.getInventory().getType() != InventoryType.BREWING || !(event.getInventory().getHolder() instanceof BrewingStand)) {
return;
}
if (!(event.getWhoClicked() instanceof Player) || Misc.isNPCEntity(event.getWhoClicked()) || !Permissions.concoctions(event.getWhoClicked())) {
return;
}
AlchemyPotionBrewer.handleInventoryClick(event);
}
@EventHandler(ignoreCancelled = true)
public void onAlchemyDragEvent(InventoryDragEvent event) {
if (event.getInventory().getType() != InventoryType.BREWING || !(event.getInventory().getHolder() instanceof BrewingStand)) {
return;
}
if (!(event.getWhoClicked() instanceof Player) || Misc.isNPCEntity(event.getWhoClicked()) || !Permissions.concoctions(event.getWhoClicked())) {
return;
}
AlchemyPotionBrewer.handleInventoryDrag(event);
}
@EventHandler(ignoreCancelled = true)
public void onAlchemyMoveItemEvent(InventoryMoveItemEvent event) {
if (event.getDestination().getType() != InventoryType.BREWING || !(event.getDestination().getHolder() instanceof BrewingStand)) {
return;
}
if (Config.getInstance().getPreventHopperTransfer() && event.getItem() != null && event.getItem().getType() != Material.POTION) {
event.setCancelled(true);
return;
}
if (Config.getInstance().getEnabledForHoppers()) {
AlchemyPotionBrewer.handleInventoryMoveItem(event);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryClickEvent(InventoryClickEvent event) {
SkillUtils.removeAbilityBuff(event.getCurrentItem());

View File

@ -19,6 +19,7 @@ import com.gmail.nossr50.config.mods.CustomBlockConfig;
import com.gmail.nossr50.config.mods.CustomEntityConfig;
import com.gmail.nossr50.config.mods.CustomToolConfig;
import com.gmail.nossr50.config.repair.RepairConfigManager;
import com.gmail.nossr50.config.potion.PotionConfig;
import com.gmail.nossr50.config.treasure.TreasureConfig;
import com.gmail.nossr50.database.DatabaseManager;
import com.gmail.nossr50.database.DatabaseManagerFactory;
@ -38,6 +39,7 @@ import com.gmail.nossr50.runnables.database.UserPurgeTask;
import com.gmail.nossr50.runnables.party.PartyAutoKickTask;
import com.gmail.nossr50.runnables.player.PowerLevelUpdatingTask;
import com.gmail.nossr50.runnables.skills.BleedTimerTask;
import com.gmail.nossr50.skills.alchemy.Alchemy;
import com.gmail.nossr50.skills.child.ChildConfig;
import com.gmail.nossr50.skills.repair.repairables.Repairable;
import com.gmail.nossr50.skills.repair.repairables.RepairableManager;
@ -198,6 +200,7 @@ public class mcMMO extends JavaPlugin {
@Override
public void onDisable() {
try {
Alchemy.finishAllBrews(); // Finish all partially complete AlchemyBrewTasks to prevent vanilla brewing continuation on restart
UserManager.saveAll(); // Make sure to save player information if the server shuts down
PartyManager.saveParties(); // Save our parties
ScoreboardManager.teardownAll();
@ -358,6 +361,7 @@ public class mcMMO extends JavaPlugin {
TreasureConfig.getInstance();
HiddenConfig.getInstance();
AdvancedConfig.getInstance();
PotionConfig.getInstance();
new ChildConfig();
List<Repairable> repairables = new ArrayList<Repairable>();

View File

@ -0,0 +1,42 @@
package com.gmail.nossr50.runnables.skills;
import java.util.Arrays;
import org.bukkit.block.Block;
import org.bukkit.block.BrewingStand;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import com.gmail.nossr50.skills.alchemy.Alchemy;
import com.gmail.nossr50.skills.alchemy.AlchemyPotionBrewer;
public class AlchemyBrewCheckTask extends BukkitRunnable {
private final static int INGREDIENT_SLOT = 3;
private Player player;
private Block brewingStand;
private ItemStack[] oldInventory;
private ItemStack[] newInventory;
public AlchemyBrewCheckTask(Player player, BrewingStand brewingStand) {
this.player = player;
this.brewingStand = brewingStand.getBlock();
this.oldInventory = Arrays.copyOfRange(brewingStand.getInventory().getContents(), 0, 4);
}
@Override
public void run() {
this.newInventory = Arrays.copyOfRange(((BrewingStand) brewingStand.getState()).getInventory().getContents(), 0, 4);
if (Alchemy.brewingStandMap.containsKey(brewingStand)) {
if (oldInventory[INGREDIENT_SLOT] == null || newInventory[INGREDIENT_SLOT] == null || !oldInventory[INGREDIENT_SLOT].isSimilar(newInventory[INGREDIENT_SLOT]) || !AlchemyPotionBrewer.isValidBrew(player, newInventory)) {
Alchemy.brewingStandMap.get(brewingStand).cancelBrew();
}
}
if (!Alchemy.brewingStandMap.containsKey(brewingStand) && AlchemyPotionBrewer.isValidBrew(player, newInventory)) {
Alchemy.brewingStandMap.put(brewingStand, new AlchemyBrewTask(brewingStand, player));
}
}
}

View File

@ -0,0 +1,95 @@
package com.gmail.nossr50.runnables.skills;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.BrewingStand;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.events.skills.alchemy.McMMOPlayerBrewEvent;
import com.gmail.nossr50.events.skills.alchemy.McMMOPlayerCatalysisEvent;
import com.gmail.nossr50.skills.alchemy.Alchemy;
import com.gmail.nossr50.skills.alchemy.AlchemyPotionBrewer;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.player.UserManager;
public class AlchemyBrewTask extends BukkitRunnable {
private final double DEFAULT_BREW_SPEED = 1.0;
private final int DEFAULT_BREW_TICKS = 400;
private Block brewingStand;
private double brewSpeed;
private double brewTimer;
private Player player;
public AlchemyBrewTask(Block brewingStand, Player player) {
this.brewingStand = brewingStand;
this.player = player;
brewSpeed = DEFAULT_BREW_SPEED;
brewTimer = DEFAULT_BREW_TICKS;
if (player != null && !Misc.isNPCEntity(player) && Permissions.catalysis(player)) {
double catalysis = UserManager.getPlayer(player).getAlchemyManager().getBrewSpeed();
if (Permissions.lucky(player, SkillType.ALCHEMY)) {
catalysis = UserManager.getPlayer(player).getAlchemyManager().getBrewSpeedLucky();
}
McMMOPlayerCatalysisEvent event = new McMMOPlayerCatalysisEvent(player, catalysis);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
brewSpeed = catalysis;
}
}
if (Alchemy.brewingStandMap.containsKey(brewingStand)) {
Alchemy.brewingStandMap.get(brewingStand).cancel();
}
Alchemy.brewingStandMap.put(brewingStand, this);
this.runTaskTimer(mcMMO.p, 1, 1);
}
@Override
public void run() {
brewTimer -= brewSpeed;
// Vanilla potion brewing completes when BrewingTime == 1
if (brewTimer < Math.max(brewSpeed, 2)) {
this.cancel();
finish();
}
else {
((BrewingStand) brewingStand.getState()).setBrewingTime((int) brewTimer);
}
}
private void finish() {
McMMOPlayerBrewEvent event = new McMMOPlayerBrewEvent(player, brewingStand);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
AlchemyPotionBrewer.finishBrewing(brewingStand, player, false);
}
Alchemy.brewingStandMap.remove(brewingStand);
}
public void finishImmediately() {
this.cancel();
AlchemyPotionBrewer.finishBrewing(brewingStand, player, true);
Alchemy.brewingStandMap.remove(brewingStand);
}
public void cancelBrew() {
this.cancel();
((BrewingStand) brewingStand.getState()).setBrewingTime(-1);
Alchemy.brewingStandMap.remove(brewingStand);
}
}

View File

@ -0,0 +1,83 @@
package com.gmail.nossr50.skills.alchemy;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.bukkit.block.Block;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.config.experience.ExperienceConfig;
import com.gmail.nossr50.runnables.skills.AlchemyBrewTask;
public final class Alchemy {
public enum Tier {
EIGHT(8),
SEVEN(7),
SIX(6),
FIVE(5),
FOUR(4),
THREE(3),
TWO(2),
ONE(1);
int numerical;
private Tier(int numerical) {
this.numerical = numerical;
}
public int toNumerical() {
return numerical;
}
public static Tier fromNumerical(int numerical) {
for (Tier tier : Tier.values()) {
if (tier.toNumerical() == numerical) {
return tier;
}
}
return null;
}
protected int getLevel() {
return AdvancedConfig.getInstance().getConcoctionsTierLevel(this);
}
}
public static int catalysisUnlockLevel = AdvancedConfig.getInstance().getCatalysisUnlockLevel();
public static int catalysisMaxBonusLevel = AdvancedConfig.getInstance().getCatalysisMaxBonusLevel();
public static double catalysisMinSpeed = AdvancedConfig.getInstance().getCatalysisMinSpeed();
public static double catalysisMaxSpeed = AdvancedConfig.getInstance().getCatalysisMaxSpeed();
public static double potionXp = ExperienceConfig.getInstance().getPotionXP();
public static Map<Block, AlchemyBrewTask> brewingStandMap = new HashMap<Block, AlchemyBrewTask>();
private Alchemy() {};
/**
* Calculate base brewing speed, given a skill level and ignoring all perks.
*
* @param skillLevel Skill level used for calculation.
* @return Base brewing speed for the level.
*/
public static double calculateBrewSpeed(int skillLevel) {
if (skillLevel < catalysisUnlockLevel) {
return catalysisMinSpeed;
}
return Math.min(catalysisMaxSpeed, catalysisMinSpeed + (catalysisMaxSpeed - catalysisMinSpeed) * (skillLevel - catalysisUnlockLevel) / (catalysisMaxBonusLevel - catalysisUnlockLevel));
}
/**
* Finish all active brews. Used upon Disable to prevent vanilla potions from being brewed upon next Enable.
*/
public static void finishAllBrews() {
mcMMO.p.getLogger().info("Completing " + brewingStandMap.size() + " unfinished Alchemy brews.");
for (Entry<Block, AlchemyBrewTask> entry : brewingStandMap.entrySet()) {
entry.getValue().finishImmediately();
}
}
}

View File

@ -0,0 +1,86 @@
package com.gmail.nossr50.skills.alchemy;
import java.util.List;
import org.bukkit.inventory.ItemStack;
import com.gmail.nossr50.config.experience.ExperienceConfig;
import com.gmail.nossr50.config.potion.PotionConfig;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.SkillType;
import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.StringUtils;
public class AlchemyManager extends SkillManager {
private final double LUCKY_MODIFIER = 4.0 / 3.0;
public AlchemyManager(McMMOPlayer mcMMOPlayer) {
super(mcMMOPlayer, SkillType.ALCHEMY);
}
public boolean canCatalysis() {
return Permissions.catalysis(getPlayer());
}
public boolean canUseIngredient(ItemStack item) {
for (ItemStack ingredient : getIngredients()) {
if (item.isSimilar(ingredient)) {
return true;
}
}
return false;
}
public int getTier() {
for (Alchemy.Tier tier : Alchemy.Tier.values()) {
if (getSkillLevel() >= tier.getLevel()) {
return tier.toNumerical();
}
}
return 0;
}
public List<ItemStack> getIngredients() {
switch (Alchemy.Tier.fromNumerical(getTier())) {
case EIGHT:
return PotionConfig.getInstance().concoctionsIngredientsTierEight;
case SEVEN:
return PotionConfig.getInstance().concoctionsIngredientsTierSeven;
case SIX:
return PotionConfig.getInstance().concoctionsIngredientsTierSix;
case FIVE:
return PotionConfig.getInstance().concoctionsIngredientsTierFive;
case FOUR:
return PotionConfig.getInstance().concoctionsIngredientsTierFour;
case THREE:
return PotionConfig.getInstance().concoctionsIngredientsTierThree;
case TWO:
return PotionConfig.getInstance().concoctionsIngredientsTierTwo;
default:
return PotionConfig.getInstance().concoctionsIngredientsTierOne;
}
}
public String getIngredientList() {
String list = "";
for (ItemStack ingredient : getIngredients()) {
list += ", " + StringUtils.getPrettyItemString(ingredient.getType()) + (ingredient.getDurability() != 0 ? ":" + ingredient.getDurability() : "");
}
return list.substring(2);
}
public double getBrewSpeed() {
return Alchemy.calculateBrewSpeed(getSkillLevel());
}
public double getBrewSpeedLucky() {
return LUCKY_MODIFIER * Alchemy.calculateBrewSpeed(getSkillLevel());
}
public void handlePotionBrewSuccesses(int amount) {
applyXpGain((float) (ExperienceConfig.getInstance().getPotionXP() * amount));
}
}

View File

@ -0,0 +1,349 @@
package com.gmail.nossr50.skills.alchemy;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BrewingStand;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.inventory.InventoryType.SlotType;
import org.bukkit.inventory.BrewerInventory;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.config.potion.PotionConfig;
import com.gmail.nossr50.datatypes.AlchemyPotion;
import com.gmail.nossr50.runnables.PlayerUpdateInventoryTask;
import com.gmail.nossr50.runnables.skills.AlchemyBrewCheckTask;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.player.UserManager;
public final class AlchemyPotionBrewer {
private final static int[] BOTTLE_SLOTS = new int[] { 0, 1, 2 };
private final static int INGREDIENT_SLOT = 3;
public static boolean isValidBrew(Player player, ItemStack[] contents) {
if (isValidIngredient(player, contents[INGREDIENT_SLOT])) {
for (int bottle : BOTTLE_SLOTS) {
if (contents[bottle] != null && contents[bottle].getType() == Material.POTION) {
AlchemyPotion potion = PotionConfig.getInstance().potionMap.get(contents[bottle].getDurability());
if (getChildPotion(potion, contents[INGREDIENT_SLOT]) != null) {
return true;
}
}
}
}
return false;
}
private static AlchemyPotion getChildPotion(AlchemyPotion potion, ItemStack ingredient) {
if (potion != null && potion.getChildDataValue(ingredient) != -1) {
return PotionConfig.getInstance().potionMap.get(potion.getChildDataValue(ingredient));
}
return null;
}
private static boolean isEmpty(ItemStack item) {
return item == null || item.getType() == Material.AIR || item.getAmount() == 0;
}
private static boolean removeIngredient(BrewerInventory inventory, Player player) {
ItemStack ingredient = inventory.getIngredient();
if (isEmpty(ingredient) || !isValidIngredient(player, ingredient)) {
return false;
}
else if (ingredient.getAmount() <= 1) {
inventory.setItem(INGREDIENT_SLOT, null);
return true;
}
else {
ingredient.setAmount(ingredient.getAmount() - 1);
inventory.setItem(INGREDIENT_SLOT, ingredient);
return true;
}
}
private static boolean isValidIngredient(Player player, ItemStack item) {
if (isEmpty(item)) {
return false;
}
for (ItemStack ingredient : getValidIngredients(player)) {
if (item.isSimilar(ingredient)) {
return true;
}
}
return false;
}
private static List<ItemStack> getValidIngredients(Player player) {
if (player == null || !Permissions.concoctions(player)) {
return PotionConfig.getInstance().concoctionsIngredientsTierOne;
}
switch (UserManager.getPlayer(player).getAlchemyManager().getTier()) {
case 5:
return PotionConfig.getInstance().concoctionsIngredientsTierFive;
case 4:
return PotionConfig.getInstance().concoctionsIngredientsTierFour;
case 3:
return PotionConfig.getInstance().concoctionsIngredientsTierThree;
case 2:
return PotionConfig.getInstance().concoctionsIngredientsTierTwo;
default:
return PotionConfig.getInstance().concoctionsIngredientsTierOne;
}
}
public static void finishBrewing(Block brewingStand, Player player, boolean forced) {
if (!(brewingStand.getState() instanceof BrewingStand)) {
return;
}
BrewerInventory inventory = ((BrewingStand) brewingStand.getState()).getInventory();
ItemStack ingredient = inventory.getIngredient() == null ? null : inventory.getIngredient().clone();
if (removeIngredient(inventory, player)) {
for (int bottle : BOTTLE_SLOTS) {
if (!isEmpty(inventory.getItem(bottle)) && PotionConfig.getInstance().potionMap.containsKey(inventory.getItem(bottle).getDurability())) {
AlchemyPotion input = PotionConfig.getInstance().potionMap.get(inventory.getItem(bottle).getDurability());
AlchemyPotion output = PotionConfig.getInstance().potionMap.get(input.getChildDataValue(ingredient));
if (output != null) {
inventory.setItem(bottle, output.toItemStack(inventory.getItem(bottle).getAmount()).clone());
if (player != null) {
UserManager.getPlayer(player).getAlchemyManager().handlePotionBrewSuccesses(1);
}
}
}
}
if (!forced) {
scheduleUpdate(inventory);
}
return;
}
}
private static boolean transferOneItem(InventoryView view, int fromSlot, int toSlot) {
ItemStack from = view.getItem(fromSlot).clone();
ItemStack to = view.getItem(toSlot).clone();
if (isEmpty(from)) {
return false;
}
else if (!isEmpty(to) && from.getAmount() >= from.getType().getMaxStackSize()) {
return false;
}
else if (isEmpty(to) || from.isSimilar(to)) {
if (isEmpty(to)) {
to = from.clone();
to.setAmount(1);
}
else {
to.setAmount(to.getAmount() + 1);
}
from.setAmount(from.getAmount() - 1);
view.setItem(toSlot, isEmpty(to) ? null : to);
view.setItem(fromSlot, isEmpty(from) ? null : from);
return true;
}
return false;
}
/**
* Transfer items between two ItemStacks, returning the leftover status
*/
private static boolean transferItems(InventoryView view, int fromSlot, int toSlot) {
if (isEmpty(view.getItem(fromSlot))) {
return false;
}
else if (isEmpty(view.getItem(toSlot))) {
view.setItem(toSlot, view.getItem(fromSlot).clone());
view.setItem(fromSlot, null);
return true;
}
else if (view.getItem(fromSlot).isSimilar(view.getItem(toSlot))) {
if (view.getItem(fromSlot).getAmount() + view.getItem(toSlot).getAmount() > view.getItem(toSlot).getType().getMaxStackSize()) {
int left = view.getItem(fromSlot).getAmount() + view.getItem(toSlot).getAmount() - view.getItem(toSlot).getType().getMaxStackSize();
ItemStack to = new ItemStack(view.getItem(toSlot));
to.setAmount(to.getType().getMaxStackSize());
view.setItem(toSlot, to);
ItemStack from = new ItemStack(view.getItem(fromSlot));
from.setAmount(left);
view.setItem(fromSlot, from);
return true;
}
ItemStack to = new ItemStack(view.getItem(toSlot));
to.setAmount(view.getItem(fromSlot).getAmount() + view.getItem(toSlot).getAmount());
view.setItem(fromSlot, null);
view.setItem(toSlot, to);
return true;
}
return false;
}
private static void scheduleCheck(Player player, BrewingStand brewingStand) {
Bukkit.getScheduler().scheduleSyncDelayedTask(mcMMO.p, new AlchemyBrewCheckTask(player, brewingStand));
}
private static void scheduleUpdate(Inventory inventory) {
for (HumanEntity he : inventory.getViewers()) {
if (he instanceof Player) {
scheduleUpdate((Player) he);
}
}
}
private static void scheduleUpdate(Player player) {
Bukkit.getScheduler().scheduleSyncDelayedTask(mcMMO.p, new PlayerUpdateInventoryTask(player));
}
public static void handleInventoryClick(InventoryClickEvent event) {
Player player = event.getWhoClicked() instanceof Player ? (Player) event.getWhoClicked() : null;
BrewingStand brewingStand = (BrewingStand) event.getInventory().getHolder();
ItemStack cursor = event.getCursor();
ItemStack clicked = event.getCurrentItem();
if (clicked != null && clicked.getType() == Material.POTION) {
scheduleCheck(player, brewingStand);
return;
}
if (event.isShiftClick()) {
if (event.getSlotType() == SlotType.FUEL) {
scheduleCheck(player, brewingStand);
return;
}
else if (event.getSlotType() == SlotType.CONTAINER || event.getSlotType() == SlotType.QUICKBAR) {
if (isValidIngredient(player, clicked)) {
if (event.isLeftClick()) {
transferItems(event.getView(), event.getRawSlot(), INGREDIENT_SLOT);
}
else if (event.isRightClick()) {
transferOneItem(event.getView(), event.getRawSlot(), INGREDIENT_SLOT);
}
event.setCancelled(true);
scheduleUpdate(brewingStand.getInventory());
scheduleCheck(player, brewingStand);
return;
}
}
}
else if (event.getRawSlot() == INGREDIENT_SLOT) {
if (isEmpty(cursor) && isEmpty(clicked)) {
return;
}
else if (isEmpty(cursor)) {
scheduleCheck(player, brewingStand);
return;
}
else if (isEmpty(clicked)) {
if (isValidIngredient(player, event.getCursor())) {
if (event.getClick() == ClickType.LEFT || (event.getClick() == ClickType.RIGHT && event.getCursor().getAmount() == 1)) {
event.setCancelled(true);
event.setCurrentItem(event.getCursor().clone());
event.setCursor(null);
scheduleUpdate(brewingStand.getInventory());
scheduleCheck(player, brewingStand);
return;
}
else if (event.getClick() == ClickType.RIGHT) {
event.setCancelled(true);
ItemStack one = event.getCursor().clone();
one.setAmount(1);
ItemStack rest = event.getCursor().clone();
rest.setAmount(event.getCursor().getAmount() - 1);
event.setCurrentItem(one);
event.setCursor(rest);
scheduleUpdate(brewingStand.getInventory());
scheduleCheck(player, brewingStand);
return;
}
}
return;
}
}
}
public static void handleInventoryDrag(InventoryDragEvent event) {
Player player = event.getWhoClicked() instanceof Player ? (Player) event.getWhoClicked() : null;
BrewingStand brewingStand = (BrewingStand) event.getInventory().getHolder();
ItemStack cursor = event.getCursor();
ItemStack ingredient = brewingStand.getInventory().getIngredient();
if (event.getInventorySlots().contains(INGREDIENT_SLOT)) {
if (isEmpty(ingredient) || ingredient.isSimilar(cursor)) {
if (isValidIngredient(player, cursor)) {
// Not handled: dragging custom ingredients over ingredient slot (does not trigger any event)
scheduleCheck(player, brewingStand);
return;
}
else {
event.setCancelled(true);
scheduleUpdate(brewingStand.getInventory());
return;
}
}
}
}
public static void handleInventoryMoveItem(InventoryMoveItemEvent event) {
Player player = null;
BrewingStand brewingStand = (BrewingStand) event.getDestination().getHolder();
if (isValidIngredient(player, event.getItem())) {
scheduleCheck(player, brewingStand);
return;
}
else {
event.setCancelled(true);
return;
}
}
}

View File

@ -126,6 +126,20 @@ public final class Permissions {
public static boolean skillEnabled(Permissible permissible, SkillType skill) {return permissible.hasPermission("mcmmo.skills." + skill.toString().toLowerCase()); }
public static boolean vanillaXpBoost(Permissible permissible, SkillType skill) { return permissible.hasPermission("mcmmo.ability." + skill.toString().toLowerCase() + ".vanillaxpboost"); }
public static boolean secondaryAbilityEnabled(Permissible permissible, SecondaryAbility skillAbility) { return permissible.hasPermission("mcmmo.ability." + SkillType.bySecondaryAbility(skillAbility).toString().toLowerCase() + "." + StringUtils.getPrettySecondaryAbilityString(skillAbility).replace(" ", "").toLowerCase()); }
public static boolean bonusDamage(Permissible permissible, SkillType skill) { return permissible.hasPermission("mcmmo.ability." + skill.toString().toLowerCase() + ".bonusdamage"); }
/* ACROBATICS */
public static boolean dodge(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.acrobatics.dodge"); }
public static boolean gracefulRoll(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.acrobatics.gracefulroll"); }
public static boolean roll(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.acrobatics.roll"); }
/* ALCHEMY */
public static boolean catalysis(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.alchemy.catalysis"); }
public static boolean concoctions(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.alchemy.concoctions"); }
/* ARCHERY */
public static boolean arrowRetrieval(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.archery.trackarrows"); }
public static boolean daze(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.archery.daze"); }
/* AXES */
public static boolean skullSplitter(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.axes.skullsplitter"); }

View File

@ -35,6 +35,7 @@ import com.gmail.nossr50.commands.player.McrankCommand;
import com.gmail.nossr50.commands.player.McstatsCommand;
import com.gmail.nossr50.commands.player.MctopCommand;
import com.gmail.nossr50.commands.skills.AcrobaticsCommand;
import com.gmail.nossr50.commands.skills.AlchemyCommand;
import com.gmail.nossr50.commands.skills.ArcheryCommand;
import com.gmail.nossr50.commands.skills.AxesCommand;
import com.gmail.nossr50.commands.skills.ExcavationCommand;
@ -76,6 +77,10 @@ public final class CommandRegistrationManager {
command.setExecutor(new AcrobaticsCommand());
break;
case ALCHEMY:
command.setExecutor(new AlchemyCommand());
break;
case ARCHERY:
command.setExecutor(new ArcheryCommand());
break;