Anvil Recipes Beginning

This commit is contained in:
Kam committed 2025-02-09 20:49:45 -05:00
1 parent e9004aafa3
commit 9cda5503ed
13 files changed
+947 -31

No files matched your search

+4 -1
View File
@@ -64,9 +64,12 @@ public class CommonProxy implements IGuiHandler {
if(gui == EnumGuiType.PlayerTrader)
return new ContainerNPCTrader(npc, player);
if(gui == EnumGuiType.PlayerAnvil)
if(gui == EnumGuiType.PlayerCarpentryBench)
return new ContainerCarpentryBench(player.inventory, player.worldObj, x, y, z);
if(gui == EnumGuiType.PlayerAnvil)
return new ContainerAnvilRepair(player.inventory, player.worldObj, x, y, z);
if(gui == EnumGuiType.SetupItemGiver)
return new ContainerNpcItemGiver(npc, player);
@@ -2,9 +2,9 @@ package noppes.npcs.blocks;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
@@ -32,9 +32,14 @@ public class BlockCarpentryBench extends BlockContainer
@Override
public boolean onBlockActivated(World par1World, int i, int j, int k, EntityPlayer player, int par6, float par7, float par8, float par9)
{//onBlockActivated
{
if(!par1World.isRemote){
player.openGui(CustomNpcs.instance, EnumGuiType.PlayerAnvil.ordinal(), par1World, i, j, k);
int meta = par1World.getBlockMetadata(i, j, k);
if(meta >= 4){
player.openGui(CustomNpcs.instance, EnumGuiType.PlayerAnvil.ordinal(), par1World, i, j, k);
} else {
player.openGui(CustomNpcs.instance, EnumGuiType.PlayerCarpentryBench.ordinal(), par1World, i, j, k);
}
}
return true;
}
@@ -316,9 +316,12 @@ public class ClientProxy extends CommonProxy {
else if (gui == EnumGuiType.ScriptItem)
return new GuiScriptItem();
else if (gui == EnumGuiType.PlayerAnvil)
else if (gui == EnumGuiType.PlayerCarpentryBench)
return new GuiNpcCarpentryBench((ContainerCarpentryBench) container);
else if (gui == EnumGuiType.PlayerAnvil)
return new GuiNpcAnvil((ContainerAnvilRepair) container);
else if (gui == EnumGuiType.SetupFollower)
return new GuiNpcFollowerSetup(npc, (ContainerNPCFollowerSetup) container);
@@ -0,0 +1,232 @@
package noppes.npcs.client.gui.player;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.util.ArrayList;
import java.util.List;
import noppes.npcs.client.CustomNpcResourceListener;
import noppes.npcs.client.gui.util.*;
import noppes.npcs.controllers.RecipeController;
import noppes.npcs.controllers.data.RecipeAnvil;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ResourceLocation;
import noppes.npcs.util.ValueUtil;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
@SideOnly(Side.CLIENT)
public class GuiAnvilRecipes extends GuiNPCInterface {
private static final ResourceLocation SLOT_TEXTURE = new ResourceLocation("customnpcs", "textures/gui/slot.png");
private int page = 0;
private GuiNpcLabel lblPage;
private GuiNpcButton btnLeft, btnRight;
private List<RecipeAnvil> recipes = new ArrayList<RecipeAnvil>();
private String search = "";
public GuiAnvilRecipes() {
this.xSize = 256;
this.ySize = 182;
setBackground("recipesAnvil.png");
this.closeOnEsc = true;
recipes.addAll(RecipeController.Instance.anvilRecipes.values());
}
@Override
public void initGui() {
super.initGui();
guiTop += 10;
// Add search text field (ID 3) at top.
addTextField(new GuiNpcTextField(3, this, fontRendererObj, guiLeft + 2, guiTop - 25, 250, 20, search));
addLabel(new GuiNpcLabel(0, "Anvil Recipe List", guiLeft + 5, guiTop + 5));
addLabel(lblPage = new GuiNpcLabel(1, "", guiLeft + 5, guiTop + 168));
addButton(this.btnLeft = new GuiButtonNextPage(1, guiLeft + 150, guiTop + 164, true));
addButton(this.btnRight = new GuiButtonNextPage(2, guiLeft + 80, guiTop + 164, false));
updateButton();
}
private void updateButton() {
// We want 8 recipes per page.
int maxPages = MathHelper.ceiling_float_int(recipes.size() / 8.0F);
btnRight.visible = btnRight.enabled = page > 0;
btnLeft.visible = btnLeft.enabled = page < maxPages - 1;
lblPage.label = (page + 1) + "/" + maxPages;
}
@Override
public void keyTyped(char c, int i) {
super.keyTyped(c, i);
if(search.equals(getTextField(3).getText()))
return;
search = getTextField(3).getText().toLowerCase();
recipes = getSearchList();
page = 0;
updateButton();
}
private List<RecipeAnvil> getSearchList() {
if(search.isEmpty()) {
return new ArrayList<RecipeAnvil>(RecipeController.Instance.anvilRecipes.values());
}
List<RecipeAnvil> list = new ArrayList<RecipeAnvil>();
for(RecipeAnvil recipe : RecipeController.Instance.anvilRecipes.values()) {
ItemStack repairItem = recipe.itemToRepair;
if(repairItem == null)
continue;
if(repairItem.getDisplayName() == null)
continue;
if(repairItem.getDisplayName().trim().isEmpty())
continue;
if(repairItem.getDisplayName().toLowerCase().contains(search))
list.add(recipe);
}
return list;
}
@Override
protected void actionPerformed(GuiButton button) {
if(!button.enabled)
return;
if(button == btnRight) {
if(page > 0)
page--;
}
if(button == btnLeft) {
int maxPages = MathHelper.ceiling_float_int(recipes.size() / 8.0F);
if(page < maxPages - 1)
page++;
}
updateButton();
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
super.drawScreen(mouseX, mouseY, partialTicks);
// Update page label.
lblPage.label = (page + 1) + "/" + MathHelper.ceiling_float_int(recipes.size() / 8.0F);
lblPage.x = guiLeft + (xSize - Minecraft.getMinecraft().fontRenderer.getStringWidth(lblPage.label)) / 2;
// Determine which recipes to show.
int recipesPerPage = 8;
int startIndex = page * recipesPerPage;
int endIndex = Math.min(recipes.size(), startIndex + recipesPerPage);
// Set base positions: first column X and first row Y.
int baseX = guiLeft + 4;
int baseY = guiTop + 28; // first row Y = 28
int colSpacing = 124; // horizontal spacing between columns
int rowSpacing = 35; // vertical spacing so row1 becomes 28+35 = 63
for (int i = startIndex; i < endIndex; i++) {
RecipeAnvil recipe = recipes.get(i);
int localIndex = i - startIndex; // 0 to 7
int col = localIndex / 4; // 0 for left column, 1 for right column
int row = localIndex % 4; // 0 to 3
int slotX = baseX + col * colSpacing;
int slotY = baseY + row * rowSpacing;
// Draw slot backgrounds for two input slots.
mc.renderEngine.bindTexture(SLOT_TEXTURE);
GL11.glColor4f(1F, 1F, 1F, 1F);
// Left slot (item to repair)
drawTexturedModalRect(slotX, slotY, 0, 0, 18, 18);
// Middle slot (repair material)
drawTexturedModalRect(slotX + 22, slotY, 0, 0, 18, 18);
// Draw the item-to-repair at 50% durability.
ItemStack toRepair = recipe.itemToRepair;
if (toRepair != null) {
ItemStack halfItem = toRepair.copy();
if (halfItem.isItemStackDamageable()) {
int halfDamage = halfItem.getMaxDamage() / 2;
halfItem.setItemDamage(halfDamage);
}
drawItem(halfItem, slotX + 1, slotY + 1, mouseX, mouseY);
}
// Draw the repair material.
ItemStack material = recipe.repairMaterial;
if (material != null) {
drawItem(material, slotX + 23, slotY + 1, mouseX, mouseY);
}
// Draw the output item fully repaired (damage = 0).
// For first column, output X = guiLeft+103; second column, output X = guiLeft+229.
int outputX = (col == 0) ? (guiLeft + 103) : (guiLeft + 229);
if (recipe.itemToRepair != null) {
ItemStack fullOutput = recipe.itemToRepair.copy();
if (fullOutput.isItemStackDamageable()) {
fullOutput.setItemDamage(0);
}
drawItem(fullOutput, outputX, slotY, mouseX, mouseY);
}
// Draw the percentage text.
// We want the "middle right" for the first column to be at 68.
// So for column 0, centerX is fixed at 68; for column 1, centerX is 68 + colSpacing.
String percentText = Math.round(recipe.getRepairPercentage()) + "%";
int textWidth = fontRendererObj.getStringWidth(percentText);
int centerX = (col == 0) ? guiLeft + 57 : (guiLeft + 57 + colSpacing);
int textX = centerX - (textWidth / 2);
int textY = slotY + 4 + row;
fontRendererObj.drawString(percentText, textX, textY, CustomNpcResourceListener.DefaultTextColor);
// Draw XP cost with scaling.
String xpCostStr = formatXpCost(recipe.getXpCost());
int digitCount = xpCostStr.length();
// Scale factor: for 1 digit = 1.0, for 2 digits = 0.9, for 3 digits = 0.8.
float xpScale = 1.0F - 0.1F * (digitCount - 1);
// Get raw text width.
int rawTextWidth = fontRendererObj.getStringWidth(xpCostStr);
int scaledTextWidth = (int)(rawTextWidth * xpScale);
int xpCenterX = (col == 0) ? (guiLeft + 76) : (guiLeft + 78 + colSpacing);
int xpTextX = xpCenterX - (scaledTextWidth / 2);
int xpTextY = slotY - 4 + row; // adjust as needed
GL11.glPushMatrix();
GL11.glTranslatef(xpTextX, xpTextY, 0);
GL11.glScalef(xpScale, xpScale, 1.0F);
fontRendererObj.drawString(xpCostStr, 0, 0, 0x4ac26a);
GL11.glPopMatrix();
}
}
private String formatXpCost(int xp) {
if (xp < 1000) {
return String.valueOf(xp);
}
double xpK = xp / 1000.0;
if (xpK == (int)xpK) {
return ((int)xpK) + "K";
} else {
return String.format("%.1fK", xpK);
}
}
private void drawItem(ItemStack item, int x, int y, int mouseX, int mouseY) {
GL11.glPushMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
RenderHelper.enableGUIStandardItemLighting();
itemRender.zLevel = 100.0F;
itemRender.renderItemAndEffectIntoGUI(fontRendererObj, mc.renderEngine, item, x, y);
itemRender.renderItemOverlayIntoGUI(fontRendererObj, mc.renderEngine, item, x, y);
itemRender.zLevel = 0.0F;
RenderHelper.disableStandardItemLighting();
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
}
@Override
public void save() {}
}
@@ -0,0 +1,81 @@
package noppes.npcs.client.gui.player;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import noppes.npcs.client.CustomNpcResourceListener;
import noppes.npcs.client.gui.util.GuiContainerNPCInterface;
import noppes.npcs.client.gui.util.GuiNpcButton;
import noppes.npcs.containers.ContainerAnvilRepair;
import noppes.npcs.controllers.RecipeController;
import org.lwjgl.opengl.GL11;
public class GuiNpcAnvil extends GuiContainerNPCInterface {
private final ResourceLocation resource = new ResourceLocation("customnpcs", "textures/gui/anvil.png");
private ContainerAnvilRepair container;
private GuiNpcButton button;
public GuiNpcAnvil(ContainerAnvilRepair container) {
super(null, container);
this.container = container;
this.title = "";
allowUserInput = false;
closeOnEsc = true;
ySize = 180;
}
@Override
public void initGui() {
super.initGui();
addButton(button = new GuiNpcButton(0, guiLeft + 158, guiTop + 4, 12, 20, "..."));
}
@Override
public void buttonEvent(GuiButton guibutton) {
displayGuiScreen(new GuiAnvilRecipes());
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
// Enable the button if there are any anvil recipes.
button.enabled = RecipeController.Instance != null && !RecipeController.Instance.getAnvilList().isEmpty();
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
mc.renderEngine.bindTexture(resource);
int l = (width - xSize) / 2;
int i1 = (height - ySize) / 2;
drawTexturedModalRect(l, i1, 0, 0, xSize, ySize);
super.drawGuiContainerBackgroundLayer(partialTicks, mouseX, mouseY);
// Draw title and player's inventory label.
fontRendererObj.drawString(StatCollector.translateToLocal("tile.anvil.name"), guiLeft + 4, guiTop + 4, CustomNpcResourceListener.DefaultTextColor);
fontRendererObj.drawString(StatCollector.translateToLocal("container.inventory"), guiLeft + 4, guiTop + 87, CustomNpcResourceListener.DefaultTextColor);
// Compute the repair status message based on container.repairCost and player's XP.
String status = "";
if (container.repairCost > 0) {
if (container.repairCost > mc.thePlayer.experienceTotal) {
status = "Repair cost: " + container.repairCost + " XP";
} else {
status = "Repair cost: " + container.repairCost + " XP";
}
} else {
// If there is a damaged item that is fully repaired.
if (container.anvilMatrix.getStackInRowAndColumn(0, 0) != null &&
container.anvilMatrix.getStackInRowAndColumn(0, 0).isItemStackDamageable() &&
container.anvilMatrix.getStackInRowAndColumn(0, 0).getItemDamage() <= 0) {
status = "Item is already fully repaired";
}
}
int textColor = CustomNpcResourceListener.DefaultTextColor;
if (container.repairCost > mc.thePlayer.experienceTotal) {
textColor = 0xFF0000; // red when not enough XP
}
fontRendererObj.drawString(status, guiLeft + 5, guiTop + 75, textColor);
}
@Override
public void save() {
// Nothing to save.
}
}
@@ -1,5 +1,11 @@
package noppes.npcs.constants;
import noppes.npcs.quests.QuestItem;
import noppes.npcs.roles.companion.CompanionTrader;
import noppes.npcs.scripted.ScriptBlock;
import javax.swing.border.Border;
public enum EnumGuiType {
MainMenuDisplay,
MainMenuInv,
@@ -27,7 +33,8 @@ public enum EnumGuiType {
SetupBank,
ManageDialogs,
ManageQuests,
PlayerAnvil,
PlayerCarpentryBench,
PlayerAnvil,
QuestReward,
ManageRecipes,
QuestItem,
@@ -0,0 +1,370 @@
package noppes.npcs.containers;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.Items;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.inventory.InventoryCraftResult;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.network.play.server.S2FPacketSetSlot;
import net.minecraft.world.World;
import noppes.npcs.api.handler.data.IAnvilRecipe;
import noppes.npcs.controllers.RecipeController;
import noppes.npcs.controllers.data.RecipeAnvil;
public class ContainerAnvilRepair extends Container {
// A 2-slot crafting matrix: slot 0 = damaged item, slot 1 = repair material.
public InventoryCrafting anvilMatrix = new InventoryCrafting(this, 2, 1);
// Single-slot output inventory.
public InventoryCraftResult anvilResult = new InventoryCraftResult();
private EntityPlayer player;
private World worldObj;
private int posX, posY, posZ;
// These fields are used for syncing the repair cost message.
public String repairStatus = "";
public int repairCost = 0;
// How many repair material items are used during the repair calculation.
public int repairMaterialConsumed = 0;
public ContainerAnvilRepair(InventoryPlayer playerInv, World world, int x, int y, int z) {
this.worldObj = world;
this.posX = x;
this.posY = y;
this.posZ = z;
this.player = playerInv.player;
// Output slot (index 0) using our custom SlotAnvilOutput.
this.addSlotToContainer(new SlotAnvilOutput(this, anvilResult, 0, 133, 47));
// Input slot 0: damaged item. We restrict its stack size to 1.
this.addSlotToContainer(new Slot(anvilMatrix, 0, 26, 47) {
@Override
public int getSlotStackLimit() {
return 1;
}
});
// Input slot 1: repair material. Override onSlotChanged so that changes to the stack size trigger an update.
this.addSlotToContainer(new Slot(anvilMatrix, 1, 75, 47) {
@Override
public void onSlotChanged() {
super.onSlotChanged();
ContainerAnvilRepair.this.onCraftMatrixChanged(anvilMatrix);
}
});
// Add player inventory slots.
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 9; ++col) {
this.addSlotToContainer(new Slot(playerInv, col + row * 9 + 9, 8 + col * 18, 98 + row * 18));
}
}
for (int col = 0; col < 9; ++col) {
this.addSlotToContainer(new Slot(playerInv, col, 8 + col * 18, 156));
}
updateRepairResult();
// For testing: clear recipes and add a test recipe.
RecipeController.Instance.anvilRecipes.clear();
RecipeController.Instance.addAnvilRecipe(new RecipeAnvil(
"Test",
new ItemStack(Items.iron_pickaxe),
new ItemStack(Items.paper),
4,
3));
RecipeController.Instance.addAnvilRecipe(new RecipeAnvil(
"Okay",
new ItemStack(Items.diamond_pickaxe),
new ItemStack(Items.paper),
4,
3));
RecipeController.Instance.addAnvilRecipe(new RecipeAnvil(
"Bob",
new ItemStack(Items.golden_pickaxe),
new ItemStack(Items.paper),
4,
3));
RecipeController.Instance.addAnvilRecipe(new RecipeAnvil(
"Dude",
new ItemStack(Items.iron_chestplate),
new ItemStack(Items.paper),
4,
3));
RecipeController.Instance.addAnvilRecipe(new RecipeAnvil(
"Oas",
new ItemStack(Items.golden_pickaxe),
new ItemStack(Items.diamond),
4,
3));
RecipeController.Instance.addAnvilRecipe(new RecipeAnvil(
"awd",
new ItemStack(Items.golden_sword),
new ItemStack(Items.gold_ingot),
4,
3));
RecipeController.Instance.addAnvilRecipe(new RecipeAnvil(
"fawd",
new ItemStack(Items.bow),
new ItemStack(Items.string),
4,
3));
RecipeController.Instance.addAnvilRecipe(new RecipeAnvil(
"cxzs",
new ItemStack(Items.bow),
new ItemStack(Items.diamond),
4,
3));
RecipeController.Instance.addAnvilRecipe(new RecipeAnvil(
"awdawdwa",
new ItemStack(Items.iron_sword),
new ItemStack(Items.blaze_rod),
4,
3));
}
@Override
public void onCraftMatrixChanged(IInventory inventory) {
updateRepairResult();
detectAndSendChanges();
}
/**
* Updates the output slot (and repair cost fields) based on the two input slots.
* Instead of forcing the damaged item’s stack to 1 (which deletes extra items),
* we create a copy with stackSize 1 for calculations. Then, when the repair is picked up,
* we subtract one from the original stack.
*/
public void updateRepairResult() {
if (!this.worldObj.isRemote) {
repairMaterialConsumed = 0;
ItemStack input0 = anvilMatrix.getStackInRowAndColumn(0, 0);
ItemStack input1 = anvilMatrix.getStackInRowAndColumn(1, 0);
// If either input is missing, clear output.
if (input0 == null || input1 == null) {
repairCost = 0;
anvilResult.setInventorySlotContents(0, null);
return;
}
// Create a copy of the damaged item for calculation (stack size 1)
ItemStack calcItem = input0.copy();
calcItem.stackSize = 1;
// If the item is damageable and already fully repaired, show a message.
if (calcItem.isItemStackDamageable() && calcItem.getItemDamage() <= 0) {
repairCost = 0;
anvilResult.setInventorySlotContents(0, null);
return;
}
// Look for a matching recipe.
RecipeAnvil matchingRecipe = null;
for (IAnvilRecipe recipe : RecipeController.Instance.getAnvilList()) {
if (recipe.matches(input0, input1)) {
matchingRecipe = (RecipeAnvil) recipe;
break;
}
}
ItemStack output = null;
if (matchingRecipe != null) {
int baseXpCost = matchingRecipe.getXpCost();
// Assume repairPercentage is given as a percent (e.g. 20 for 20% per material)
float repairPercentage = matchingRecipe.getRepairPercentage() / 100.0f;
int maxDamage = calcItem.getMaxDamage();
int currentDamage = calcItem.getItemDamage();
// Fixed repair amount per material (at least 1 point)
int repairPerMaterial = (int) Math.floor(maxDamage * repairPercentage);
if (repairPerMaterial < 1) {
repairPerMaterial = 1;
}
int availableMaterials = input1.stackSize;
int materialsUsed = 0;
while (currentDamage > 0 && materialsUsed < availableMaterials) {
int repairThisIteration = repairPerMaterial;
if (repairThisIteration > currentDamage) {
repairThisIteration = currentDamage;
}
currentDamage -= repairThisIteration;
materialsUsed++;
// Stop if item is fully repaired.
if (currentDamage <= 0) {
break;
}
}
int xpCost = baseXpCost * materialsUsed;
calcItem.setItemDamage(currentDamage);
if (player.experienceTotal >= xpCost) {
output = calcItem;
}
repairMaterialConsumed = materialsUsed;
repairCost = xpCost;
} else {
repairCost = 0;
}
anvilResult.setInventorySlotContents(0, output);
}
}
// --- Sync Methods ---
@Override
public void addCraftingToCrafters(ICrafting listener) {
super.addCraftingToCrafters(listener);
listener.sendProgressBarUpdate(this, 0, this.repairCost);
}
@Override
public void detectAndSendChanges() {
super.detectAndSendChanges();
for (Object crafterObj : this.crafters) {
((ICrafting) crafterObj).sendProgressBarUpdate(this, 0, this.repairCost);
}
}
@Override
public void updateProgressBar(int id, int data) {
if (id == 0) {
this.repairCost = data;
}
}
// --- End Sync Methods ---
@Override
public void onContainerClosed(EntityPlayer player) {
super.onContainerClosed(player);
if (!this.worldObj.isRemote) {
for (int i = 0; i < this.anvilMatrix.getSizeInventory(); i++) {
ItemStack stack = this.anvilMatrix.getStackInSlotOnClosing(i);
if (stack != null) {
player.dropPlayerItemWithRandomChoice(stack, false);
}
}
}
}
@Override
public boolean canInteractWith(EntityPlayer player) {
return player.getDistanceSq((double)this.posX + 0.5D,
(double)this.posY + 0.5D,
(double)this.posZ + 0.5D) <= 64.0D;
}
@Override
public ItemStack transferStackInSlot(EntityPlayer player, int index) {
ItemStack copy = null;
Slot slot = (Slot)this.inventorySlots.get(index);
if (slot != null && slot.getHasStack()) {
ItemStack stack = slot.getStack();
copy = stack.copy();
if (index == 0) { // output slot
if (player.experienceTotal < this.repairCost) {
return null;
}
if (!this.mergeItemStack(stack, 3, this.inventorySlots.size(), true)) {
return null;
}
slot.onSlotChange(stack, copy);
} else if (index >= 1 && index <= 2) { // input slots
if (!this.mergeItemStack(stack, 3, this.inventorySlots.size(), false)) {
return null;
}
} else { // player inventory
if (!this.mergeItemStack(stack, 1, 3, false)) {
return null;
}
}
if (stack.stackSize == 0) {
slot.putStack(null);
} else {
slot.onSlotChanged();
}
if (stack.stackSize == copy.stackSize) {
return null;
}
slot.onPickupFromSlot(player, stack);
}
if (!this.worldObj.isRemote && player instanceof EntityPlayerMP) {
((EntityPlayerMP) player).sendContainerToPlayer(this);
}
return copy;
}
@Override
public boolean func_94530_a(ItemStack stack, Slot slotIn) {
return slotIn.inventory != this.anvilResult && super.func_94530_a(stack, slotIn);
}
// Custom output slot: only allows pickup if the player has enough XP and,
// when picked up, consumes the required number of repair material items and
// subtracts one from the damaged item stack.
public class SlotAnvilOutput extends Slot {
private ContainerAnvilRepair container;
public SlotAnvilOutput(ContainerAnvilRepair container, IInventory inventory, int index, int x, int y) {
super(inventory, index, x, y);
this.container = container;
}
@Override
public boolean isItemValid(ItemStack stack) {
return false;
}
@Override
public boolean canTakeStack(EntityPlayer player) {
return player.experienceTotal >= container.repairCost;
}
@Override
public void onPickupFromSlot(EntityPlayer player, ItemStack stack) {
if (player.experienceTotal < container.repairCost) {
container.updateRepairResult();
return;
}
if (!player.capabilities.isCreativeMode) {
player.addExperience(-container.repairCost);
}
ItemStack repairMat = container.anvilMatrix.getStackInRowAndColumn(1, 0);
if (repairMat != null) {
if (repairMat.stackSize > container.repairMaterialConsumed) {
repairMat.stackSize -= container.repairMaterialConsumed;
} else {
repairMat = null;
}
container.anvilMatrix.setInventorySlotContents(1, repairMat);
}
ItemStack input0 = container.anvilMatrix.getStackInRowAndColumn(0, 0);
if (input0 != null) {
if (input0.stackSize > 1) {
input0.stackSize -= 1;
} else {
input0 = null;
}
container.anvilMatrix.setInventorySlotContents(0, input0);
}
container.repairCost = 0;
container.updateRepairResult();
super.onPickupFromSlot(player, stack);
}
}
}
@@ -57,7 +57,7 @@ public class MagicController {
} catch (Exception ee) { }
}
magics.clear();
if (true) {
if (false) {
// Create default Pokémon types
Magic normal = new Magic(0, "Normal", 0xA8A878);
normal.setIconItem(new ItemStack(net.minecraft.init.Items.paper)); // using paper for Normal
@@ -205,7 +205,7 @@ public class MagicController {
magics.put(fairy.id, fairy);
}
if (false) {
if (true) {
// Create default magics
Magic earth = new Magic(0, "Earth", 0x00DD00, 1, 1);
earth.setIconItem(new ItemStack(CustomItems.earthElement));
@@ -9,7 +9,9 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import noppes.npcs.CustomNpcs;
import noppes.npcs.api.handler.IRecipeHandler;
import noppes.npcs.api.handler.data.IAnvilRecipe;
import noppes.npcs.api.handler.data.IRecipe;
import noppes.npcs.controllers.data.RecipeAnvil;
import noppes.npcs.controllers.data.RecipeCarpentry;
import noppes.npcs.controllers.data.RecipesDefault;
@@ -21,14 +23,19 @@ import java.util.*;
public class RecipeController implements IRecipeHandler {
private static Collection<RecipeCarpentry> prevRecipes;
public HashMap<Integer,RecipeCarpentry> globalRecipes = new HashMap<Integer, RecipeCarpentry>();
public HashMap<Integer,RecipeCarpentry> carpentryRecipes = new HashMap<Integer, RecipeCarpentry>();
public static RecipeController Instance;
public HashMap<Integer, RecipeCarpentry> globalRecipes = new HashMap<Integer, RecipeCarpentry>();
public HashMap<Integer, RecipeCarpentry> carpentryRecipes = new HashMap<Integer, RecipeCarpentry>();
public HashMap<Integer, RecipeAnvil> anvilRecipes = new HashMap<Integer, RecipeAnvil>();
public static RecipeController Instance;
public static final int version = 1;
public int nextId = 1;
public int nextAnvilId = 1;
public static HashMap<Integer,RecipeCarpentry> syncRecipes = new HashMap<Integer, RecipeCarpentry>();
public static HashMap<Integer, RecipeCarpentry> syncRecipes = new HashMap<Integer, RecipeCarpentry>();
public static HashMap<Integer, RecipeAnvil> syncAnvilRecipes = new HashMap<Integer, RecipeAnvil>();
public RecipeController(){
Instance = this;
@@ -37,6 +44,7 @@ public class RecipeController implements IRecipeHandler {
loadCategories();
reloadGlobalRecipes(globalRecipes);
}
public static void reloadGlobalRecipes(HashMap<Integer,RecipeCarpentry> globalRecipes){
List list = CraftingManager.getInstance().getRecipeList();
if(prevRecipes != null){
@@ -61,6 +69,7 @@ public class RecipeController implements IRecipeHandler {
else{
globalRecipes.clear();
carpentryRecipes.clear();
anvilRecipes.clear();
loadDefaultRecipes(-1);
}
} catch (Exception e) {
@@ -85,23 +94,34 @@ public class RecipeController implements IRecipeHandler {
private void loadCategories(File file) throws Exception{
NBTTagCompound nbttagcompound1 = CompressedStreamTools.readCompressed(new FileInputStream(file));
nextId = nbttagcompound1.getInteger("LastId");
nextAnvilId = nbttagcompound1.getInteger("LastAnvilId");
NBTTagList list = nbttagcompound1.getTagList("Data", 10);
HashMap<Integer,RecipeCarpentry> globalRecipes = new HashMap<Integer, RecipeCarpentry>();
HashMap<Integer,RecipeCarpentry> anvilRecipes = new HashMap<Integer, RecipeCarpentry>();
HashMap<Integer,RecipeCarpentry> carpentryRecipes = new HashMap<Integer, RecipeCarpentry>();
HashMap<Integer,RecipeAnvil> anvilRecipes = new HashMap<Integer, RecipeAnvil>();
if(list != null){
for(int i = 0; i < list.tagCount(); i++)
{
RecipeCarpentry recipe = RecipeCarpentry.read(list.getCompoundTagAt(i));
if(recipe.isGlobal)
globalRecipes.put(recipe.id,recipe);
else
anvilRecipes.put(recipe.id,recipe);
if(recipe.id > nextId)
nextId = recipe.id;
NBTTagCompound compound = list.getCompoundTagAt(i);
if(compound.hasKey("IsAnvil")){
RecipeAnvil anvil = RecipeAnvil.read(compound);
anvilRecipes.put(anvil.id, anvil);
if(anvil.id > nextAnvilId)
nextAnvilId = anvil.id;
} else {
RecipeCarpentry recipe = RecipeCarpentry.read(compound);
if(recipe.isGlobal)
globalRecipes.put(recipe.id,recipe);
else
carpentryRecipes.put(recipe.id,recipe);
if(recipe.id > nextId)
nextId = recipe.id;
}
}
}
this.carpentryRecipes = anvilRecipes;
this.carpentryRecipes = carpentryRecipes;
this.globalRecipes = globalRecipes;
this.anvilRecipes = anvilRecipes;
loadDefaultRecipes(nbttagcompound1.getInteger("Version"));
}
private void saveCategories(){
@@ -114,9 +134,13 @@ public class RecipeController implements IRecipeHandler {
for(RecipeCarpentry recipe : carpentryRecipes.values()){
list.appendTag(recipe.writeNBT());
}
for(RecipeAnvil recipe : anvilRecipes.values()){
list.appendTag(recipe.writeNBT());
}
NBTTagCompound nbttagcompound = new NBTTagCompound();
nbttagcompound.setTag("Data", list);
nbttagcompound.setInteger("LastId", nextId);
nbttagcompound.setInteger("LastAnvilId", nextAnvilId);
nbttagcompound.setInteger("Version", version);
File file = new File(saveDir, "recipes.dat_new");
File file1 = new File(saveDir, "recipes.dat_old");
@@ -157,6 +181,12 @@ public class RecipeController implements IRecipeHandler {
return null;
}
public RecipeAnvil getAnvilRecipe(int id) {
if(anvilRecipes.containsKey(id))
return anvilRecipes.get(id);
return null;
}
public RecipeCarpentry saveRecipe(NBTTagCompound compound) throws IOException {
RecipeCarpentry recipe = RecipeCarpentry.read(compound);
@@ -184,9 +214,34 @@ public class RecipeController implements IRecipeHandler {
return recipe;
}
public RecipeAnvil saveAnvilRecipe(NBTTagCompound compound) throws IOException {
RecipeAnvil recipe = RecipeAnvil.read(compound);
RecipeAnvil current = getAnvilRecipe(recipe.id);
if(current != null && !current.name.equals(recipe.name)){
while(containsRecipeName(recipe.name))
recipe.name += "_";
}
if(recipe.id == -1){
recipe.id = getUniqueAnvilId();
while(containsRecipeName(recipe.name))
recipe.name += "_";
}
anvilRecipes.put(recipe.id, recipe);
saveCategories();
return recipe;
}
private int getUniqueId() {
return nextId++;
}
private int getUniqueAnvilId() {
return nextAnvilId++;
}
private boolean containsRecipeName(String name) {
name = name.toLowerCase();
for(RecipeCarpentry recipe : globalRecipes.values()){
@@ -200,6 +255,15 @@ public class RecipeController implements IRecipeHandler {
return false;
}
private boolean containsAnvilRecipeName(String name) {
name = name.toLowerCase();
for(RecipeAnvil recipe : anvilRecipes.values()){
if(recipe.name.toLowerCase().equals(name))
return true;
}
return false;
}
public RecipeCarpentry delete(int id) {
RecipeCarpentry recipe = getRecipe(id);
if(recipe == null)
@@ -210,29 +274,58 @@ public class RecipeController implements IRecipeHandler {
RecipeCarpentry carpentry = carpentryRecipes.remove(recipe.id);
if(carpentry != null)
SyncController.syncAllWorkbenchRecipes();
SyncController.syncAllCarpentryRecipes();
saveCategories();
reloadGlobalRecipes(globalRecipes);
return recipe;
}
public void addRecipe(RecipeCarpentry recipeAnvil) {
recipeAnvil.id = getUniqueId();
if(!recipeAnvil.isGlobal)
RecipeController.Instance.carpentryRecipes.put(recipeAnvil.id, recipeAnvil);
public RecipeAnvil deleteAnvil(int id) {
RecipeAnvil recipe = getAnvilRecipe(id);
if(recipe == null)
return null;
RecipeAnvil anvilRecipe = anvilRecipes.remove(recipe.id);
if(anvilRecipe != null)
// SyncController.syncAllWorkbenchRecipes();
saveCategories();
return recipe;
}
public void addRecipe(RecipeCarpentry recipeCarpentry) {
recipeCarpentry.id = getUniqueId();
if(!recipeCarpentry.isGlobal)
RecipeController.Instance.carpentryRecipes.put(recipeCarpentry.id, recipeCarpentry);
else{
RecipeController.Instance.globalRecipes.put(recipeAnvil.id, recipeAnvil);
RecipeController.Instance.globalRecipes.put(recipeCarpentry.id, recipeCarpentry);
}
}
public void addAnvilRecipe(RecipeAnvil recipeAnvil) {
recipeAnvil.id = getUniqueAnvilId();
anvilRecipes.put(recipeAnvil.id, recipeAnvil);
}
@Override
public List<IRecipe> getGlobalList() {
return new ArrayList(this.globalRecipes.values());
}
@Override
public List<IRecipe> getCarpentryList() {
return new ArrayList(this.carpentryRecipes.values());
}
@Override
public List<IAnvilRecipe> getAnvilList() {
List<IAnvilRecipe> list = new ArrayList<>();
list.addAll(anvilRecipes.values());
return list;
}
@Override
public void addRecipe(String name, boolean global, ItemStack result, Object... objects) {
RecipeCarpentry recipe = new RecipeCarpentry(name);
recipe.isGlobal = global;
@@ -245,6 +338,7 @@ public class RecipeController implements IRecipeHandler {
}
}
@Override
public void addRecipe(String name, boolean global, ItemStack result, int width, int height, ItemStack... objects) {
ArrayList<ItemStack> list = new ArrayList<>();
int var9 = objects.length;
@@ -266,4 +360,14 @@ public class RecipeController implements IRecipeHandler {
var12.printStackTrace();
}
}
@Override
public void addAnvilRecipe(String name, boolean global, ItemStack itemToRepair, ItemStack repairMaterial, int xpCost, float repairPercentage) {
RecipeAnvil recipe = new RecipeAnvil(name, itemToRepair, repairMaterial, xpCost, repairPercentage);
try {
this.saveAnvilRecipe(recipe.writeNBT());
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,111 @@
package noppes.npcs.controllers.data;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.api.handler.data.IAnvilRecipe;
import noppes.npcs.NoppesUtilPlayer;
import noppes.npcs.NoppesUtilServer;
public class RecipeAnvil implements IAnvilRecipe {
public int id = -1;
public String name = "";
public Availability availability = new Availability();
public boolean ignoreNBT = false;
public ItemStack itemToRepair;
public ItemStack repairMaterial;
private int xpCost;
private float repairPercentage;
private boolean isAnvil = true;
public RecipeAnvil() { }
public RecipeAnvil(String name, ItemStack itemToRepair, ItemStack repairMaterial, int xpCost, float repairPercentage) {
this.name = name;
this.itemToRepair = itemToRepair;
this.repairMaterial = repairMaterial;
this.xpCost = xpCost;
this.repairPercentage = repairPercentage;
}
public static RecipeAnvil read(NBTTagCompound compound) {
RecipeAnvil recipe = new RecipeAnvil();
recipe.id = compound.getInteger("ID");
recipe.name = compound.getString("Name");
recipe.availability.readFromNBT(compound.getCompoundTag("Availability"));
recipe.xpCost = compound.getInteger("XPCost");
recipe.repairPercentage = compound.getFloat("RepairPercentage");
recipe.itemToRepair = NoppesUtilServer.readItem(compound.getCompoundTag("ItemToRepair"));
recipe.repairMaterial = NoppesUtilServer.readItem(compound.getCompoundTag("RepairMaterial"));
recipe.isAnvil = true;
return recipe;
}
public NBTTagCompound writeNBT() {
NBTTagCompound compound = new NBTTagCompound();
compound.setInteger("ID", id);
compound.setString("Name", name);
compound.setTag("Availability", availability.writeToNBT(new NBTTagCompound()));
compound.setInteger("XPCost", xpCost);
compound.setFloat("RepairPercentage", repairPercentage);
compound.setTag("ItemToRepair", NoppesUtilServer.writeItem(itemToRepair, new NBTTagCompound()));
compound.setTag("RepairMaterial", NoppesUtilServer.writeItem(repairMaterial, new NBTTagCompound()));
compound.setBoolean("IsAnvil", true);
return compound;
}
public int getXpCost() {
return xpCost;
}
@Override
public float getRepairPercentage() {
return repairPercentage;
}
/**
* Checks that both input ItemStacks are non-null and match the recipe’s defined items.
*/
@Override
public boolean matches(ItemStack inputItem, ItemStack inputRepairMaterial) {
if (inputItem == null || inputRepairMaterial == null) return false;
if (!NoppesUtilPlayer.compareItems(this.itemToRepair, inputItem, true, false)) {
return false;
}
if (!NoppesUtilPlayer.compareItems(this.repairMaterial, inputRepairMaterial, false, false)) {
return false;
}
return true;
}
/**
* Returns a repaired copy of the input item by reducing its damage.
*/
@Override
public ItemStack getResult(ItemStack inputItem) {
if (inputItem == null)
return null;
ItemStack result = inputItem.copy();
if (!result.isItemStackDamageable())
return result;
int maxDamage = result.getMaxDamage();
int repairAmount = (int) (maxDamage * repairPercentage);
int currentDamage = result.getItemDamage();
int newDamage = currentDamage - repairAmount;
if (newDamage < 0) newDamage = 0;
result.setItemDamage(newDamage);
return result;
}
@Override
public String getName() {
return name;
}
@Override
public int getID() {
return this.id;
}
}
@@ -19,10 +19,10 @@ public class RecipesDefault {
else
item = (ItemStack) ob;
RecipeCarpentry recipeAnvil = new RecipeCarpentry(name);
recipeAnvil.isGlobal = isGlobal;
recipeAnvil = RecipeCarpentry.saveRecipe(recipeAnvil, item, recipe);
RecipeController.Instance.addRecipe(recipeAnvil);
RecipeCarpentry recipeCarpentry = new RecipeCarpentry(name);
recipeCarpentry.isGlobal = isGlobal;
recipeCarpentry = RecipeCarpentry.saveRecipe(recipeCarpentry, item, recipe);
RecipeController.Instance.addRecipe(recipeCarpentry);
}
public static void loadDefaultRecipes(int i) {
if(i < 0){