Files
Wizardry/src/main/java/electroblob/wizardry/enchantment/Imbuement.java
T

157 lines
6.4 KiB
Java

package electroblob.wizardry.enchantment;
import com.google.common.collect.Iterables;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryEnchantments;
import electroblob.wizardry.spell.FreezingWeapon;
import electroblob.wizardry.spell.ImbueWeapon;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.init.Items;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemEnchantedBook;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.item.ItemTossEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import java.util.Iterator;
/**
* Interface for temporary enchantments that last for a certain duration ('imbuements'). This interface allows
* {@link EnchantmentMagicSword} and {@link EnchantmentTimed} to both be treated as instances of a single type, rather
* than having to deal with each of them separately, which would be inefficient and cumbersome (the former of those
* classes cannot extend the latter because they both need to extend different subclasses of
* {@link net.minecraft.enchantment.Enchantment}).
*
* @since Wizardry 1.2
*/
@Mod.EventBusSubscriber
public interface Imbuement {
// This interface has no abstract methods, these handlers are just here for the sake of keeping things organised.
@SubscribeEvent
public static void onLivingDropsEvent(LivingDropsEvent event){
// Instantly disenchants an imbued weapon if it is dropped when the player dies.
for(EntityItem item : event.getDrops()){
// Apparently some mods don't behave and shove null items in the list, quite why I have no idea
if(item != null) removeImbuements(item.getItem());
}
}
@SubscribeEvent
public static void onItemTossEvent(ItemTossEvent event){
// Instantly disenchants an imbued weapon if it is thrown on the ground.
removeImbuements(event.getEntityItem().getItem());
}
/** Removes all imbuements from the given itemstack. */
static void removeImbuements(ItemStack stack){
if(stack.isItemEnchanted()){
// No need to check what enchantments the item has, since remove() does nothing if the element does not exist
NBTTagList enchantmentList = stack.getItem() == Items.ENCHANTED_BOOK ?
ItemEnchantedBook.getEnchantments(stack) : stack.getEnchantmentTagList();
// Check all enchantments of the item
Iterator<NBTBase> enchantmentIt = enchantmentList.iterator();
while(enchantmentIt.hasNext()){
NBTTagCompound enchantmentTag = (NBTTagCompound) enchantmentIt.next();
Enchantment enchantment = Enchantment.getEnchantmentByID(enchantmentTag.getShort("id"));
// If the item contains a magic weapon enchantment, remove it from the item
if(enchantment instanceof Imbuement){
((Imbuement) enchantment).onImbuementRemoval(stack);
enchantmentIt.remove();
}
}
}
}
/** Allows executing some custom logic before this imbuement is being removed from the stack. Called when the imbuement is about to be removed. */
default void onImbuementRemoval(ItemStack stack){}
@SubscribeEvent
public static void onPlayerOpenContainerEvent(PlayerContainerEvent event){
// Brute-force fix to stop enchanted books in dungeon chests from having imbuements on them.
if(event.getContainer() instanceof ContainerChest){
// Still not sure if it's better to set stacks in slots or modify the itemstack list directly, but I would
// imagine it's the former.
for(Slot slot : event.getContainer().inventorySlots){
ItemStack slotStack = slot.getStack();
if(slotStack.getItem() instanceof ItemEnchantedBook){
// We don't care about the level of the enchantments
NBTTagList enchantmentList = ItemEnchantedBook.getEnchantments(slotStack);
// Removes all imbuements
if(Iterables.removeIf(enchantmentList, tag -> {
NBTTagCompound enchantmentTag = (NBTTagCompound) tag;
return Enchantment.getEnchantmentByID(enchantmentTag.getShort("id"))
instanceof Imbuement;
})){
// If any imbuements were removed, inform about the removal of the enchantment(s), or
// delete the book entirely if there are none left.
if(enchantmentList.isEmpty()){
slot.putStack(ItemStack.EMPTY);
Wizardry.logger.info("Deleted enchanted book with illegal enchantments");
}else{
// Inform about enchantment removal
Wizardry.logger.info("Removed illegal enchantments from enchanted book");
}
}
}
}
}
}
@SubscribeEvent
public static void onEntityJoinWorld(EntityJoinWorldEvent event){
// Rather long-winded (but necessary) way of getting an arrow just after it has been fired, checking if the bow
// that fired it has the imbuement enchantment, and applying extra damage accordingly.
if(!event.getEntity().world.isRemote && event.getEntity() instanceof EntityArrow){
EntityArrow arrow = (EntityArrow)event.getEntity();
if(arrow.shootingEntity instanceof EntityLivingBase){
EntityLivingBase archer = (EntityLivingBase)arrow.shootingEntity;
ItemStack bow = archer.getHeldItemMainhand();
if(!ImbueWeapon.isBow(bow)){
bow = archer.getHeldItemOffhand();
if(!ImbueWeapon.isBow(bow)) return;
}
// Taken directly from ItemBow, so it works exactly the same as the power enchantment.
int level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.magic_bow, bow);
if(level > 0){
arrow.setDamage(arrow.getDamage() + (double)level * 0.5D + 0.5D);
}
if(EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.flaming_weapon, bow) > 0){
// Again, this is exactly what happens in ItemBow (flame is flame; level does nothing).
arrow.setFire(100);
}
level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.freezing_weapon, bow);
if(level > 0){
if(arrow.getEntityData() != null){
arrow.getEntityData().setInteger(FreezingWeapon.FREEZING_ARROW_NBT_KEY, level);
}
}
}
}
}
}