package crazypants.enderio.enchantment; import java.util.ListIterator; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.EnumEnchantmentType; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemArmor; import net.minecraft.item.ItemStack; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.event.entity.player.PlayerDropsEvent; import net.minecraftforge.event.entity.player.PlayerEvent; import com.enderio.core.api.common.enchant.IAdvancedEnchant; import cpw.mods.fml.common.eventhandler.EventPriority; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import crazypants.enderio.EnderIO; import crazypants.enderio.config.Config; import crazypants.util.BaublesUtil; import crazypants.util.GalacticraftUtil; public class EnchantmentSoulBound extends Enchantment implements IAdvancedEnchant { public static EnchantmentSoulBound create(int id) { EnchantmentSoulBound res = new EnchantmentSoulBound(id); MinecraftForge.EVENT_BUS.register(res); return res; } private final int id; private EnchantmentSoulBound(int id) { super(id, Config.enchantmentSoulBoundWeight, EnumEnchantmentType.all); this.id = id; setName("enderio.soulBound"); } @Override public int getMaxEnchantability(int level) { return super.getMaxEnchantability(level) + 30; } @Override public int getMinEnchantability(int level) { return super.getMinEnchantability(level); } @Override public int getMaxLevel() { return 1; } /* * This is called the moment the player dies and drops his stuff. * * We go early, so we can get our items before other mods put them into some * grave. Also remove them from the list so they won't get duped. If the * inventory overflows, e.g. because everything there and the armor is * soulbound, let the remainder be dropped/graved. */ @SubscribeEvent(priority = EventPriority.HIGHEST) public void onPlayerDeath(PlayerDropsEvent evt) { if (evt.entityPlayer == null || evt.entityPlayer instanceof FakePlayer || evt.isCanceled()) { return; } if(evt.entityPlayer.worldObj.getGameRules().getGameRuleBooleanValue("keepInventory")) { return; } ListIterator<EntityItem> iter = evt.drops.listIterator(); while (iter.hasNext()) { EntityItem ei = iter.next(); ItemStack item = ei.getEntityItem(); if(isSoulBound(item)) { if (addToPlayerInventory(evt.entityPlayer, item)) { iter.remove(); } } } // Note: Baubles will also add its items to evt.drops, but later. We cannot // wait for that because gravestone mods also listen to this event. So we have // to fetch Baubles items ourselves here. // For the same reason we cannot put the items into Baubles slots. IInventory baubles = BaublesUtil.instance().getBaubles(evt.entityPlayer); if (baubles != null) { for (int i = 0; i < baubles.getSizeInventory(); i++) { ItemStack item = baubles.getStackInSlot(i); if(isSoulBound(item)) { if (addToPlayerInventory(evt.entityPlayer, item)) { baubles.setInventorySlotContents(i, null); } } } } // Galacticraft. Again we are too early for those items. We just dump the // stuff into the normal inventory to not have to keep a separate list. if (evt.entityPlayer instanceof EntityPlayerMP) { IInventory galacticraft = GalacticraftUtil.getGCInventoryForPlayer((EntityPlayerMP) evt.entityPlayer); if (galacticraft != null) { for (int i = 0; i < galacticraft.getSizeInventory(); i++) { ItemStack item = galacticraft.getStackInSlot(i); if (isSoulBound(item)) { if (addToPlayerInventory(evt.entityPlayer, item)) { galacticraft.setInventorySlotContents(i, null); } } } } } } /* * This is called when the user presses the "respawn" button. The original * inventory would be empty, but onPlayerDeath() above placed items in it. * * Note: Without other death-modifying mods, the content of the old inventory * would always fit into the new one (both being empty but for soulbound items * in the old one) and the old one would be discarded just after this method. * But better play it safe and assume that an overflow is possible and that * another mod may move stuff out of the old inventory, too. */ @SubscribeEvent public void onPlayerClone(PlayerEvent.Clone evt) { if (!evt.wasDeath || evt.isCanceled()) { return; } if(evt.original == null || evt.entityPlayer == null || evt.entityPlayer instanceof FakePlayer) { return; } if(evt.entityPlayer.worldObj.getGameRules().getGameRuleBooleanValue("keepInventory")) { return; } for (int i = 0; i < evt.original.inventory.mainInventory.length; i++) { ItemStack item = evt.original.inventory.mainInventory[i]; if(isSoulBound(item)) { if (addToPlayerInventory(evt.entityPlayer, item)) { evt.original.inventory.mainInventory[i] = null; } } } for (int i = 0; i < evt.original.inventory.armorInventory.length; i++) { ItemStack item = evt.original.inventory.armorInventory[i]; if(isSoulBound(item)) { if (addToPlayerInventory(evt.entityPlayer, item)) { evt.original.inventory.armorInventory[i] = null; } } } } private boolean isSoulBound(ItemStack item) { return EnchantmentHelper.getEnchantmentLevel(id, item) > 0; } private boolean addToPlayerInventory(EntityPlayer entityPlayer, ItemStack item) { if(item == null || entityPlayer == null) { return false; } if(item.getItem() instanceof ItemArmor) { ItemArmor arm = (ItemArmor) item.getItem(); int index = 3 - arm.armorType; if(entityPlayer.inventory.armorItemInSlot(index) == null) { entityPlayer.inventory.armorInventory[index] = item; return true; } } InventoryPlayer inv = entityPlayer.inventory; for (int i = 0; i < inv.mainInventory.length; i++) { if(inv.mainInventory[i] == null) { inv.mainInventory[i] = item.copy(); return true; } } return false; } @Override public String[] getTooltipDetails(ItemStack stack) { return new String[] { EnderIO.lang.localizeExact("description.enchantment.enderio.soulBound") }; } }