mirror of
https://gitlab.com/phoenix-dvpmt/mmoitems.git
synced 2024-12-22 04:37:42 +01:00
Smithing Crafting Recipes now supported.
**Update MythicLib** Pro tip: Its not implemented in-game but you can write it in the config files directly: ``` crafting: smithing: '1': input1: SWORD.HEARTSWORD input2: SWORD.ORACLE_SWORD # Makes extra gems drop instead of getting lost drop-gems: true # If both inputs have upgrades, how to treat them? # upgrades: ADDITIVE # Sum them upgrades: MAXIMUM # Largest of them (Default) # upgrades: EVEN # Average # upgrades: MINIMUM # Minimum of them # upgrades: NONE # Actually just dont keep upgrades ```
This commit is contained in:
parent
e30a0f9e8f
commit
1f88c15f28
@ -0,0 +1,392 @@
|
||||
package net.Indyuce.mmoitems.api.crafting.recipe;
|
||||
|
||||
import io.lumine.mythic.lib.api.crafting.ingredients.MythicBlueprintInventory;
|
||||
import io.lumine.mythic.lib.api.crafting.ingredients.MythicRecipeInventory;
|
||||
import io.lumine.mythic.lib.api.crafting.outputs.MRORecipe;
|
||||
import io.lumine.mythic.lib.api.crafting.outputs.MythicRecipeOutput;
|
||||
import io.lumine.mythic.lib.api.crafting.recipes.MythicCachedResult;
|
||||
import io.lumine.mythic.lib.api.crafting.recipes.vmp.VanillaInventoryMapping;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.util.Ref;
|
||||
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
|
||||
import net.Indyuce.mmoitems.ItemStats;
|
||||
import net.Indyuce.mmoitems.api.interaction.GemStone;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
|
||||
import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
|
||||
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Intended for use with Anvil / Smithing station, the combination of
|
||||
* two MMOItems, or upgrading a MMOItem with an ingot, also combines the
|
||||
* gems and upgrade level of the components.
|
||||
*
|
||||
* @author Gunging
|
||||
*/
|
||||
public class CustomSmithingRecipe extends MythicRecipeOutput {
|
||||
|
||||
/**
|
||||
* @param outputItem The MMOItem that results from the completion of these recipes.
|
||||
* @param dropGemstones Should extra gemstones be dropped? (Otherwise lost)
|
||||
* @param upgradeTreatment How will upgrades combine?
|
||||
*/
|
||||
public CustomSmithingRecipe(@NotNull MMOItemTemplate outputItem, boolean dropGemstones, @NotNull UpgradeCombinationType upgradeTreatment) {
|
||||
this.outputItem = outputItem;
|
||||
this.dropGemstones = dropGemstones;
|
||||
this.upgradeTreatment = upgradeTreatment; }
|
||||
|
||||
|
||||
/**
|
||||
* The MMOItem that results from the completion of these recipes.
|
||||
*/
|
||||
@NotNull final MMOItemTemplate outputItem;
|
||||
/**
|
||||
* @return The MMOItem that results from the completion of these recipes.
|
||||
*/
|
||||
@NotNull public MMOItemTemplate getOutputItem() { return outputItem; }
|
||||
|
||||
/**
|
||||
* Will the extra gemstones be dropped to the ground?
|
||||
*/
|
||||
final boolean dropGemstones;
|
||||
|
||||
/**
|
||||
* @return Will the extra gemstones be dropped to the ground?
|
||||
*/
|
||||
public boolean isDropGemstones() { return dropGemstones; }
|
||||
|
||||
/**
|
||||
* @return How to treat upgrade level combinations?
|
||||
*/
|
||||
@NotNull
|
||||
public UpgradeCombinationType getUpgradeTreatment() { return upgradeTreatment; }
|
||||
/**
|
||||
* How to treat upgrade level combinations?
|
||||
*/
|
||||
@NotNull final UpgradeCombinationType upgradeTreatment;
|
||||
|
||||
/**
|
||||
* Is this a MMOItem? Well fetch
|
||||
*
|
||||
* @param item Item Stack to transform
|
||||
* @return a MMOItem if appropriate.
|
||||
*/
|
||||
@Nullable MMOItem fromStack(@Nullable ItemStack item) {
|
||||
|
||||
if (item == null) { return null; } else {
|
||||
|
||||
NBTItem itemNBT = NBTItem.get(item);
|
||||
if (itemNBT.hasType()) { return new LiveMMOItem(item); } }
|
||||
|
||||
return null; }
|
||||
/**
|
||||
* Is there at least one item in the first side inventory? Well git
|
||||
*
|
||||
* @param b Blueprint
|
||||
* @return an ItemStack if any exists
|
||||
*/
|
||||
@Nullable ItemStack firstFromFirstSide(@NotNull MythicBlueprintInventory b) {
|
||||
|
||||
// No sides?
|
||||
if (b.getSideInventoryNames().size() == 0) { return null; }
|
||||
|
||||
// Get
|
||||
return b.getSideInventory(b.getSideInventoryNames().get(0)).getFirst(); }
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public MythicRecipeInventory applyDisplay(@NotNull MythicBlueprintInventory mythicRecipeInventory, @NotNull InventoryClickEvent eventTrigger, @NotNull VanillaInventoryMapping mapping) {
|
||||
|
||||
// Not supported
|
||||
if (!(eventTrigger.getWhoClicked() instanceof Player)) { return mythicRecipeInventory.getResultInventory(); }
|
||||
|
||||
// Get the two combinant items
|
||||
MythicBlueprintInventory original = mapping.extractFrom(eventTrigger.getView().getTopInventory());
|
||||
ItemStack item = original.getMainInventory().getFirst();
|
||||
ItemStack ingot = firstFromFirstSide(original);
|
||||
|
||||
MMOItem itemMMO = fromStack(item);
|
||||
MMOItem ingotMMO = fromStack(ingot);
|
||||
|
||||
// Get the display
|
||||
MMOItem display = fromCombinationWith(itemMMO, ingotMMO, (Player) eventTrigger.getWhoClicked(), null);
|
||||
|
||||
// Result
|
||||
MythicRecipeInventory result = mythicRecipeInventory.getResultInventory().clone();
|
||||
result.setItemAt(mapping.getResultWidth(mapping.getResultInventoryStart()), mapping.getResultHeight(mapping.getResultInventoryStart()), display.newBuilder().build());
|
||||
|
||||
// Set the display
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyResult(@NotNull MythicRecipeInventory resultInventory, @NotNull MythicBlueprintInventory otherInventories, @NotNull MythicCachedResult cache, @NotNull InventoryClickEvent eventTrigger, @NotNull VanillaInventoryMapping map, int times) {
|
||||
|
||||
/*
|
||||
* Listen, we'll take it from here. Cancel the original event.
|
||||
*
|
||||
* Now run Mythic Crafting version of the event.
|
||||
* Did anyone cancel it? Well I guess we'll touch nothing then, but you also cant craft this item >:I
|
||||
*/
|
||||
eventTrigger.setCancelled(true);
|
||||
if (!(eventTrigger.getWhoClicked() instanceof Player)) { return; }
|
||||
|
||||
// Get the two combinant items
|
||||
ItemStack item = otherInventories.getMainInventory().getFirst();
|
||||
ItemStack ingot = firstFromFirstSide(otherInventories);
|
||||
|
||||
MMOItem itemMMO = fromStack(item);
|
||||
MMOItem ingotMMO = fromStack(ingot);
|
||||
|
||||
// Get the display
|
||||
Ref<ArrayList<ItemStack>> droppedGemstones = new Ref<>();
|
||||
MMOItem display = fromCombinationWith(itemMMO, ingotMMO, (Player) eventTrigger.getWhoClicked(), droppedGemstones);
|
||||
|
||||
// Result
|
||||
MythicRecipeInventory result = otherInventories.getResultInventory().clone();
|
||||
result.setItemAt(map.getResultWidth(map.getResultInventoryStart()), map.getResultHeight(map.getResultInventoryStart()), display.newBuilder().build());
|
||||
|
||||
/*
|
||||
* Crafting the item only once allows to put it in the cursor.
|
||||
*
|
||||
* Otherwise, this stuff will have to
|
||||
* 1 Calculate how many times until it runs out of inventory slots
|
||||
* 2 Move it to those inventory slots
|
||||
*/
|
||||
if (times == 1 && (eventTrigger.getAction() != InventoryAction.MOVE_TO_OTHER_INVENTORY)) {
|
||||
|
||||
/*
|
||||
* When crafting with the cursor, we must make sure that:
|
||||
*
|
||||
* 1 The player is holding nothing in the cursor
|
||||
* or
|
||||
*
|
||||
* 2 The item in their cursor is stackable with the result
|
||||
* and
|
||||
* 3 The max stacks would not be exceeded
|
||||
*/
|
||||
ItemStack currentInCursor = eventTrigger.getCursor();
|
||||
|
||||
/*
|
||||
* Set the result into the result slots.
|
||||
*/
|
||||
|
||||
//RR//for (String str : result.toStrings("\u00a78Result \u00a79RR-")) { MythicCraftingManager.log(str); }
|
||||
|
||||
// Apply the result
|
||||
//RDR//MythicCraftingManager.log("\u00a78RDR \u00a748\u00a77 Processing Result Inventory");
|
||||
processInventory(resultInventory, result, times);
|
||||
//RR//for (String str : resultInventory.toStrings("\u00a78Result \u00a79PR-")) { MythicCraftingManager.log(str); }
|
||||
|
||||
//RDR//MythicCraftingManager.log("\u00a78RDR \u00a749\u00a77 Finding item to put on cursor");
|
||||
|
||||
// Get the zeroth entry, which will be put in the players cursor >:o
|
||||
ItemStack cursor = resultInventory.getItemAt(map.getResultWidth(eventTrigger.getSlot()), map.getResultHeight(eventTrigger.getSlot()));
|
||||
if (cursor == null) { cursor = new ItemStack(Material.AIR); }
|
||||
ItemStack actualCursor = cursor.clone();
|
||||
|
||||
/*
|
||||
* All right, so, can the actual cursor stack with the current?
|
||||
*/
|
||||
if (!SilentNumbers.isAir(currentInCursor)) {
|
||||
|
||||
// Aye so they could stack
|
||||
if (currentInCursor.isSimilar(actualCursor)) {
|
||||
|
||||
// Exceeds max stacks?
|
||||
int cAmount = currentInCursor.getAmount();
|
||||
int aAmount = actualCursor.getAmount();
|
||||
int maxAmount = actualCursor.getMaxStackSize();
|
||||
|
||||
// Cancel if their sum would exceed the max
|
||||
if (cAmount + aAmount > maxAmount) { return; }
|
||||
|
||||
// All right recalculate amount then
|
||||
actualCursor.setAmount(cAmount + aAmount);
|
||||
|
||||
} else {
|
||||
|
||||
// Cancel this operation
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//RR//MythicCraftingManager.log("\u00a78Result \u00a74C\u00a77 Found for cursor " + SilentNumbers.getItemName(actualCursor));
|
||||
|
||||
// Deleting original item (now its going to be on cursor so)
|
||||
cursor.setAmount(0);
|
||||
|
||||
// Apply result to the inventory
|
||||
//RDR//MythicCraftingManager.log("\u00a78RDR \u00a7410\u00a77 Actually applying to result inventory through map");
|
||||
map.applyToResultInventory(eventTrigger.getInventory(), resultInventory, false);
|
||||
|
||||
// Apply result to the cursor
|
||||
eventTrigger.getView().setCursor(actualCursor);
|
||||
|
||||
// Player is crafting to completion - move to inventory style.
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Set the result into the result slots.
|
||||
*/
|
||||
//RDR//MythicCraftingManager.log("\u00a78RDR \u00a747\u00a77 Reading/Generating Result");
|
||||
|
||||
// Build the result
|
||||
ArrayList<ItemStack> outputItems = MRORecipe.toItemsList(result);
|
||||
HashMap<Integer, ItemStack> modifiedInventory = null;
|
||||
Inventory inven = eventTrigger.getWhoClicked().getInventory();
|
||||
int trueTimes = 0;
|
||||
|
||||
// For every time
|
||||
for (int t = 1; t <= times; t++) {
|
||||
//RDR//MythicCraftingManager.log("\u00a78RDR \u00a748\u00a77 Iteration \u00a7c#" + t);
|
||||
|
||||
//RR//for (String str : localResult.toStrings("\u00a78Result \u00a79RR-")) { io.lumine.mythic.lib.api.crafting.recipes.MythicCraftingManager.log(str); }
|
||||
|
||||
// Send to
|
||||
HashMap<Integer, ItemStack> localIterationResult = MRORecipe.distributeInInventory(inven, outputItems, modifiedInventory);
|
||||
|
||||
// Failed? Break
|
||||
if (localIterationResult == null) {
|
||||
|
||||
// No changes in the modified inventory, just break
|
||||
//RR//io.lumine.mythic.lib.api.crafting.recipes.MythicCraftingManager.log("\u00a78Result \u00a7cIC\u00a77 Iteration Cancelled: \u00a7cNo Inventory Space");
|
||||
break;
|
||||
|
||||
// Prepare for next iteration
|
||||
} else {
|
||||
|
||||
// Store changes
|
||||
modifiedInventory = localIterationResult;
|
||||
trueTimes = t;
|
||||
//RR//io.lumine.mythic.lib.api.crafting.recipes.MythicCraftingManager.log("\u00a78Result \u00a7aIV\u00a77 Iteration Validated, total times: \u00a7a" + trueTimes);
|
||||
} }
|
||||
|
||||
// True times is 0? Cancel this.
|
||||
if (trueTimes == 0) { return; }
|
||||
|
||||
// All right apply
|
||||
times = trueTimes;
|
||||
for (Integer s : modifiedInventory.keySet()) {
|
||||
|
||||
// Get Item
|
||||
ItemStack putt = modifiedInventory.get(s);
|
||||
//RR//io.lumine.mythic.lib.api.crafting.recipes.MythicCraftingManager.log("\u00a78Result \u00a79IS\u00a77 Putting \u00a7b@" + s + "\u00a77 a " + SilentNumbers.getItemName(putt));
|
||||
|
||||
// Set
|
||||
inven.setItem(s, putt); }
|
||||
}
|
||||
|
||||
// Drop?
|
||||
if (isDropGemstones() && (droppedGemstones.getValue() != null) && (eventTrigger.getWhoClicked().getLocation().getWorld() != null)) {
|
||||
Location l = eventTrigger.getWhoClicked().getLocation();
|
||||
|
||||
// Drop each yea
|
||||
for (ItemStack gem : droppedGemstones.getValue()) {
|
||||
|
||||
if (SilentNumbers.isAir(gem)) { continue; }
|
||||
|
||||
// God damn drop yo
|
||||
l.getWorld().dropItemNaturally(l, gem);
|
||||
} }
|
||||
|
||||
// Consume ingredients
|
||||
consumeIngredients(otherInventories, cache, eventTrigger.getInventory(), map, times);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param item The item you are upgrading
|
||||
* @param ingot The second item you are upgrading
|
||||
*
|
||||
* @return What would the output be if combined with this other MMOItem?
|
||||
*/
|
||||
@NotNull MMOItem fromCombinationWith(@Nullable MMOItem item, @Nullable MMOItem ingot, @NotNull Player p, @Nullable Ref<ArrayList<ItemStack>> rem) {
|
||||
|
||||
// Generate
|
||||
MMOItem gen = getOutputItem().newBuilder(0, null).build();
|
||||
|
||||
/*
|
||||
* Two things must be merged:
|
||||
*
|
||||
* 1 Gem Stones - Checks which gem stones can still fit
|
||||
*
|
||||
* 2 Upgrades - Performs an operation with the combination of them both
|
||||
*/
|
||||
|
||||
// Extract gemstones
|
||||
ArrayList<MMOItem> compGemstones = new ArrayList<>();
|
||||
if (item != null) { compGemstones.addAll(item.extractGemstones()); }
|
||||
if (ingot != null) { compGemstones.addAll(ingot.extractGemstones()); }
|
||||
|
||||
// Which stones would not fit
|
||||
ArrayList<ItemStack> remainingStones = new ArrayList<>();
|
||||
for (MMOItem m : compGemstones) {
|
||||
//GEM// MMOItems.log("\u00a76 +\u00a77 Fitting \u00a7e" + m.getType().toString() + " " + m.getId());
|
||||
|
||||
// What sockets are available?
|
||||
GemSocketsData genGemstones = (GemSocketsData) gen.getData(ItemStats.GEM_SOCKETS);
|
||||
|
||||
// Abort lol
|
||||
if (genGemstones == null || (genGemstones.getEmptySlots().size() == 0)) {
|
||||
//GEM// MMOItems.log("\u00a7c !!\u00a77 Dropping: No more empty slots in target ");
|
||||
|
||||
// Just keep as 'remaining'
|
||||
remainingStones.add(m.newBuilder().build());
|
||||
continue; }
|
||||
|
||||
// Ok proceed
|
||||
GemStone asGem = new GemStone(p, m.newBuilder().buildNBT());
|
||||
|
||||
// Put
|
||||
GemStone.ApplyResult res = asGem.applyOntoItem(gen, gen.getType(), "", false, true);
|
||||
|
||||
// None?
|
||||
if (res.getType().equals(GemStone.ResultType.SUCCESS) && (res.getResultAsMMOItem() != null)) {
|
||||
|
||||
// Success that's nice
|
||||
gen = res.getResultAsMMOItem();
|
||||
//GEM// MMOItems.log("\u00a7a W\u00a77 Socketed! ");
|
||||
|
||||
// Didn't fit L
|
||||
} else {
|
||||
//GEM// MMOItems.log("\u00a7e !!\u00a77 Dropping: Does not fit socket ");
|
||||
remainingStones.add(m.newBuilder().build()); } }
|
||||
|
||||
// Set value
|
||||
Ref.setValue(rem, remainingStones);
|
||||
|
||||
// All right whats the level stuff up now
|
||||
if (gen.hasUpgradeTemplate() && !(getUpgradeTreatment().equals(UpgradeCombinationType.NONE))) {
|
||||
|
||||
// All right get the levels of them both
|
||||
int itemLevel = 0; if (item != null) { itemLevel = item.getUpgradeLevel(); }
|
||||
int ingotLevel = 0; if (ingot != null) { ingotLevel = ingot.getUpgradeLevel(); }
|
||||
int finalLevel;
|
||||
|
||||
switch (getUpgradeTreatment()) {
|
||||
case ADDITIVE: finalLevel = itemLevel + ingotLevel; break;
|
||||
case MAXIMUM: finalLevel = Math.max(itemLevel, ingotLevel); break;
|
||||
case MINIMUM: finalLevel = Math.min(itemLevel, ingotLevel); break;
|
||||
default: finalLevel = SilentNumbers.ceil((itemLevel + ingotLevel) / 2D); break;
|
||||
}
|
||||
|
||||
// Upgrade yes
|
||||
gen.getUpgradeTemplate().upgradeTo(gen, Math.min(finalLevel, gen.getMaxUpgradeLevel())); }
|
||||
|
||||
// That's it
|
||||
return gen;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package net.Indyuce.mmoitems.api.crafting.recipe;
|
||||
|
||||
public enum UpgradeCombinationType {
|
||||
|
||||
/**
|
||||
* Adds the upgrade levels of both items
|
||||
*/
|
||||
ADDITIVE,
|
||||
|
||||
/**
|
||||
* Chooses the upgrade level of the item
|
||||
* with the greatest upgrade level
|
||||
*/
|
||||
MAXIMUM,
|
||||
|
||||
/**
|
||||
* Takes the average of the upgrade levels
|
||||
*/
|
||||
EVEN,
|
||||
|
||||
/**
|
||||
* Chooses the least upgrade level
|
||||
*/
|
||||
MINIMUM,
|
||||
|
||||
/**
|
||||
* Upgrade levels are lost
|
||||
*/
|
||||
NONE
|
||||
}
|
@ -7,6 +7,8 @@ import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.event.item.ApplyGemStoneEvent;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.util.message.Message;
|
||||
import net.Indyuce.mmoitems.stat.GemUpgradeScaling;
|
||||
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
|
||||
@ -23,6 +25,8 @@ import org.bukkit.ChatColor;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class GemStone extends UseItem {
|
||||
|
||||
@ -30,13 +34,18 @@ public class GemStone extends UseItem {
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
public ApplyResult applyOntoItem(NBTItem target, Type targetType) {
|
||||
@NotNull public ApplyResult applyOntoItem(@NotNull NBTItem target, @NotNull Type targetType) {
|
||||
|
||||
/*
|
||||
* Entirely loads the MMOItem and checks if it has the required empty
|
||||
* socket for the gem
|
||||
*/
|
||||
MMOItem targetMMO = new LiveMMOItem(target);
|
||||
return applyOntoItem(targetMMO, targetType, MMOUtils.getDisplayName(target.getItem()), true, false);
|
||||
}
|
||||
|
||||
@NotNull public ApplyResult applyOntoItem(@NotNull MMOItem targetMMO, @NotNull Type targetType, @NotNull String itemName, boolean buildStack, boolean silent){
|
||||
|
||||
if (!targetMMO.hasData(ItemStats.GEM_SOCKETS))
|
||||
return new ApplyResult(ResultType.NONE);
|
||||
|
||||
@ -59,10 +68,11 @@ public class GemStone extends UseItem {
|
||||
// check for success rate
|
||||
double successRate = getNBTItem().getStat(ItemStats.SUCCESS_RATE.getId());
|
||||
if (successRate != 0 && RANDOM.nextDouble() > successRate / 100) {
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
|
||||
Message.GEM_STONE_BROKE
|
||||
.format(ChatColor.RED, "#gem#", MMOUtils.getDisplayName(getItem()), "#item#", MMOUtils.getDisplayName(target.getItem()))
|
||||
.send(player);
|
||||
|
||||
if (!silent) {
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
|
||||
Message.GEM_STONE_BROKE.format(ChatColor.RED, "#gem#", MMOUtils.getDisplayName(getItem()), "#item#", itemName).send(player); }
|
||||
|
||||
return new ApplyResult(ResultType.FAILURE);
|
||||
}
|
||||
|
||||
@ -124,38 +134,46 @@ public class GemStone extends UseItem {
|
||||
}
|
||||
}
|
||||
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 2);
|
||||
Message.GEM_STONE_APPLIED
|
||||
.format(ChatColor.YELLOW, "#gem#", MMOUtils.getDisplayName(getItem()), "#item#", MMOUtils.getDisplayName(target.getItem()))
|
||||
.send(player);
|
||||
if (!silent) {
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 2);
|
||||
Message.GEM_STONE_APPLIED.format(ChatColor.YELLOW, "#gem#", MMOUtils.getDisplayName(getItem()), "#item#", itemName).send(player); }
|
||||
|
||||
return new ApplyResult(targetMMO.newBuilder().build());
|
||||
if (buildStack) {
|
||||
return new ApplyResult(targetMMO.newBuilder().build());
|
||||
|
||||
} else { return new ApplyResult(targetMMO, ResultType.SUCCESS); }
|
||||
}
|
||||
|
||||
public static class ApplyResult {
|
||||
private final ResultType type;
|
||||
private final ItemStack result;
|
||||
@NotNull private final ResultType type;
|
||||
@Nullable private final ItemStack result;
|
||||
@Nullable private final MMOItem resultAsMMOItem;
|
||||
|
||||
public ApplyResult(ResultType type) {
|
||||
this(null, type);
|
||||
public ApplyResult(@NotNull ResultType type) {
|
||||
this((ItemStack) null, type);
|
||||
}
|
||||
|
||||
public ApplyResult(ItemStack result) {
|
||||
this(result, ResultType.SUCCESS);
|
||||
}
|
||||
public ApplyResult(@Nullable ItemStack result) { this(result, ResultType.SUCCESS); }
|
||||
|
||||
public ApplyResult(ItemStack result, ResultType type) {
|
||||
public ApplyResult(@Nullable ItemStack result, @NotNull ResultType type) {
|
||||
this.type = type;
|
||||
this.result = result;
|
||||
this.resultAsMMOItem = null;
|
||||
}
|
||||
public ApplyResult(@Nullable MMOItem result, @NotNull ResultType type) {
|
||||
this.type = type;
|
||||
this.result = null;
|
||||
this.resultAsMMOItem = result;
|
||||
}
|
||||
|
||||
public ResultType getType() {
|
||||
@NotNull public ResultType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public ItemStack getResult() {
|
||||
@Nullable public ItemStack getResult() {
|
||||
return result;
|
||||
}
|
||||
@Nullable public MMOItem getResultAsMMOItem() { return resultAsMMOItem; }
|
||||
}
|
||||
|
||||
public enum ResultType {
|
||||
|
@ -6,6 +6,7 @@ import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.UpgradeTemplate;
|
||||
import net.Indyuce.mmoitems.api.item.ItemReference;
|
||||
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
|
||||
import net.Indyuce.mmoitems.stat.GemSockets;
|
||||
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
|
||||
import net.Indyuce.mmoitems.stat.data.GemstoneData;
|
||||
import net.Indyuce.mmoitems.stat.data.UpgradeData;
|
||||
@ -243,6 +244,22 @@ public class MMOItem implements ItemReference {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The upgrade level, or 0 if there is none.
|
||||
*/
|
||||
public int getMaxUpgradeLevel() {
|
||||
|
||||
// Does it have Upgrade Data?
|
||||
if (hasData(ItemStats.UPGRADE)) {
|
||||
|
||||
// Return the registered level.
|
||||
return ((UpgradeData) getData(ItemStats.UPGRADE)).getMax();
|
||||
}
|
||||
|
||||
// Nope? Well its level 0 I guess.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Make sure to check {@link #hasUpgradeTemplate()} before calling.</b>
|
||||
* <p></p>
|
||||
@ -282,4 +299,72 @@ public class MMOItem implements ItemReference {
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Gem Sockets API
|
||||
/**
|
||||
* It is not 100% fool proof, since some GemStones just don't have
|
||||
* enough information to be extracted (legacy gemstones).
|
||||
* <p></p>
|
||||
* Note that this is somewhat an expensive operation, restrain
|
||||
* from calling it much because it completely loads all the stats
|
||||
* of every Gem Stone.
|
||||
*
|
||||
* @see #getColor()
|
||||
*
|
||||
* @return The list of GemStones contained here.
|
||||
*/
|
||||
@NotNull public ArrayList<MMOItem> extractGemstones() {
|
||||
|
||||
// Found?
|
||||
GemSocketsData thisSocketsData = (GemSocketsData) getData(ItemStats.GEM_SOCKETS);
|
||||
if (thisSocketsData == null) { return new ArrayList<>(); }
|
||||
|
||||
// All right, whats all yous data
|
||||
HashMap<UUID, MMOItem> regeneratedGems = new HashMap<>();
|
||||
for (GemstoneData gem : thisSocketsData.getGemstones()) {
|
||||
|
||||
// Can we generate?
|
||||
MMOItem restored = MMOItems.plugin.getMMOItem(MMOItems.plugin.getType(gem.getMMOItemType()), gem.getMMOItemID());
|
||||
|
||||
// Valid? neat-o
|
||||
if (restored != null) {
|
||||
restored.color = gem.getSocketColor();
|
||||
regeneratedGems.put(gem.getHistoricUUID(), restored);
|
||||
} }
|
||||
|
||||
// Identify actual attributes
|
||||
for (ItemStat stat : getStats()) {
|
||||
|
||||
// Mergeable right
|
||||
if (!(stat.getClearStatData() instanceof Mergeable)) { continue; }
|
||||
|
||||
// Any stat affected by gems is sure to have a Stat History
|
||||
StatHistory hist = getStatHistory(stat);
|
||||
if (hist == null) { continue; }
|
||||
|
||||
// Data associated with any of the gems?
|
||||
for (Map.Entry<UUID, MMOItem> gem : regeneratedGems.entrySet()) {
|
||||
|
||||
// History got gem registered?
|
||||
StatData historicGemData = hist.getGemstoneData(gem.getKey());
|
||||
if (historicGemData == null) { continue;}
|
||||
|
||||
// This gemstone had this data... Override.
|
||||
gem.getValue().setData(stat, historicGemData);
|
||||
|
||||
} }
|
||||
|
||||
// Thats the gemstones we was searching for
|
||||
return new ArrayList<>(regeneratedGems.values());
|
||||
}
|
||||
|
||||
@Nullable String color;
|
||||
|
||||
/**
|
||||
* @return Supposing this MMOItem is a Gem Stone within an item,
|
||||
* obtained via {@link #extractGemstones()}, then this
|
||||
* will be the color of the slot it occupies.
|
||||
*/
|
||||
@Nullable public String getColor() { return color; }
|
||||
//endregion
|
||||
}
|
||||
|
@ -1040,7 +1040,7 @@ public class MMOItemReforger {
|
||||
} else {
|
||||
|
||||
// Get colour
|
||||
String colour = data.getColour();
|
||||
String colour = data.getSocketColor();
|
||||
String remembrance;
|
||||
|
||||
// Not null?
|
||||
|
@ -11,6 +11,7 @@ import io.lumine.mythic.lib.api.crafting.recipes.MythicRecipeBlueprint;
|
||||
import io.lumine.mythic.lib.api.crafting.recipes.MythicRecipeStation;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackCategory;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackProvider;
|
||||
import net.Indyuce.mmoitems.api.crafting.recipe.UpgradeCombinationType;
|
||||
import net.Indyuce.mmoitems.api.util.message.FFPMMOItems;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -165,13 +166,24 @@ public class RecipeManager implements Reloadable {
|
||||
loadedLegacyRecipes.add(recipe);
|
||||
}
|
||||
|
||||
public void registerSmithingRecipe(Type type, String id, ConfigurationSection section, String number) {
|
||||
public void registerSmithingRecipe(@NotNull Type type, @NotNull String id, @NotNull ConfigurationSection section, @NotNull String number) throws IllegalArgumentException {
|
||||
Validate.isTrue(section.isString("input1") && section.isString("input2"), "Invalid smithing recipe for '" + type.getId() + " . " + id + "'");
|
||||
WorkbenchIngredient input1 = getWorkbenchIngredient(section.getString("input1"));
|
||||
WorkbenchIngredient input2 = getWorkbenchIngredient(section.getString("input2"));
|
||||
SmithingRecipe recipe = new SmithingRecipe(getRecipeKey(type, id, "smithing", number), MMOItems.plugin.getItem(type, id), input1.toBukkit(),
|
||||
input2.toBukkit());
|
||||
loadedLegacyRecipes.add(recipe);
|
||||
|
||||
String item = section.getString("input1");
|
||||
String ingot = section.getString("input2");
|
||||
boolean dropGems = section.getBoolean("drop-gems", false);
|
||||
String upgrade = section.getString("upgrades" );
|
||||
if (item == null) { item = ""; }
|
||||
if (ingot == null) { ingot = ""; }
|
||||
if (upgrade == null) { upgrade = UpgradeCombinationType.MAXIMUM.toString(); }
|
||||
|
||||
MythicRecipeBlueprint blueprint = CustomRecipe.generateSmithing(type, id, item, ingot, dropGems, upgrade);
|
||||
|
||||
// Remember it
|
||||
customRecipes.add(blueprint);
|
||||
|
||||
// Enable it
|
||||
blueprint.deploy(MythicRecipeStation.SMITHING);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,7 @@ import java.util.Set;
|
||||
|
||||
import io.lumine.mythic.lib.api.util.Ref;
|
||||
import net.Indyuce.mmoitems.api.interaction.GemStone;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
|
||||
import org.apache.commons.lang.Validate;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
@ -21,6 +21,24 @@ public class GemstoneData {
|
||||
@Nullable Integer levelPut = 0;
|
||||
@NotNull final UUID historicUUID;
|
||||
|
||||
@Nullable
|
||||
public String getMMOItemType() {
|
||||
return mmoitemType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getMMOItemID() {
|
||||
return mmoitemID;
|
||||
}
|
||||
|
||||
/**
|
||||
* If known, the socket colour this gem was put into
|
||||
*/
|
||||
@Nullable
|
||||
public String getSocketColor() {
|
||||
return socketColor;
|
||||
}
|
||||
|
||||
@Nullable final String mmoitemType;
|
||||
@Nullable final String mmoitemID;
|
||||
@Nullable
|
||||
@ -173,11 +191,6 @@ public class GemstoneData {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* If known, the socket colour this gem was put into
|
||||
*/
|
||||
@Nullable public String getColour() { return socketColor; }
|
||||
|
||||
/**
|
||||
* If known, the socket colour this gem was put into
|
||||
*/
|
||||
|
@ -26,7 +26,7 @@ import java.util.*;
|
||||
* <p></p>
|
||||
* This class will store the different sources of each stat UPON being modified.
|
||||
*/
|
||||
@SuppressWarnings({"unused", "unchecked", "SpellCheckingInspection"})
|
||||
@SuppressWarnings({"unused", "SpellCheckingInspection"})
|
||||
public class StatHistory {
|
||||
|
||||
/*
|
||||
@ -84,7 +84,7 @@ public class StatHistory {
|
||||
* The final modifier being provided by each gemstone.
|
||||
* GemStones may have scaled with upgrades, that will be accounted for.
|
||||
*/
|
||||
@NotNull public StatData getGemstoneData(UUID of) { return perGemstoneData.get(of); }
|
||||
@Nullable public StatData getGemstoneData(UUID of) { return perGemstoneData.get(of); }
|
||||
|
||||
/**
|
||||
* All the Stat Datas provided by GemStones
|
||||
@ -330,6 +330,7 @@ public class StatHistory {
|
||||
if (gData.isScaling()) {
|
||||
|
||||
// Ok
|
||||
//noinspection ConstantConditions
|
||||
level = gData.getLevel();
|
||||
|
||||
} else {
|
||||
@ -346,6 +347,7 @@ public class StatHistory {
|
||||
|
||||
//DBL//if (getGemstoneData(d) instanceof DoubleData) MMOItems. Log("\u00a76 \u00a7b|>\u00a77 Gemstone Base: \u00a7e" + ((DoubleData) getGemstoneData(d)).getValue());
|
||||
// Apply upgrades
|
||||
//noinspection ConstantConditions
|
||||
StatData gRet = ((Upgradable) getItemStat()).apply(((Mergeable) getGemstoneData(d)).cloneData(), inf, gLevel);
|
||||
//DBL//if (gRet instanceof DoubleData) MMOItems.Log("\u00a76 \u00a7b|>\u00a77 Leveled Base: \u00a7e" + ((DoubleData) gRet).getValue());
|
||||
|
||||
@ -428,6 +430,7 @@ public class StatHistory {
|
||||
JsonObject yes = new JsonObject();
|
||||
|
||||
// Compress tags
|
||||
//noinspection ConstantConditions
|
||||
JsonArray yesCompressed = ItemTag.compressTags(getItemStat().getAppliedNBT(getGemstoneData(gem)));
|
||||
|
||||
// Put
|
||||
@ -640,7 +643,9 @@ public class StatHistory {
|
||||
//UPDT//MMOItems.Log(" \u00a76:\u00a72: \u00a77Original Externals \u00a7f" + perExternalData.size());
|
||||
|
||||
// Register gemstones
|
||||
for (UUID exUID : other.perGemstoneData.keySet()) { registerGemstoneData(exUID, other.getGemstoneData(exUID)); }
|
||||
for (UUID exUID : other.perGemstoneData.keySet()) {
|
||||
//noinspection ConstantConditions
|
||||
registerGemstoneData(exUID, other.getGemstoneData(exUID)); }
|
||||
|
||||
// Register externals
|
||||
for (StatData ex : other.perExternalData) { registerExternalData((ex)); }
|
||||
|
Loading…
Reference in New Issue
Block a user