package com.bioxx.tfc2.tileentities;
import java.util.ArrayList;
import java.util.UUID;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.World;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import com.bioxx.tfc2.Core;
import com.bioxx.tfc2.Reference;
import com.bioxx.tfc2.TFC;
import com.bioxx.tfc2.api.properties.PropertyItem;
import com.bioxx.tfc2.api.util.Helper;
import com.bioxx.tfc2.blocks.BlockAnvil;
import com.bioxx.tfc2.core.Timekeeper;
import com.bioxx.tfc2.networking.client.CAnvilStrikePacket;
import com.bioxx.tfc2.networking.server.SAnvilCraftingPacket;
public class TileAnvil extends TileTFC implements ITickable, IInventory
{
UUID smithID;
ItemStack[] inventory;
AnvilStrikePoint[] hitArray;
int anvilRecipeIndex = -1;
int craftingTimer = 0;
int craftingProgress = 0;
AnvilStrikeType strikeTarget;
ArrayList<Integer> availableHitPoints = new ArrayList<Integer>();
public TileAnvil()
{
smithID = new UUID(0L, 0L);
inventory = new ItemStack[3];
hitArray = new AnvilStrikePoint[24];
}
/***********************************************************************************
* 1. Content
***********************************************************************************/
@Override
public void update()
{
Timekeeper time = Timekeeper.getInstance();
if(craftingTimer > 0)
craftingTimer--;
generateStrikePoints();
resetStrikePoints();
if(craftingTimer == 0 && craftingProgress >= 100)
endCrafting(CraftingResult.SUCCEED);
else if(craftingTimer == 0)
endCrafting(CraftingResult.FAILED);
}
protected void generateStrikePoints()
{
Timekeeper time = Timekeeper.getInstance();
if(!worldObj.isRemote && craftingTimer > 0 && craftingTimer % 10 == 0)
{
AnvilStrikePoint p = new AnvilStrikePoint();
p.setBirthTime(time.getTotalTicks());
//Create Specials
if(worldObj.rand.nextFloat() < 0.25)
{
if(worldObj.rand.nextFloat() < 0.25)
{
int type = worldObj.rand.nextInt(3);
if(type == 0)
p.setType(AnvilStrikeType.EFF_CRIT);
else if(type == 1)
p.setType(AnvilStrikeType.DUR_CRIT);
else if(type == 2)
p.setType(AnvilStrikeType.DAM_CRIT);
else if(type == 3)
p.setType(AnvilStrikeType.SPD_CRIT);
p.setLifeTime(50);
}
else
{
int type = worldObj.rand.nextInt(3);
if(type == 0)
p.setType(AnvilStrikeType.EFF_NORM);
else if(type == 1)
p.setType(AnvilStrikeType.DUR_NORM);
else if(type == 2)
p.setType(AnvilStrikeType.DAM_NORM);
else if(type == 3)
p.setType(AnvilStrikeType.SPD_NORM);
p.setLifeTime(100);
}
}
else
{
int type = worldObj.rand.nextInt(7);
if(type == 0)
p.setType(AnvilStrikeType.HIT_LIGHT);
else if(type == 1)
p.setType(AnvilStrikeType.HIT_MEDIUM);
else if(type == 2)
p.setType(AnvilStrikeType.HIT_HEAVY);
else if(type == 3)
p.setType(AnvilStrikeType.HIT_BEND);
else if(type == 4)
p.setType(AnvilStrikeType.HIT_UPSET);
else if(type == 5)
p.setType(AnvilStrikeType.HIT_PUNCH);
else if(type == 6)
p.setType(AnvilStrikeType.HIT_SHRINK);
p.setLifeTime(100);
}
int xz = worldObj.rand.nextInt(availableHitPoints.size());
int index = availableHitPoints.remove(xz);
if(this.getStrikePoint(index) == null)
{
this.setStrikePoint(index, p);
sendSmithingPacket(index, p);
}
}
}
protected void resetStrikePoints()
{
Timekeeper time = Timekeeper.getInstance();
if(craftingTimer <= 0)
{
for(int i = 0; i < 24; i++)
{
AnvilStrikePoint p = hitArray[i];
if(p != null)
{
resetStrikePoint(i);
}
}
}
else
{
for(int i = 0; i < 24; i++)
{
AnvilStrikePoint p = hitArray[i];
if(p != null && p.getBirthTime()+p.getLifeTime() < time.getTotalTicks())
{
resetStrikePoint(i);
}
}
}
}
public boolean resetStrikePoint(int index)
{
if(index < 24 && this.getStrikePoint(index) != null)
{
this.setStrikePoint(index, null);
this.availableHitPoints.add(index);
return true;
}
return false;
}
public void hitStrikePoint(int index)
{
resetStrikePoint(index);
}
public void endCrafting(CraftingResult r)
{
anvilRecipeIndex = -1;//Resets the selected recipe
craftingTimer = -1;//This effectively turns off crafting stuff when we're done
switch(r)
{
case SUCCEED:
//Create the final item
break;
case FAILED:
//Do something if the smith fails
break;
}
//Send a packet to reset the info for the client
}
public void sendSmithingPacket(int xz, AnvilStrikePoint point)
{
EntityPlayerMP player = worldObj.getMinecraftServer().getPlayerList().getPlayerByUUID(smithID);
if(player != null)
TFC.network.sendTo(new CAnvilStrikePacket(this.getPos(), xz, point), player);
}
public IExtendedBlockState writeExtendedBlockState(IExtendedBlockState state)
{
state = setInventoryDisplay(state);
return state;
}
protected IExtendedBlockState setInventoryDisplay(IExtendedBlockState state)
{
PropertyItem.PropItems toDisplay = new PropertyItem.PropItems();
EnumFacing facing = state.getValue(BlockAnvil.FACING);
ItemStack stack = getStackInSlot(0);
float x = 0, z = 0;
if(stack != null)
{
if(getStackInSlot(1) != null)
{
if(facing == EnumFacing.NORTH)
x = 0.25f;
else if(facing == EnumFacing.SOUTH)
x = -0.25f;
else if(facing == EnumFacing.EAST)
z= 0.25f;
else
z= -0.25f;
}
PropertyItem.PItem item = getAnvilItem(stack, worldObj, null, x, z);
if(item != null) {
toDisplay.items.add(item);
}
}
stack = getStackInSlot(1);
x = 0; z = 0;
if(stack != null)
{
if(getStackInSlot(0) != null)
{
if(facing == EnumFacing.NORTH)
x = -0.25f;
else if(facing == EnumFacing.SOUTH)
x = 0.25f;
else if(facing == EnumFacing.EAST)
z= -0.25f;
else
z = 0.25f;
}
PropertyItem.PItem item = getAnvilItem(stack, worldObj, null, x, z);
if(item != null) {
toDisplay.items.add(item);
}
}
// add inventory if needed
return state.withProperty(BlockAnvil.INVENTORY, toDisplay);
}
@SideOnly(Side.CLIENT)
public static PropertyItem.PItem getAnvilItem(ItemStack stack, World world, EntityLivingBase entity, float x, float z) {
if(stack == null)
return null;
IBakedModel model = Minecraft.getMinecraft().getRenderItem().getItemModelWithOverrides(stack, world, entity);
if(model == null || model.isBuiltInRenderer()) {
// missing model so people don't go paranoid when their chests go missing
model = Minecraft.getMinecraft().getRenderItem().getItemModelMesher().getModelManager().getMissingModel();
}
PropertyItem.PItem item = new PropertyItem.PItem(model, x,0,z, 0.5f, (float) (Math.PI/2));
if(stack.getItem() instanceof ItemBlock) {
item.y = -0.3125f;
item.s = 0.375f;
item.r = 0;
}
return item;
}
@SideOnly(Side.CLIENT)
public void selectRecipe(int index)
{
this.anvilRecipeIndex = index;
}
public void startCrafting(UUID id)
{
if(worldObj.isRemote)
{
TFC.network.sendToServer(new SAnvilCraftingPacket(this.getPos(),this.getAnvilRecipeIndex(), true, id));
this.craftingTimer = 2000;
}
else
{
if(craftingTimer <= 0)
{
this.smithID = id;
this.craftingTimer = 2000;
for(int i = 0; i < 24; i++)
{
availableHitPoints.add(i);
}
}
}
}
/***********************************************************************************
* 2. Getters and Setters
***********************************************************************************/
public void setSmithID(EntityPlayer player)
{
smithID = EntityPlayer.getUUID(player.getGameProfile());
}
public EntityPlayer getSmith()
{
if(!worldObj.isRemote)
return worldObj.getMinecraftServer().getPlayerList().getPlayerByUUID(smithID);
else return TFC.proxy.getPlayer();
}
public void setStrikePoint(int index, AnvilStrikePoint point)
{
hitArray[index] = point;
if(point == null)
availableHitPoints.add(index);
}
public void setStrikePoint(int x, int z, AnvilStrikePoint point)
{
setStrikePoint(getStrikePointIndex(x, z), point);
}
public AnvilStrikePoint getStrikePoint(int index)
{
if(index < 0 || index > 23) return null;
return hitArray[index];
}
public AnvilStrikePoint getStrikePoint(int x, int z)
{
return getStrikePoint(getStrikePointIndex(x, z));
}
public static int getStrikePointIndex(int x, int z)
{
return z * 6 + x;
}
public int getAnvilRecipeIndex() {
return anvilRecipeIndex;
}
public void setAnvilRecipeIndex(int anvilRecipeIndex) {
this.anvilRecipeIndex = anvilRecipeIndex;
}
public int getTimer() {
return craftingTimer;
}
public void setTimer(int timer) {
this.craftingTimer = timer;
}
/***********************************************************************************
* 3. NBT Methods
***********************************************************************************/
@Override
public void readSyncableNBT(NBTTagCompound nbt)
{
NBTTagList invList = nbt.getTagList("inventory", 10);
inventory = Helper.readStackArrayFromNBTList(invList, getSizeInventory());
}
@Override
public void readNonSyncableNBT(NBTTagCompound nbt)
{
smithID = new UUID(nbt.getLong("farmerID_least"), nbt.getLong("farmerID_most"));
}
@Override
public void writeSyncableNBT(NBTTagCompound nbt)
{
NBTTagList invList = Helper.writeStackArrayToNBTList(inventory);
nbt.setTag("inventory", invList);
}
@Override
public void writeNonSyncableNBT(NBTTagCompound nbt)
{
nbt.setLong("farmerID_least", this.smithID.getLeastSignificantBits());
nbt.setLong("farmerID_most", this.smithID.getMostSignificantBits());
}
/*********************************************************
* IInventory Implementation
*********************************************************/
@Override
public String getName() {
return "Anvil";
}
@Override
public boolean hasCustomName() {
return false;
}
@Override
public ITextComponent getDisplayName() {
return null;
}
@Override
public int getSizeInventory() {
return 3;
}
@Override
public ItemStack getStackInSlot(int index) {
if(index < getSizeInventory())
return inventory[index];
return null;
}
@Override
public ItemStack decrStackSize(int index, int count)
{
if(inventory[index] != null)
{
if(inventory[index].stackSize <= count)
{
ItemStack itemstack = inventory[index];
inventory[index] = null;
TFC.proxy.sendToAllNear(getWorld(), getPos(), 200, this.getUpdatePacket());
return itemstack;
}
ItemStack itemstack1 = inventory[index].splitStack(count);
if(inventory[index].stackSize == 0)
inventory[index] = null;
return itemstack1;
}
else
return null;
}
@Override
public ItemStack removeStackFromSlot(int index)
{
if(index < getSizeInventory())
{
ItemStack out = inventory[index];
inventory[index] = null;
TFC.proxy.sendToAllNear(getWorld(), getPos(), 200, this.getUpdatePacket());
return out;
}
return null;
}
@Override
public void setInventorySlotContents(int index, ItemStack stack)
{
if(index < getSizeInventory())
{
inventory[index] = stack;
TFC.proxy.sendToAllNear(getWorld(), getPos(), 200, this.getUpdatePacket());
}
}
@Override
public int getInventoryStackLimit()
{
return 1;
}
@Override
public boolean isUseableByPlayer(EntityPlayer player)
{
return true;
}
@Override
public void openInventory(EntityPlayer player) {}
@Override
public void closeInventory(EntityPlayer player) {}
@Override
public boolean isItemValidForSlot(int index, ItemStack stack) {return true;}
@Override
public int getField(int id)
{
if(id == 0)
return this.getAnvilRecipeIndex();
return -1;
}
@Override
public void setField(int id, int value)
{
if(id == 0)
{
this.setAnvilRecipeIndex(value);
if(worldObj.isRemote)
{
TFC.network.sendToServer(new SAnvilCraftingPacket(this.getPos(), this.getAnvilRecipeIndex(), false, this.smithID));
}
}
}
@Override
public int getFieldCount() {
return 1;
}
@Override
public void clear() {
}
/*********************************************************
* Associated Classes
*********************************************************/
public static class AnvilStrikePoint
{
long birthTime;
int lifeTime;
AnvilStrikeType type;
public long getBirthTime() {
return birthTime;
}
public void setBirthTime(long timer) {
this.birthTime = timer;
}
public AnvilStrikeType getType() {
return type;
}
public void setType(AnvilStrikeType type) {
this.type = type;
}
public int getLifeTime() {
return lifeTime;
}
public void setLifeTime(int lifeTime) {
this.lifeTime = lifeTime;
}
}
public enum AnvilStrikeType
{
EFF_NORM(Core.CreateRes(Reference.ModID+":textures/blocks/anvil/eff_norm.png")),
EFF_CRIT(Core.CreateRes(Reference.ModID+":textures/blocks/anvil/eff_crit.png")),
DUR_NORM(Core.CreateRes(Reference.ModID+":textures/blocks/anvil/dur_norm.png")),
DUR_CRIT(Core.CreateRes(Reference.ModID+":textures/blocks/anvil/dur_crit.png")),
SPD_NORM(Core.CreateRes(Reference.ModID+":textures/blocks/anvil/spd_norm.png")),
SPD_CRIT(Core.CreateRes(Reference.ModID+":textures/blocks/anvil/spd_crit.png")),
DAM_NORM(Core.CreateRes(Reference.ModID+":textures/blocks/anvil/dam_norm.png")),
DAM_CRIT(Core.CreateRes(Reference.ModID+":textures/blocks/anvil/dam_crit.png")),
HIT_LIGHT(Core.CreateRes(Reference.ModID+":textures/gui/anvil_hit_light.png")),
HIT_MEDIUM(Core.CreateRes(Reference.ModID+":textures/gui/anvil_hit_medium.png")),
HIT_HEAVY(Core.CreateRes(Reference.ModID+":textures/gui/anvil_hit_heavy.png")),
HIT_BEND(Core.CreateRes(Reference.ModID+":textures/gui/anvil_bend.png")),
HIT_UPSET(Core.CreateRes(Reference.ModID+":textures/gui/anvil_upset.png")),
HIT_PUNCH(Core.CreateRes(Reference.ModID+":textures/gui/anvil_punch.png")),
HIT_SHRINK(Core.CreateRes(Reference.ModID+":textures/gui/anvil_shrink.png"));
ResourceLocation texture;
AnvilStrikeType(ResourceLocation image)
{
texture = image;
}
public ResourceLocation getTexture()
{
return texture;
}
}
public enum CraftingResult
{
SUCCEED, FAILED;
}
}