package slimeknights.tconstruct.library.traits; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.world.BlockEvent; import slimeknights.tconstruct.library.Util; import slimeknights.tconstruct.library.modifiers.Modifier; import slimeknights.tconstruct.library.modifiers.ModifierAspect; import slimeknights.tconstruct.library.modifiers.ModifierNBT; import slimeknights.tconstruct.library.utils.TagUtil; import slimeknights.tconstruct.library.utils.TinkerUtil; // Trait and modifier in one! Useful because modifiers are saved as traits public abstract class AbstractTrait extends Modifier implements ITrait { public static final String LOC_Name = Modifier.LOC_Name; public static final String LOC_Desc = Modifier.LOC_Desc; //private final String identifier; protected final int color; public AbstractTrait(String identifier, TextFormatting color) { this(identifier, Util.enumChatFormattingToColor(color)); } public AbstractTrait(String identifier, int color) { super(Util.sanitizeLocalizationString(identifier)); //this.identifier = Util.sanitizeLocalizationString(identifier); this.color = color; // we assume traits can only be applied once. // If you want stacking traits you'll have to do that stuff yourself :P this.addAspects(new ModifierAspect.SingleAspect(this)); } @Override public String getIdentifier() { return identifier; } @Override public String getLocalizedName() { return Util.translate(LOC_Name, getIdentifier()); } @Override public String getLocalizedDesc() { return Util.translate(LOC_Desc, getIdentifier()); } @Override public boolean isHidden() { return false; } /* Updating */ @Override public void onUpdate(ItemStack tool, World world, Entity entity, int itemSlot, boolean isSelected) { } @Override public void onArmorTick(ItemStack tool, World world, EntityPlayer player) { } /* Mining & Harvesting */ @Override public void miningSpeed(ItemStack tool, PlayerEvent.BreakSpeed event) { } @Override public void beforeBlockBreak(ItemStack tool, BlockEvent.BreakEvent event) { } @Override public void afterBlockBreak(ItemStack tool, World world, IBlockState state, BlockPos pos, EntityLivingBase player, boolean wasEffective) { } @Override public void blockHarvestDrops(ItemStack tool, BlockEvent.HarvestDropsEvent event) { } /* Attacking */ @Override public boolean isCriticalHit(ItemStack tool, EntityLivingBase player, EntityLivingBase target) { return false; } @Override public float damage(ItemStack tool, EntityLivingBase player, EntityLivingBase target, float damage, float newDamage, boolean isCritical) { return newDamage; } @Override public void onHit(ItemStack tool, EntityLivingBase player, EntityLivingBase target, float damage, boolean isCritical) { } @Override public void afterHit(ItemStack tool, EntityLivingBase player, EntityLivingBase target, float damageDealt, boolean wasCritical, boolean wasHit) { } @Override public float knockBack(ItemStack tool, EntityLivingBase player, EntityLivingBase target, float damage, float knockback, float newKnockback, boolean isCritical) { return newKnockback; } @Override public void onBlock(ItemStack tool, EntityPlayer player, LivingHurtEvent event) { } /* Durability and repairing */ @Override public int onToolDamage(ItemStack tool, int damage, int newDamage, EntityLivingBase entity) { return newDamage; } @Override public int onToolHeal(ItemStack tool, int amount, int newAmount, EntityLivingBase entity) { return newAmount; } @Override public void onRepair(ItemStack tool, int amount) { } /* Modifier things */ // The name the modifier tag is saved under public String getModifierIdentifier() { return identifier; } @Override public boolean canApplyCustom(ItemStack stack) { // can only apply if the trait isn't present already NBTTagList tagList = TagUtil.getTraitsTagList(stack); int index = TinkerUtil.getIndexInList(tagList, this.getIdentifier()); // not present yet return index < 0; } @Override public void updateNBT(NBTTagCompound modifierTag) { updateNBTforTrait(modifierTag, color); } public void updateNBTforTrait(NBTTagCompound modifierTag, int newColor) { ModifierNBT data = ModifierNBT.readTag(modifierTag); data.identifier = getModifierIdentifier(); data.color = newColor; // we ensure at least lvl1 for compatibility with the level-aspect if(data.level == 0) { data.level = 1; } data.write(modifierTag); } @Override public void applyEffect(NBTTagCompound rootCompound, NBTTagCompound modifierTag) { // add the trait to the traitlist so it gets processed NBTTagList traits = TagUtil.getTraitsTagList(rootCompound); // if it's not already present for(int i = 0; i < traits.tagCount(); i++) { if(identifier.equals(traits.getStringTagAt(i))) { return; } } traits.appendTag(new NBTTagString(identifier)); TagUtil.setTraitsTagList(rootCompound, traits); } }