package WayofTime.bloodmagic.item; import java.util.ArrayList; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.input.Keyboard; import WayofTime.bloodmagic.BloodMagic; import WayofTime.bloodmagic.api.Constants; import WayofTime.bloodmagic.api.registry.RitualRegistry; import WayofTime.bloodmagic.api.ritual.EnumRuneType; import WayofTime.bloodmagic.api.ritual.Ritual; import WayofTime.bloodmagic.api.ritual.RitualComponent; import WayofTime.bloodmagic.api.util.helper.RitualHelper; import WayofTime.bloodmagic.client.IVariantProvider; import WayofTime.bloodmagic.registry.ModBlocks; import WayofTime.bloodmagic.tile.TileMasterRitualStone; import WayofTime.bloodmagic.util.ChatUtil; import WayofTime.bloodmagic.util.helper.TextHelper; public class ItemRitualDiviner extends Item implements IVariantProvider { public static String[] names = { "normal", "dusk", "dawn" }; public static final String tooltipBase = "tooltip.BloodMagic.diviner."; public ItemRitualDiviner() { setUnlocalizedName(Constants.Mod.MODID + ".ritualDiviner"); setRegistryName(Constants.BloodMagicItem.RITUAL_DIVINER.getRegName()); setCreativeTab(BloodMagic.tabBloodMagic); setHasSubtypes(true); setMaxStackSize(1); } @Override public String getUnlocalizedName(ItemStack stack) { return super.getUnlocalizedName(stack) + names[stack.getItemDamage()]; } @Override @SideOnly(Side.CLIENT) public void getSubItems(Item id, CreativeTabs creativeTab, List list) { for (int i = 0; i < names.length; i++) list.add(new ItemStack(id, 1, i)); } @Override public EnumActionResult onItemUse(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) { if (addRuneToRitual(stack, world, pos, player)) { if (world.isRemote) { spawnParticles(world, pos.up(), 15); } return EnumActionResult.SUCCESS; // TODO: Have the diviner automagically build the ritual } return EnumActionResult.PASS; } /** * Adds a single rune to the ritual. * * @param stack * - The Ritual Diviner stack * @param world * - The World * @param pos * - Block Position of the MRS. * @param player * - The Player attempting to place the ritual * * @return - True if a rune was successfully added */ public boolean addRuneToRitual(ItemStack stack, World world, BlockPos pos, EntityPlayer player) { TileEntity tile = world.getTileEntity(pos); if (tile instanceof TileMasterRitualStone) { Ritual ritual = RitualRegistry.getRitualForId(this.getCurrentRitual(stack)); if (ritual != null) { EnumFacing direction = getDirection(stack); for (RitualComponent component : ritual.getComponents()) { if (!canPlaceRitualStone(component.getRuneType(), stack)) { return false; } BlockPos offset = component.getOffset(direction); BlockPos newPos = pos.add(offset); IBlockState state = world.getBlockState(newPos); Block block = state.getBlock(); if (RitualHelper.isRune(world, newPos)) { if (RitualHelper.isRuneType(world, newPos, component.getRuneType())) { continue; } else { // Replace existing ritual stone RitualHelper.setRuneType(world, newPos, component.getRuneType()); return true; } } else if (block.isAir(state, world, newPos)) { if (!consumeStone(stack, world, player)) { return false; } int meta = component.getRuneType().ordinal(); IBlockState newState = ModBlocks.ritualStone.getStateFromMeta(meta); world.setBlockState(newPos, newState); return true; } else { return false; // TODO: Possibly replace the block with a // ritual stone } } } } return false; } // TODO: Make this work for any IRitualStone public boolean consumeStone(ItemStack stack, World world, EntityPlayer player) { if (player.capabilities.isCreativeMode) { return true; } ItemStack[] inventory = player.inventory.mainInventory; for (int i = 0; i < inventory.length; i++) { ItemStack newStack = inventory[i]; if (newStack == null) { continue; } Item item = newStack.getItem(); if (item instanceof ItemBlock) { Block block = ((ItemBlock) item).getBlock(); if (block == ModBlocks.ritualStone) { newStack.stackSize--; if (newStack.stackSize <= 0) { inventory[i] = null; } return true; } } } return false; } @Override @SideOnly(Side.CLIENT) public void addInformation(ItemStack stack, EntityPlayer player, List tooltip, boolean advanced) { Ritual ritual = RitualRegistry.getRitualForId(this.getCurrentRitual(stack)); if (ritual != null) { tooltip.add(TextHelper.localize("tooltip.BloodMagic.diviner.currentRitual") + TextHelper.localize(ritual.getUnlocalizedName())); boolean sneaking = Keyboard.isKeyDown(Keyboard.KEY_RSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_LSHIFT); if (sneaking) { tooltip.add(TextHelper.localize(tooltipBase + "currentDirection", getDirection(stack))); tooltip.add(""); ArrayList componentList = ritual.getComponents(); int blankRunes = 0; int airRunes = 0; int waterRunes = 0; int fireRunes = 0; int earthRunes = 0; int duskRunes = 0; int dawnRunes = 0; int totalRunes = 0; for (RitualComponent component : componentList) { totalRunes++; switch (component.getRuneType()) { case BLANK: blankRunes++; break; case AIR: airRunes++; break; case EARTH: earthRunes++; break; case FIRE: fireRunes++; break; case WATER: waterRunes++; break; case DUSK: duskRunes++; break; case DAWN: dawnRunes++; break; } } if (blankRunes > 0) { tooltip.add(TextHelper.localize(tooltipBase + "blankRune", blankRunes)); } if (waterRunes > 0) { tooltip.add(TextHelper.localize(tooltipBase + "waterRune", waterRunes)); } if (airRunes > 0) { tooltip.add(TextHelper.localize(tooltipBase + "airRune", airRunes)); } if (fireRunes > 0) { tooltip.add(TextHelper.localize(tooltipBase + "fireRune", fireRunes)); } if (earthRunes > 0) { tooltip.add(TextHelper.localize(tooltipBase + "earthRune", earthRunes)); } if (duskRunes > 0) { tooltip.add(TextHelper.localize(tooltipBase + "duskRune", duskRunes)); } if (dawnRunes > 0) { tooltip.add(TextHelper.localize(tooltipBase + "dawnRune", dawnRunes)); } tooltip.add(""); tooltip.add(TextHelper.localize(tooltipBase + "totalRune", totalRunes)); } else { tooltip.add(""); tooltip.add(TextHelper.localize(tooltipBase + "extraInfo")); } } } @Override public ActionResult onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand) { if (player.isSneaking() && !world.isRemote) { cycleRitual(stack, player); return new ActionResult(EnumActionResult.SUCCESS, stack); } return new ActionResult(EnumActionResult.PASS, stack); } @Override public boolean onEntitySwing(EntityLivingBase entityLiving, ItemStack stack) { if (entityLiving instanceof EntityPlayer) { EntityPlayer player = (EntityPlayer) entityLiving; if (!player.isSwingInProgress) { if (player.isSneaking()) { cycleRitualBackwards(stack, player); } else { cycleDirection(stack, player); } } } return false; } @Override public List> getVariants() { List> ret = new ArrayList>(); ret.add(new ImmutablePair(0, "type=basic")); ret.add(new ImmutablePair(1, "type=dusk")); ret.add(new ImmutablePair(2, "type=dawn")); return ret; } public void cycleDirection(ItemStack stack, EntityPlayer player) { EnumFacing direction = getDirection(stack); EnumFacing newDirection; switch (direction) { case NORTH: newDirection = EnumFacing.EAST; break; case EAST: newDirection = EnumFacing.SOUTH; break; case SOUTH: newDirection = EnumFacing.WEST; break; case WEST: newDirection = EnumFacing.NORTH; break; default: newDirection = EnumFacing.NORTH; } setDirection(stack, newDirection); notifyDirectionChange(newDirection, player); } public void notifyDirectionChange(EnumFacing direction, EntityPlayer player) { ChatUtil.sendNoSpam(player, TextHelper.localize(tooltipBase + "currentDirection", direction.getName())); } public void setDirection(ItemStack stack, EnumFacing direction) { if (!stack.hasTagCompound()) { stack.setTagCompound(new NBTTagCompound()); } NBTTagCompound tag = stack.getTagCompound(); tag.setInteger(Constants.NBT.DIRECTION, direction.getIndex()); } public EnumFacing getDirection(ItemStack stack) { if (!stack.hasTagCompound()) { stack.setTagCompound(new NBTTagCompound()); return EnumFacing.NORTH; } NBTTagCompound tag = stack.getTagCompound(); int dir = tag.getInteger(Constants.NBT.DIRECTION); if (dir == 0) { return EnumFacing.NORTH; } return EnumFacing.VALUES[tag.getInteger(Constants.NBT.DIRECTION)]; } /** * Cycles the selected ritual to the next available ritual that is enabled. * * @param stack * - The ItemStack of the ritual diviner * @param player * - The player using the ritual diviner */ public void cycleRitual(ItemStack stack, EntityPlayer player) { String key = getCurrentRitual(stack); List idList = RitualRegistry.getOrderedIds(); String firstId = ""; boolean foundId = false; boolean foundFirst = false; for (String str : idList) { Ritual ritual = RitualRegistry.getRitualForId(str); if (!RitualRegistry.ritualEnabled(ritual) || !canDivinerPerformRitual(stack, ritual)) { continue; } if (!foundFirst) { firstId = str; foundFirst = true; } if (foundId) { setCurrentRitual(stack, str); notifyRitualChange(str, player); return; } else { if (str.equals(key)) { foundId = true; continue; } } } if (foundFirst) { setCurrentRitual(stack, firstId); notifyRitualChange(firstId, player); } } /** * Does the same as cycleRitual but instead cycles backwards. * * @param stack * @param player */ public void cycleRitualBackwards(ItemStack stack, EntityPlayer player) { String key = getCurrentRitual(stack); List idList = RitualRegistry.getOrderedIds(); String firstId = ""; boolean foundId = false; boolean foundFirst = false; for (int i = idList.size() - 1; i >= 0; i--) { String str = idList.get(i); Ritual ritual = RitualRegistry.getRitualForId(str); if (!RitualRegistry.ritualEnabled(ritual) || !canDivinerPerformRitual(stack, ritual)) { continue; } if (!foundFirst) { firstId = str; foundFirst = true; } if (foundId) { setCurrentRitual(stack, str); notifyRitualChange(str, player); return; } else { if (str.equals(key)) { foundId = true; continue; } } } if (foundFirst) { setCurrentRitual(stack, firstId); notifyRitualChange(firstId, player); } } public boolean canDivinerPerformRitual(ItemStack stack, Ritual ritual) { if (ritual == null) { return false; } ArrayList components = ritual.getComponents(); for (RitualComponent component : components) { if (!canPlaceRitualStone(component.getRuneType(), stack)) { return false; } } return true; } public void notifyRitualChange(String key, EntityPlayer player) { Ritual ritual = RitualRegistry.getRitualForId(key); if (ritual != null) { ChatUtil.sendNoSpam(player, TextHelper.localize(tooltipBase + "currentRitual") + TextHelper.localize(ritual.getUnlocalizedName())); } } public void setCurrentRitual(ItemStack stack, String key) { if (!stack.hasTagCompound()) { stack.setTagCompound(new NBTTagCompound()); } NBTTagCompound tag = stack.getTagCompound(); tag.setString(Constants.NBT.CURRENT_RITUAL, key); } public String getCurrentRitual(ItemStack stack) { if (!stack.hasTagCompound()) { stack.setTagCompound(new NBTTagCompound()); } NBTTagCompound tag = stack.getTagCompound(); return tag.getString(Constants.NBT.CURRENT_RITUAL); } public boolean canPlaceRitualStone(EnumRuneType rune, ItemStack stack) { int meta = stack.getItemDamage(); switch (rune) { case BLANK: case AIR: case EARTH: case FIRE: case WATER: return true; case DUSK: return meta >= 1; case DAWN: return meta >= 2; } return false; } public static void spawnParticles(World worldIn, BlockPos pos, int amount) { IBlockState state = worldIn.getBlockState(pos); Block block = worldIn.getBlockState(pos).getBlock(); if (block.isAir(state, worldIn, pos)) { for (int i = 0; i < amount; ++i) { double d0 = itemRand.nextGaussian() * 0.02D; double d1 = itemRand.nextGaussian() * 0.02D; double d2 = itemRand.nextGaussian() * 0.02D; worldIn.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, (double) ((float) pos.getX() + itemRand.nextFloat()), (double) pos.getY() + (double) itemRand.nextFloat(), (double) ((float) pos.getZ() + itemRand.nextFloat()), d0, d1, d2, new int[0]); } } else { for (int i1 = 0; i1 < amount; ++i1) { double d0 = itemRand.nextGaussian() * 0.02D; double d1 = itemRand.nextGaussian() * 0.02D; double d2 = itemRand.nextGaussian() * 0.02D; worldIn.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, (double) ((float) pos.getX() + itemRand.nextFloat()), (double) pos.getY() + (double) itemRand.nextFloat() * 1.0f, (double) ((float) pos.getZ() + itemRand.nextFloat()), d0, d1, d2, new int[0]); } } } }