package minefantasy.mf2.block.tileentity; import java.util.List; import java.util.Random; import minefantasy.mf2.MineFantasyII; import minefantasy.mf2.api.crafting.carpenter.CraftingManagerCarpenter; import minefantasy.mf2.api.crafting.carpenter.ICarpenter; import minefantasy.mf2.api.crafting.carpenter.ShapelessCarpenterRecipes; import minefantasy.mf2.api.helpers.ToolHelper; import minefantasy.mf2.api.knowledge.ResearchLogic; import minefantasy.mf2.api.rpg.RPGElements; import minefantasy.mf2.api.rpg.Skill; import minefantasy.mf2.api.rpg.SkillList; import minefantasy.mf2.container.ContainerCarpenterMF; import minefantasy.mf2.item.armour.ItemArmourMF; import minefantasy.mf2.network.packet.CarpenterPacket; import minefantasy.mf2.util.MFLogUtil; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.ItemArmor; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.WorldServer; public class TileEntityCarpenterMF extends TileEntity implements IInventory, ICarpenter { private int tier; private ItemStack[] inventory; private Random rand = new Random(); private int ticksExisted; private ContainerCarpenterMF syncCarpenter; private InventoryCrafting craftMatrix; private String lastPlayerHit = ""; private String toolTypeRequired = "hands"; private String craftSound = "step.wood"; private String researchRequired = ""; private Skill skillUsed; private boolean resetRecipe = false; public final int width = 4; public final int height = 4; public TileEntityCarpenterMF() { this(0); } public TileEntityCarpenterMF(int tier) { inventory = new ItemStack[width*height+5]; this.tier=tier; setContainer(new ContainerCarpenterMF(this)); } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); tier = nbt.getInteger("tier"); NBTTagList savedItems = nbt.getTagList("Items", 10); this.inventory = new ItemStack[this.getSizeInventory()]; for (int i = 0; i < savedItems.tagCount(); ++i) { NBTTagCompound savedSlot = savedItems.getCompoundTagAt(i); byte slotNum = savedSlot.getByte("Slot"); if (slotNum >= 0 && slotNum < this.inventory.length) { this.inventory[slotNum] = ItemStack.loadItemStackFromNBT(savedSlot); } } progress = nbt.getFloat("Progress"); progressMax = nbt.getFloat("ProgressMax"); resName = nbt.getString("ResultName"); toolTypeRequired = nbt.getString("toolTypeRequired"); craftSound = nbt.getString("craftSound"); researchRequired = nbt.getString("researchRequired"); } @Override public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); nbt.setInteger("tier", tier); NBTTagList savedItems = new NBTTagList(); for (int i = 0; i < this.inventory.length; ++i) { if (this.inventory[i] != null) { NBTTagCompound savedSlot = new NBTTagCompound(); savedSlot.setByte("Slot", (byte)i); this.inventory[i].writeToNBT(savedSlot); savedItems.appendTag(savedSlot); } } nbt.setTag("Items", savedItems); nbt.setFloat("Progress", progress); nbt.setFloat("ProgressMax", progressMax); nbt.setString("ResName", resName); nbt.setString("toolTypeRequired", toolTypeRequired); nbt.setString("craftSound", craftSound); nbt.setString("researchRequired", researchRequired); } @Override public int getSizeInventory() { return inventory.length; } @Override public ItemStack getStackInSlot(int slot) { return inventory[slot]; } @Override public ItemStack decrStackSize(int slot, int num) { onInventoryChanged(); if (this.inventory[slot] != null) { ItemStack itemstack; if (this.inventory[slot].stackSize <= num) { itemstack = this.inventory[slot]; this.inventory[slot] = null; return itemstack; } else { itemstack = this.inventory[slot].splitStack(num); if (this.inventory[slot].stackSize == 0) { this.inventory[slot] = null; } return itemstack; } } else { return null; } } @Override public ItemStack getStackInSlotOnClosing(int slot) { return inventory[slot]; } @Override public void setInventorySlotContents(int slot, ItemStack item) { onInventoryChanged(); inventory[slot] = item; } @Override public String getInventoryName() { return "gui.carpentermf.name"; } @Override public boolean hasCustomInventoryName() { return false; } @Override public int getInventoryStackLimit() { return 64; } @Override public boolean isUseableByPlayer(EntityPlayer user) { return user.getDistance(xCoord+0.5D, yCoord+0.5D, zCoord+0.5D) < 8D; } @Override public void openInventory() { } @Override public void closeInventory() { } @Override public boolean isItemValidForSlot(int slot, ItemStack item) { return true; } @Override public void updateEntity() { ++ticksExisted; super.updateEntity(); if(!worldObj.isRemote) { if(ticksExisted % 20 == 0) { updateCraftingData(); } if(!canCraft() && ticksExisted > 1) { progress = progressMax = 0; this.resName = ""; this.recipe = null; } } resetRecipe = false; } public void onInventoryChanged() { MFLogUtil.logDebug("Carpenter: Control Inv Tick"); if(!resetRecipe) { updateCraftingData(); MFLogUtil.logDebug("Carpenter: Optimised Inv Tick"); resetRecipe = true; } } public boolean tryCraft(EntityPlayer user) { if(user == null)return false; String toolType = ToolHelper.getCrafterTool(user.getHeldItem()); int hammerTier = ToolHelper.getCrafterTier(user.getHeldItem()); if(!toolType.equalsIgnoreCase("nothing")) { if(user.getHeldItem() != null) { user.getHeldItem().damageItem(1, user); if(user.getHeldItem().getItemDamage() >= user.getHeldItem().getMaxDamage()) { if(worldObj.isRemote) user.renderBrokenItemStack(user.getHeldItem()); user.destroyCurrentEquippedItem(); } } if(worldObj.isRemote) return true; if(doesPlayerKnowCraft(user) && canCraft() && toolType.equalsIgnoreCase(toolTypeRequired) && tier >= CarpenterTierRequired && hammerTier >= hammerTierRequired) { worldObj.playSoundEffect(xCoord+0.5D, yCoord+0.5D, zCoord+0.5D, getUseSound(), 1.0F, 1.0F); float efficiency = ToolHelper.getCrafterEfficiency(user.getHeldItem()); if(user.swingProgress > 0 && user.swingProgress <= 1.0) { efficiency *= (0.5F-user.swingProgress); } progress += Math.max(0.2F, efficiency); if(progress >= progressMax) { craftItem(user); } } else { worldObj.playSoundEffect(xCoord+0.5D, yCoord+0.5D, zCoord+0.5D, "step.stone", 1.25F, 1.5F); } lastPlayerHit = user.getCommandSenderName(); updateCraftingData(); return true; } updateCraftingData(); return false; } private String getUseSound() { if(craftSound.equalsIgnoreCase("engineering")) { if(rand.nextInt(5) == 0) { return "random.click"; } if(rand.nextInt(20) == 0) { return "random.door_open"; } return "step.wood"; } return craftSound; } private void craftItem(EntityPlayer user) { if (this.canCraft()) { addXP(user); ItemStack result = recipe.copy(); if(result != null && result.getItem() instanceof ItemArmourMF) { result = modifyArmour(result); } int output = getOutputSlotNum(); if (this.inventory[output] == null) { if(result.getMaxStackSize() == 1 && lastPlayerHit.length() > 0) { getNBT(result).setString("MF_CraftedByName", lastPlayerHit); } this.inventory[output] = result; } else if (this.inventory[output].getItem() == result.getItem()) { this.inventory[output].stackSize += result.stackSize; // Forge BugFix: Results may have multiple items } consumeResources(); } onInventoryChanged(); progress = 0; } private int getOutputSlotNum() { return getSizeInventory()-5; } private ItemStack modifyArmour(ItemStack result) { ItemArmourMF item = (ItemArmourMF)result.getItem(); boolean canColour = item.canColour(); int colour = -1; for(int a = 0; a < getOutputSlotNum(); a++) { ItemStack slot = getStackInSlot(a); if(slot != null && slot.getItem() instanceof ItemArmor) { ItemArmor slotitem = (ItemArmor)slot.getItem(); if(canColour && slotitem.hasColor(slot)) { colour = slotitem.getColor(slot); } if(result.isItemStackDamageable()) { result.setItemDamage(slot.getItemDamage()); } } } if(colour != -1 && canColour) { item.func_82813_b(result, colour); } return result; } private NBTTagCompound getNBT(ItemStack item) { if(!item.hasTagCompound()) { item.setTagCompound(new NBTTagCompound()); } return item.getTagCompound(); } private void dropItem(ItemStack itemstack) { if (itemstack != null) { float f = this.rand .nextFloat() * 0.8F + 0.1F; float f1 = this.rand.nextFloat() * 0.8F + 0.1F; float f2 = this.rand.nextFloat() * 0.8F + 0.1F; while (itemstack.stackSize > 0) { int j1 = this.rand.nextInt(21) + 10; if (j1 > itemstack.stackSize) { j1 = itemstack.stackSize; } itemstack.stackSize -= j1; EntityItem entityitem = new EntityItem(worldObj, xCoord + f, yCoord + f1, zCoord + f2, new ItemStack(itemstack.getItem(), j1, itemstack.getItemDamage())); if (itemstack.hasTagCompound()) { entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy()); } float f3 = 0.05F; entityitem.motionX = (float)this.rand.nextGaussian() * f3; entityitem.motionY = (float)this.rand.nextGaussian() * f3 + 0.2F; entityitem.motionZ = (float)this.rand.nextGaussian() * f3; worldObj.spawnEntityInWorld(entityitem); } } } public void syncData() { if(worldObj.isRemote)return; List<EntityPlayer> players = ((WorldServer)worldObj).playerEntities; for(int i = 0; i < players.size(); i++) { EntityPlayer player = players.get(i); ((WorldServer)worldObj).getEntityTracker().func_151248_b(player, new CarpenterPacket(this).generatePacket()); } } public String resName = "<No Project Set>"; public String getResultName() { if(!worldObj.isRemote && recipe != null && recipe.getItem() != null && recipe.getDisplayName() != null) { resName = recipe.getDisplayName(); } return resName; } public String getToolNeeded() { return toolTypeRequired; } public String getCraftingSound() { return craftSound; } public int getToolTierNeeded() { return this.hammerTierRequired; } public int getCarpenterTierNeeded() { return this.CarpenterTierRequired; } public void consumeResources() { resetRecipe = true; for(int slot = 0; slot < getOutputSlotNum(); slot++) { ItemStack item = getStackInSlot(slot); if(item != null && item.getItem() != null && item.getItem().getContainerItem(item) != null) { if(item.stackSize == 1) { setInventorySlotContents(slot, item.getItem().getContainerItem(item)); } else { ItemStack drop = processSurplus(item.getItem().getContainerItem(item)); if(drop != null) { this.dropItem(drop); } this.decrStackSize(slot, 1); } } else { this.decrStackSize(slot, 1); } } resetRecipe = false; this.onInventoryChanged(); } private ItemStack processSurplus(ItemStack item) { for(int a = 0; a < 4; a++) { if(item == null) { return null;//If item was sorted } int s = getSizeInventory()-4 + a; ItemStack slot = inventory[s]; if(slot == null) { setInventorySlotContents(s, item); return null;//All Placed } else { if(slot.isItemEqual(item) && slot.stackSize < slot.getMaxStackSize()) { if(slot.stackSize + item.stackSize <= slot.getMaxStackSize()) { slot.stackSize += item.stackSize; return null;//All Shared } else { int room_left = slot.getMaxStackSize() - slot.stackSize; slot.stackSize += room_left; item.stackSize -= room_left;//Share } } } } return item; } private boolean canFitResult(ItemStack result) { ItemStack resSlot = inventory[getOutputSlotNum()]; if(resSlot != null && result != null) { if(!resSlot.isItemEqual(result)) { return false; } if(resSlot.stackSize + result.stackSize > resSlot.getMaxStackSize()) { return false; } } return true; } //CRAFTING CODE public ItemStack getResult() { if(syncCarpenter == null || craftMatrix == null) { return null; } if(ticksExisted <= 1) return null; for(int a = 0 ; a < getOutputSlotNum() ; a ++) { craftMatrix.setInventorySlotContents(a, inventory[a]); } return CraftingManagerCarpenter.getInstance().findMatchingRecipe(this, craftMatrix); } public void updateCraftingData() { if(!worldObj.isRemote) { ItemStack oldRecipe = recipe; recipe = getResult(); //syncItems(); if (!canCraft() && progress > 0) { progress = 0; //quality = 100; } if(recipe != null && oldRecipe != null && !recipe.isItemEqual(oldRecipe)) { progress = 0; } if(progress > progressMax)progress = progressMax-1; syncData(); } } public boolean canCraft() { if(worldObj.isRemote) { //return canCraft == 1; } if(progressMax > 0 && recipe != null && recipe instanceof ItemStack) { return this.canFitResult(recipe); } return false; } private ItemStack recipe; public float progressMax; public float progress; private int hammerTierRequired; private int CarpenterTierRequired; @Override public void setForgeTime(int i) { progressMax = i; } @Override public void setToolTier(int i) { hammerTierRequired = i; } @Override public void setRequiredCarpenter(int i) { CarpenterTierRequired = i; } @Override public void setHotOutput(boolean i) { } public void setContainer(ContainerCarpenterMF container) { syncCarpenter = container; craftMatrix = new InventoryCrafting(syncCarpenter, ShapelessCarpenterRecipes.globalWidth, ShapelessCarpenterRecipes.globalHeight); } public boolean shouldRenderCraftMetre() { return recipe != null; } public int getProgressBar(int i) { return (int)Math.ceil(i / progressMax * progress); } @Override public void setToolType(String toolType) { this.toolTypeRequired = toolType; } @Override public void setCraftingSound(String sound) { this.craftSound = sound; } @Override public void setResearch(String research) { this.researchRequired = research; } public String getResearchNeeded() { return researchRequired; } public boolean doesPlayerKnowCraft(EntityPlayer user) { if(getResearchNeeded().isEmpty()) { return true; } return ResearchLogic.hasInfoUnlocked(user, getResearchNeeded()); } private void addXP(EntityPlayer smith) { if(skillUsed != null) { float baseXP = this.progressMax / 10F; skillUsed.addXP(smith, (int)baseXP + 1); } } @Override public void setSkill(Skill skill) { skillUsed = skill; } }