/** Copyright (C) <2017> <coolAlias> This file is part of coolAlias' Zelda Sword Skills Minecraft Mod; as such, you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package zeldaswordskills.item; import java.util.List; import com.google.common.collect.Multimap; import mods.battlegear2.api.weapons.IBattlegearWeapon; import net.minecraft.block.Block; import net.minecraft.block.BlockBreakable; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.item.ItemStack; import net.minecraft.util.BlockPos; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.MathHelper; import net.minecraft.util.StatCollector; import net.minecraft.world.World; import net.minecraftforge.fml.common.Optional; import net.minecraftforge.fml.common.Optional.Method; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import zeldaswordskills.api.block.BlockWeight; import zeldaswordskills.api.block.ISmashable; import zeldaswordskills.api.damage.DamageUtils.DamageSourceBaseDirect; import zeldaswordskills.api.entity.IParryModifier; import zeldaswordskills.api.item.IArmorBreak; import zeldaswordskills.api.item.ISmashBlock; import zeldaswordskills.api.item.ISwingSpeed; import zeldaswordskills.api.item.IUnenchantable; import zeldaswordskills.api.item.IWeapon; import zeldaswordskills.api.item.WeaponRegistry; import zeldaswordskills.creativetab.ZSSCreativeTabs; import zeldaswordskills.entity.player.ZSSPlayerInfo; import zeldaswordskills.handler.ZSSCombatEvents; import zeldaswordskills.network.PacketDispatcher; import zeldaswordskills.network.client.PacketISpawnParticles; import zeldaswordskills.ref.Sounds; import zeldaswordskills.util.WorldUtils; @Optional.Interface(iface="mods.battlegear2.api.weapons.IBattlegearWeapon", modid="battlegear2", striprefs=true) public class ItemHammer extends BaseModItem implements IArmorBreak, IParryModifier, ISmashBlock, ISpawnParticles, ISwingSpeed, IUnenchantable, IWeapon, IBattlegearWeapon { /** Max resistance that a block may have and still be smashed */ private final BlockWeight strength; /** Amount of damage this hammer inflicts */ private final float weaponDamage; /** Percentage of damage that ignores armor */ private final float ignoreArmorAmount; public ItemHammer(BlockWeight strength, float damage, float ignoreArmor) { super(); this.strength = strength; this.weaponDamage = damage; this.ignoreArmorAmount = ignoreArmor; setFull3D(); setMaxDamage(0); setMaxStackSize(1); setCreativeTab(ZSSCreativeTabs.tabCombat); } @Override public boolean canHarvestBlock(Block block) { return block instanceof ISmashable || block instanceof BlockBreakable; } @Override public float getOffensiveModifier(EntityLivingBase entity, ItemStack stack) { return 0.4F; } @Override public float getDefensiveModifier(EntityLivingBase entity, ItemStack stack) { return 0; } @Override public float getPercentArmorIgnored() { return ignoreArmorAmount; } @Override public BlockWeight getSmashStrength(EntityPlayer player, ItemStack stack, IBlockState state, EnumFacing side) { return (state.getBlock() instanceof BlockBreakable) ? strength.next() : strength; } @Override public void onBlockSmashed(EntityPlayer player, ItemStack stack, IBlockState state, EnumFacing side, boolean wasSmashed) { if (!wasSmashed) { WorldUtils.playSoundAtEntity(player, Sounds.HAMMER, 0.4F, 0.5F); } } @Override public float getExhaustion() { return (weaponDamage / 16.0F); } @Override public int getSwingSpeed() { return 30; } @Override public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase attacker) { WorldUtils.playSoundAtEntity(attacker, Sounds.HAMMER, 0.4F, 0.5F); double dx = 0.15D * (attacker.posX - target.posX); double dz = 0.15D * (attacker.posZ - target.posZ); float f = MathHelper.sqrt_double(dx * dx + dz * dz); if (f > 0.0F) { double resist = 1.0D - target.getEntityAttribute(SharedMonsterAttributes.knockbackResistance).getAttributeValue(); double f1 = resist * (weaponDamage / 8.0F) * 0.6000000238418579D; double k = f1 / f; target.addVelocity(-dx * k, 0.15D * f1, -dz * k); } return true; } @Override public int getItemEnchantability() { return 0; } @Override public EnumAction getItemUseAction(ItemStack stack) { return EnumAction.BLOCK; } @Override public int getMaxItemUseDuration(ItemStack stack) { return 72000; } @Override public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) { if (ZSSPlayerInfo.get(player).canAttack()) { player.setItemInUse(stack, this.getMaxItemUseDuration(stack)); } return stack; } @Override public void onPlayerStoppedUsing(ItemStack stack, World world, EntityPlayer player, int ticksRemaining) { if (this == ZSSItems.hammerSkull && ZSSPlayerInfo.get(player).canAttack()) { int ticksInUse = getMaxItemUseDuration(stack) - ticksRemaining; float charge = (float) ticksInUse / 40.0F; charge = Math.min((charge * charge + charge * 2.0F) / 3.0F, 1.0F); player.addExhaustion(charge * 2.0F); if (charge > 0.25F) { if (!player.worldObj.isRemote) { PacketDispatcher.sendToAllAround(new PacketISpawnParticles(player, 4.0F), player, 64.0D); } player.swingItem(); ZSSCombatEvents.setPlayerAttackTime(player); WorldUtils.playSoundAtEntity(player, Sounds.LEAPING_BLOW, 0.4F, 0.5F); DamageSource specialAttack = new DamageSourceBaseDirect("player", player).setStunDamage((int)(60 * charge), 5, true).setDamageBypassesArmor(); float damage = (weaponDamage * charge) / 2.0F; if (damage > 0.5F) { List<EntityLivingBase> entities = world.getEntitiesWithinAABB(EntityLivingBase.class, player.getEntityBoundingBox().expand(4.0D, 0.0D, 4.0D)); for (EntityLivingBase entity : entities) { if (entity != player && entity.onGround) { entity.attackEntityFrom(specialAttack, damage); } } } } } } @Override @SideOnly(Side.CLIENT) public void spawnParticles(World world, EntityPlayer player, ItemStack stack, double x, double y, double z, float radius) { int r = MathHelper.ceiling_float_int(radius); for (int i = 0; i < r; ++i) { for (int k = 0; k < r; ++k) { spawnParticlesAt(world, x + i, y, z + k); spawnParticlesAt(world, x + i, y, z - k); spawnParticlesAt(world, x - i, y, z + k); spawnParticlesAt(world, x - i, y, z - k); } } } @SideOnly(Side.CLIENT) private void spawnParticlesAt(World world, double x, double y, double z) { int posY = MathHelper.floor_double(y); IBlockState state = world.getBlockState(new BlockPos(MathHelper.floor_double(x), posY - 1, MathHelper.floor_double(z))); Block block = state.getBlock(); if (block.getRenderType() != -1) { int stateId = Block.getStateId(state); for (int i = 0; i < 4; ++i) { double dx = x + world.rand.nextFloat() - 0.5F; double dy = posY + world.rand.nextFloat() * 0.2F; double dz = z + world.rand.nextFloat() - 0.5F; world.spawnParticle(EnumParticleTypes.BLOCK_CRACK, dx, dy, dz, world.rand.nextGaussian(), 0, world.rand.nextGaussian(), stateId); } } } @Override public Multimap<String, AttributeModifier> getAttributeModifiers(ItemStack stack) { Multimap<String, AttributeModifier> multimap = super.getAttributeModifiers(stack); multimap.put(SharedMonsterAttributes.attackDamage.getAttributeUnlocalizedName(), new AttributeModifier(itemModifierUUID, "Weapon modifier", (double) weaponDamage, 0)); return multimap; } @Override @SideOnly(Side.CLIENT) public void addInformation(ItemStack stack, EntityPlayer player, List<String> list, boolean advanced) { list.add(EnumChatFormatting.ITALIC + StatCollector.translateToLocal("tooltip." + getUnlocalizedName().substring(5) + ".desc.0")); } @Override public boolean isSword(ItemStack stack) { return false; } @Override public boolean isWeapon(ItemStack stack) { return !WeaponRegistry.INSTANCE.isWeaponForbidden(this); } @Method(modid="battlegear2") @Override public boolean allowOffhand(ItemStack main, ItemStack offhand, EntityPlayer player) { return offhand == null; } @Method(modid="battlegear2") @Override public boolean isOffhandWieldable(ItemStack stack, EntityPlayer player) { return false; } @Method(modid="battlegear2") @Override public boolean sheatheOnBack(ItemStack stack) { return true; } }