/**
* This class was created by <Vazkii>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [Mar 29, 2015, 10:13:32 PM (GMT)]
*/
package vazkii.botania.common.item.relic;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.google.common.collect.ImmutableList;
import baubles.api.BaubleType;
import baubles.api.BaublesApi;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Enchantments;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.items.IItemHandler;
import vazkii.botania.api.BotaniaAPI;
import vazkii.botania.api.item.ISequentialBreaker;
import vazkii.botania.api.item.IWireframeCoordinateListProvider;
import vazkii.botania.api.mana.IManaUsingItem;
import vazkii.botania.api.mana.ManaItemHandler;
import vazkii.botania.common.core.helper.ItemNBTHelper;
import vazkii.botania.common.item.ModItems;
import vazkii.botania.common.item.equipment.tool.ToolCommons;
import vazkii.botania.common.lib.LibItemNames;
public class ItemLokiRing extends ItemRelicBauble implements IWireframeCoordinateListProvider, IManaUsingItem {
private static final String TAG_CURSOR_LIST = "cursorList";
private static final String TAG_CURSOR_PREFIX = "cursor";
private static final String TAG_CURSOR_COUNT = "cursorCount";
private static final String TAG_X_OFFSET = "xOffset";
private static final String TAG_Y_OFFSET = "yOffset";
private static final String TAG_Z_OFFSET = "zOffset";
private static final String TAG_X_ORIGIN = "xOrigin";
private static final String TAG_Y_ORIGIN = "yOrigin";
private static final String TAG_Z_ORIGIN = "zOrigin";
public ItemLokiRing() {
super(LibItemNames.LOKI_RING);
MinecraftForge.EVENT_BUS.register(ItemLokiRing.class);
}
@SubscribeEvent
public static void onPlayerInteract(PlayerInteractEvent.RightClickBlock event) {
EntityPlayer player = event.getEntityPlayer();
ItemStack lokiRing = getLokiRing(player);
if(lokiRing.isEmpty() || !player.isSneaking())
return;
int slot = -1;
IItemHandler inv = BaublesApi.getBaublesHandler(player);
for(int i = 0; i < inv.getSlots(); i++) {
ItemStack stack = inv.getStackInSlot(i);
if(stack == lokiRing) {
slot = i;
break;
}
}
ItemStack heldItemStack = event.getItemStack();
BlockPos originCoords = getOriginPos(lokiRing);
RayTraceResult lookPos = ToolCommons.raytraceFromEntity(player.world, player, true, 10F);
List<BlockPos> cursors = getCursorList(lokiRing);
int cost = Math.min(cursors.size(), (int) Math.pow(Math.E, cursors.size() * 0.25));
if(lookPos == null || lookPos.getBlockPos() == null)
return;
if(heldItemStack.isEmpty()) {
if(!event.getWorld().isRemote) {
if(originCoords.getY() == -1) {
setOriginPos(lokiRing, lookPos.getBlockPos());
setCursorList(lokiRing, null);
BotaniaAPI.internalHandler.sendBaubleUpdatePacket(player, slot);
} else {
if(originCoords.equals(lookPos.getBlockPos())) {
setOriginPos(lokiRing, new BlockPos(0, -1, 0));
BotaniaAPI.internalHandler.sendBaubleUpdatePacket(player, slot);
} else {
addCursor : {
BlockPos relPos = lookPos.getBlockPos().add(new BlockPos(-originCoords.getX(), -originCoords.getY(), -originCoords.getZ()));
for(BlockPos cursor : cursors)
if(cursor.equals(relPos)) {
cursors.remove(cursor);
setCursorList(lokiRing, cursors);
BotaniaAPI.internalHandler.sendBaubleUpdatePacket(player, slot);
break addCursor;
}
addCursor(lokiRing, relPos);
BotaniaAPI.internalHandler.sendBaubleUpdatePacket(player, slot);
}
}
}
}
event.setCanceled(true);
event.setCancellationResult(EnumActionResult.SUCCESS);
} else {
for(BlockPos cursor : cursors) {
BlockPos pos = lookPos.getBlockPos().add(cursor);
Item item = heldItemStack.getItem();
if(player.world.isAirBlock(pos) && ManaItemHandler.requestManaExact(lokiRing, player, cost, true)) {
ItemStack saveHeld = heldItemStack.copy();
item.onItemUse(player, player.world, pos, event.getHand(), lookPos.sideHit, (float) lookPos.hitVec.xCoord - pos.getX(), (float) lookPos.hitVec.yCoord - pos.getY(), (float) lookPos.hitVec.zCoord - pos.getZ());
if (player.isCreative())
player.setHeldItem(event.getHand(), saveHeld);
}
}
}
}
public static void breakOnAllCursors(EntityPlayer player, Item item, ItemStack stack, BlockPos pos, EnumFacing side) {
ItemStack lokiRing = getLokiRing(player);
if(lokiRing.isEmpty() || player.world.isRemote || !(item instanceof ISequentialBreaker))
return;
List<BlockPos> cursors = getCursorList(lokiRing);
ISequentialBreaker breaker = (ISequentialBreaker) item;
World world = player.world;
boolean silk = EnchantmentHelper.getEnchantmentLevel(Enchantments.SILK_TOUCH, stack) > 0;
int fortune = EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, stack);
boolean dispose = breaker.disposeOfTrashBlocks(stack);
for (BlockPos coords : cursors) {
IBlockState state = world.getBlockState(coords);
breaker.breakOtherBlock(player, stack, coords, coords, side);
ToolCommons.removeBlockWithDrops(player, stack, player.world, coords, pos, state.getBlock(), Collections.singletonList(state.getMaterial()), silk, fortune, dispose);
}
}
@Override
public BaubleType getBaubleType(ItemStack arg0) {
return BaubleType.RING;
}
@Override
public void onUnequipped(ItemStack stack, EntityLivingBase player) {
setCursorList(stack, null);
}
@Override
@SideOnly(Side.CLIENT)
public List<BlockPos> getWireframesToDraw(EntityPlayer player, ItemStack stack) {
if(getLokiRing(player) != stack)
return ImmutableList.of();
RayTraceResult lookPos = Minecraft.getMinecraft().objectMouseOver;
if(lookPos != null && lookPos.getBlockPos() != null && !player.world.isAirBlock(lookPos.getBlockPos()) && lookPos.entityHit == null) {
List<BlockPos> list = getCursorList(stack);
BlockPos origin = getOriginPos(stack);
for (int i = 0; i < list.size(); i++) {
if (origin.getY() != -1) {
list.set(i, list.get(i).add(origin));
} else {
list.set(i, list.get(i).add(lookPos.getBlockPos()));
}
}
return list;
}
return ImmutableList.of();
}
@Override
public BlockPos getSourceWireframe(EntityPlayer player, ItemStack stack) {
return getLokiRing(player) == stack ? getOriginPos(stack) : null;
}
private static ItemStack getLokiRing(EntityPlayer player) {
IItemHandler baubles = BaublesApi.getBaublesHandler(player);
ItemStack stack1 = baubles.getStackInSlot(1);
ItemStack stack2 = baubles.getStackInSlot(2);
return isLokiRing(stack1) ? stack1 : isLokiRing(stack2) ? stack2 : ItemStack.EMPTY;
}
private static boolean isLokiRing(ItemStack stack) {
return !stack.isEmpty() && (stack.getItem() == ModItems.lokiRing || stack.getItem() == ModItems.aesirRing);
}
private static BlockPos getOriginPos(ItemStack stack) {
int x = ItemNBTHelper.getInt(stack, TAG_X_ORIGIN, 0);
int y = ItemNBTHelper.getInt(stack, TAG_Y_ORIGIN, -1);
int z = ItemNBTHelper.getInt(stack, TAG_Z_ORIGIN, 0);
return new BlockPos(x, y, z);
}
private static void setOriginPos(ItemStack stack, BlockPos pos) {
ItemNBTHelper.setInt(stack, TAG_X_ORIGIN, pos.getX());
ItemNBTHelper.setInt(stack, TAG_Y_ORIGIN, pos.getY());
ItemNBTHelper.setInt(stack, TAG_Z_ORIGIN, pos.getZ());
}
private static List<BlockPos> getCursorList(ItemStack stack) {
NBTTagCompound cmp = ItemNBTHelper.getCompound(stack, TAG_CURSOR_LIST, false);
List<BlockPos> cursors = new ArrayList<>();
int count = cmp.getInteger(TAG_CURSOR_COUNT);
for(int i = 0; i < count; i++) {
NBTTagCompound cursorCmp = cmp.getCompoundTag(TAG_CURSOR_PREFIX + i);
int x = cursorCmp.getInteger(TAG_X_OFFSET);
int y = cursorCmp.getInteger(TAG_Y_OFFSET);
int z = cursorCmp.getInteger(TAG_Z_OFFSET);
cursors.add(new BlockPos(x, y, z));
}
return cursors;
}
private static void setCursorList(ItemStack stack, List<BlockPos> cursors) {
if(stack == null)
return;
NBTTagCompound cmp = new NBTTagCompound();
if(cursors != null) {
int i = 0;
for(BlockPos cursor : cursors) {
NBTTagCompound cursorCmp = cursorToCmp(cursor);
cmp.setTag(TAG_CURSOR_PREFIX + i, cursorCmp);
i++;
}
cmp.setInteger(TAG_CURSOR_COUNT, i);
}
ItemNBTHelper.setCompound(stack, TAG_CURSOR_LIST, cmp);
}
private static NBTTagCompound cursorToCmp(BlockPos pos) {
NBTTagCompound cmp = new NBTTagCompound();
cmp.setInteger(TAG_X_OFFSET, pos.getX());
cmp.setInteger(TAG_Y_OFFSET, pos.getY());
cmp.setInteger(TAG_Z_OFFSET, pos.getZ());
return cmp;
}
private static void addCursor(ItemStack stack, BlockPos pos) {
NBTTagCompound cmp = ItemNBTHelper.getCompound(stack, TAG_CURSOR_LIST, false);
int count = cmp.getInteger(TAG_CURSOR_COUNT);
cmp.setTag(TAG_CURSOR_PREFIX + count, cursorToCmp(pos));
cmp.setInteger(TAG_CURSOR_COUNT, count + 1);
ItemNBTHelper.setCompound(stack, TAG_CURSOR_LIST, cmp);
}
@Override
public boolean usesMana(ItemStack stack) {
return true;
}
}