Skip to content

Instantly share code, notes, and snippets.

@Daomephsta
Created February 7, 2017 07:18
Show Gist options
  • Save Daomephsta/b0cd6c20384cc6ca5e13e5407e928378 to your computer and use it in GitHub Desktop.
Save Daomephsta/b0cd6c20384cc6ca5e13e5407e928378 to your computer and use it in GitHub Desktop.
package net.einsteinsci.betterbeginnings.tileentity;
import java.util.*;
import javax.annotation.Nullable;
import com.google.common.collect.Lists;
import net.einsteinsci.betterbeginnings.config.BBConfig;
import net.einsteinsci.betterbeginnings.inventory.ItemHandlerInfusionRepair;
import net.einsteinsci.betterbeginnings.register.RegisterItems;
import net.einsteinsci.betterbeginnings.register.recipe.elements.RecipeElement;
import net.einsteinsci.betterbeginnings.util.*;
import net.einsteinsci.betterbeginnings.util.Util;
import net.minecraft.block.state.IBlockState;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentData;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorldNameable;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.items.*;
public class TileEntityInfusionRepair extends TileEntity implements ITickable, IWorldNameable
{
private static final String INV_TAG = "Items";
private static final String MODE = "Mode";
private static final String CUSTOM_NAME = "CustomName";
private static final String HEALTH_TAKEN = "HealthTaken";
private static final String LEVELS_NEEDED = "LevelsNeeded";
private static final String LEVELS_TAKEN = "LevelsTaken";
private static final int SLOT_ENCH_ITEM = 0;
private static final Random rand = new Random();
private IItemHandlerModifiable mainHandler;
private Stack<RecipeElement> pendingIngredients = new Stack<RecipeElement>();
private Mode mode = Mode.NONE;
private float healthTaken;
private int xpLevelsTaken;
private int xpLevelsNeeded;
private AxisAlignedBB searchBox;
private String tileName;
public TileEntityInfusionRepair()
{
this.mainHandler = new ItemHandlerInfusionRepair(10);
}
public void activate(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, @Nullable ItemStack heldItem, EnumFacing side, float hitX, float hitY, float hitZ)
{
if(Prep1_11.isEmpty(heldItem) || hasEnchItem()) return;
if(heldItem.getItem() == RegisterItems.cloth)
{
mode = Mode.DIFFUSION;
}
else if(heldItem.isItemEnchanted())
{
mode = Mode.REPAIR;
pendingIngredients.clear();
pendingIngredients.addAll(InfusionRepairUtil.getRequiredStacks(heldItem));
xpLevelsNeeded = InfusionRepairUtil.getTakenLevels(heldItem);
}
else
return;
ItemStack newStack = heldItem.copy();
newStack.stackSize = 1;
mainHandler.setStackInSlot(heldItem.isItemEnchanted() ? SLOT_ENCH_ITEM : 1, newStack);
heldItem.stackSize--;
}
@Override
public void update()
{
switch (mode)
{
case NONE:
break;
case DIFFUSION:
absorbItems();
diffuse();
break;
case REPAIR:
absorbItems();
repair();
break;
default:
return;
}
}
private void absorbItems()
{
List<EntityItem> items = worldObj.getEntitiesWithinAABB(EntityItem.class, searchBox);
IBlockState state = worldObj.getBlockState(pos);
for (EntityItem entityItem : items)
{
if(tryAbsorbDroppedItem(entityItem, state))
{
markDirty();
worldObj.notifyBlockUpdate(pos, state, state, 8);
}
if(entityItem.getEntityItem().stackSize == 0)
entityItem.setDead();
}
}
private boolean tryAbsorbDroppedItem(EntityItem item, IBlockState state)
{
ItemStack newStack = Prep1_11.getEmptyStack();
ItemStack stack = item.getEntityItem();
switch(mode)
{
case DIFFUSION:
if(isIngredientPresent(stack)) return false;
if(stack.getItem() == Items.BOOK || stack.isItemEnchanted())
{
newStack = stack.copy();
newStack.stackSize = 1;
if(!worldObj.isRemote) stack.stackSize--;
}
break;
case REPAIR:
;
for(Iterator<RecipeElement> iter = pendingIngredients.iterator(); iter.hasNext();)
{
RecipeElement currentIngredient = iter.next();
if(currentIngredient.matches(stack))
{
newStack = stack.copy();
newStack.stackSize = Math.min(currentIngredient.getStackSize(), stack.stackSize);
currentIngredient.setStackSize(currentIngredient.getStackSize() - Math.min(currentIngredient.getStackSize(), stack.stackSize));
if(currentIngredient.getStackSize() == 0)
iter.remove();
if(!worldObj.isRemote) stack.stackSize -= newStack.stackSize;
break;
}
}
break;
default:
break;
}
if(newStack == null) return false;
boolean slotFound = false;
if(newStack.isItemEnchanted())
{
mainHandler.setStackInSlot(SLOT_ENCH_ITEM, newStack);
slotFound = true;
}
else
{
//attempt to insert stacks into inv
for(int s = SLOT_ENCH_ITEM + 1; s < mainHandler.getSlots(); s++)
{
ItemStack slotStack = mainHandler.getStackInSlot(s);
if (ItemHandlerHelper.canItemStacksStack(newStack, slotStack))
{
CapUtils.incrementStack(mainHandler, s, newStack.stackSize);
slotFound = true;
break;
}
if(Prep1_11.isEmpty(slotStack))
{
mainHandler.setStackInSlot(s, newStack);
slotFound = true;
break;
}
}
}
return slotFound;
}
private boolean isIngredientPresent(ItemStack stack)
{
for(int s = 0; s < mainHandler.getSlots(); s++)
{
ItemStack slotStack = mainHandler.getStackInSlot(s);
if(ItemStack.areItemsEqual(stack, slotStack) && ItemStack.areItemStackTagsEqual(stack, slotStack))
return true;
}
return false;
}
private void diffuse()
{
//Check all ingredients are present
if(canDiffuse())
{
IBlockState state = worldObj.getBlockState(pos);
//Find the enchanted item
ItemStack enchItem = mainHandler.getStackInSlot(SLOT_ENCH_ITEM);
//Take health
if(healthTaken != BBConfig.diffusionHealthTaken)
{
for (int i = 0; i < 2; i++)
{
double x = rand.nextDouble() * 0.4 + 0.3;
double y = rand.nextDouble() * 0.5 + 0.5;
double z = rand.nextDouble() * 0.4 + 0.3;
double vx = rand.nextDouble() * 0.02 - 0.01;
double vy = rand.nextDouble() * 0.035 + 0.02;
double vz = rand.nextDouble() * 0.02 - 0.01;
worldObj.spawnParticle(EnumParticleTypes.HEART, pos.getX() + x, pos.getY() + y + 1,
pos.getZ() + z, vx, vy, vz);
}
//Get player on top and damage them
List<EntityPlayer> playersOnTop = worldObj.getEntitiesWithinAABB(EntityPlayer.class, searchBox);
if(!playersOnTop.isEmpty())
{
EntityPlayer player = playersOnTop.get(0);
if (player.attackEntityFrom(Util.DIFFUSION_DAMAGE, 0.5F))
healthTaken += 0.5F;
}
worldObj.notifyBlockUpdate(pos, state, state, 8);
markDirty();
}
else
{
NBTTagList enchList = enchItem.getEnchantmentTagList();
if(enchList != null)
{
//Choose random enchant
int chosenEnchIndex = rand.nextInt(enchList.tagCount());
NBTTagCompound chosenEnchNBT = enchList.getCompoundTagAt(chosenEnchIndex);
EnchantmentData chosenEnchData = new EnchantmentData(Enchantment.getEnchantmentByID(chosenEnchNBT.getShort("id")), chosenEnchNBT.getShort("lvl"));
//Remove the enchant
enchList.removeTag(chosenEnchIndex);
if(enchList.hasNoTags()) enchItem.getTagCompound().removeTag("ench");
//Damage the ench item
if(enchItem.isItemStackDamageable())
enchItem.damageItem(enchItem.getMaxDamage() / 5, null);
if(enchItem.getItemDamage() > enchItem.getMaxDamage())
mainHandler.setStackInSlot(SLOT_ENCH_ITEM, null);
//Create an enchanted book for the enchantment
ItemStack enchBook = new ItemStack(Items.ENCHANTED_BOOK);
Items.ENCHANTED_BOOK.addEnchantment(enchBook, chosenEnchData);
//Spawn the enchanted book & the disenchanted item
if(!worldObj.isRemote)
{
worldObj.spawnEntityInWorld(new EntityItem(worldObj, pos.getX(), pos.getY() + 1, pos.getZ(), enchBook));
if(Prep1_11.isValid(mainHandler.getStackInSlot(SLOT_ENCH_ITEM)))
worldObj.spawnEntityInWorld(new EntityItem(worldObj, pos.getX(), pos.getY() + 1, pos.getZ(), mainHandler.getStackInSlot(SLOT_ENCH_ITEM)));
worldObj.notifyBlockUpdate(pos, state, state, 8);
markDirty();
}
//Consume everything else in the inventory
for(int s = 0; s < mainHandler.getSlots(); s++)
{
mainHandler.setStackInSlot(s, null);
}
worldObj.notifyBlockUpdate(pos, state, state, 8);
markDirty();
}
mode = Mode.NONE;
}
}
}
private void repair()
{
if(canRepair())
{
IBlockState state = worldObj.getBlockState(pos);
//Find the enchanted item
ItemStack enchItem = mainHandler.getStackInSlot(SLOT_ENCH_ITEM);
if(xpLevelsTaken < xpLevelsNeeded)
{
for (int i = 0; i < 2; i++)
{
double x = rand.nextDouble() * 0.8 + 0.3;
double y = rand.nextDouble() * 0.1 + 0.2;
double z = rand.nextDouble() * 0.8 + 0.3;
double vx = rand.nextDouble() * 0.02 - 0.01;
double vy = rand.nextDouble() * 0.035 + 0.02;
double vz = rand.nextDouble() * 0.02 - 0.01;
worldObj.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, pos.getX() + x, pos.getY() + y + 1,
pos.getZ() + z, vx, vy, vz);
}
//Get player on top and damage them
List<EntityPlayer> playersOnTop = worldObj.getEntitiesWithinAABB(EntityPlayer.class, searchBox);
if(!playersOnTop.isEmpty())
{
EntityPlayer player = playersOnTop.get(0);
player.removeExperienceLevel(1);
xpLevelsTaken++;
worldObj.notifyBlockUpdate(pos, state, state, 8);
markDirty();
}
}
else
{
enchItem.setItemDamage(0);
//Spawn the repair item
if(!worldObj.isRemote)
{
worldObj.spawnEntityInWorld(new EntityItem(worldObj, pos.getX(), pos.getY() + 1, pos.getZ(), mainHandler.getStackInSlot(SLOT_ENCH_ITEM)));
}
//Consume everything else in the inventory
for(int s = 0; s < mainHandler.getSlots(); s++)
{
mainHandler.setStackInSlot(s, null);
}
mode = Mode.NONE;
markDirty();
this.xpLevelsTaken = 0;
worldObj.notifyBlockUpdate(pos, state, state, 8);
}
}
}
private boolean canDiffuse()
{
boolean foundBook = false;
boolean foundEnchItem = false;
for(int s = 0; s < mainHandler.getSlots(); s++)
{
ItemStack stack = mainHandler.getStackInSlot(s);
if(Prep1_11.isValid(stack))
{
if(stack.getItem() == Items.BOOK)
foundBook = true;
else if(stack.isItemEnchanted())
foundEnchItem = true;
}
}
return foundBook && foundEnchItem;
}
private boolean canRepair()
{
return pendingIngredients.isEmpty();
}
private boolean hasEnchItem()
{
return mainHandler.getStackInSlot(SLOT_ENCH_ITEM) != null;//STACKNULL
}
public Stack<RecipeElement> getPendingIngredients()
{
return pendingIngredients;
}
@Override
public void setPos(BlockPos pos)
{
super.setPos(pos);
searchBox = new AxisAlignedBB(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 2, pos.getZ() + 1);
}
@Override
public SPacketUpdateTileEntity getUpdatePacket()
{
NBTTagCompound tag = new NBTTagCompound();
writeToNBT(tag);
return new SPacketUpdateTileEntity(pos, 1, tag);
}
@Override
public void onDataPacket(NetworkManager manager, SPacketUpdateTileEntity packet)
{
readFromNBT(packet.getNbtCompound());
}
@Override
public NBTTagCompound getUpdateTag()
{
return this.writeToNBT(new NBTTagCompound());
}
@Override
public void handleUpdateTag(NBTTagCompound tag)
{
this.readFromNBT(tag);
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
{
if(capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return true;
return super.hasCapability(capability, facing);
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
{
if(capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.cast(mainHandler);
return super.getCapability(capability, facing);
}
@Override
public String getName()
{
return tileName;
}
@Override
public boolean hasCustomName()
{
return tileName != null;
}
@Override
public void readFromNBT(NBTTagCompound compound)
{
super.readFromNBT(compound);
CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.readNBT(mainHandler, null, compound.getTag(INV_TAG));
mode = Mode.valueOf(compound.getString(MODE));
if (compound.hasKey(CUSTOM_NAME))
{
tileName = compound.getString(CUSTOM_NAME);
}
xpLevelsNeeded = compound.getInteger(LEVELS_NEEDED);
xpLevelsTaken = compound.getInteger(LEVELS_TAKEN);
healthTaken = compound.getFloat(HEALTH_TAKEN);
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound compound)
{
compound.setTag(INV_TAG, CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.writeNBT(mainHandler, null));
compound.setString(MODE, mode.name());
if (hasCustomName())
{
compound.setString(CUSTOM_NAME, tileName);
}
compound.setInteger(LEVELS_NEEDED, xpLevelsNeeded);
compound.setInteger(LEVELS_TAKEN, xpLevelsTaken);
compound.setFloat(HEALTH_TAKEN, healthTaken);
return super.writeToNBT(compound);
}
enum Mode
{
NONE,
DIFFUSION,
REPAIR;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment