/** Copyright (C) <2015> <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.skills.sword; import java.util.List; import net.minecraft.client.Minecraft; import net.minecraft.client.settings.KeyBinding; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.DamageSource; import net.minecraft.util.StatCollector; import net.minecraft.world.World; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import zeldaswordskills.client.ZSSKeyHandler; import zeldaswordskills.network.PacketDispatcher; import zeldaswordskills.network.bidirectional.ActivateSkillPacket; import zeldaswordskills.ref.Config; import zeldaswordskills.ref.Sounds; import zeldaswordskills.skills.SkillActive; import zeldaswordskills.util.PlayerUtils; import zeldaswordskills.util.TargetUtils; import zeldaswordskills.util.WorldUtils; /** * * SWORD BREAK * Activation: Double-tap back while blocking * Effect: A fierce block that is capable of destroying the opponent's blade * Exhaustion: 2.0F - (0.1 * level) * Damage: Up to 90 durability damage to the opponent's held item (15 * (level + 1)) * Duration: Time allowed before skill fails is 2 ticks at level 1, up to 8 ticks at max level * Notes: * - Only works when being attacked by an enemy holding an item * - Has no effect other than blocking the attack if the attacker's held item can not be damaged * - Must release the block key in between uses * */ public class SwordBreak extends SkillActive { /** Timer during which player is considered actively parrying */ private int breakTimer; /** Only for double-tap activation: Current number of ticks remaining before skill will not activate */ @SideOnly(Side.CLIENT) private int ticksTilFail; /** Notification to play miss sound; set to true when activated and false when attack parried */ private boolean playMissSound; public SwordBreak(String name) { super(name); } private SwordBreak(SwordBreak skill) { super(skill); } @Override public SwordBreak newInstance() { return new SwordBreak(this); } @Override @SideOnly(Side.CLIENT) public void addInformation(List<String> desc, EntityPlayer player) { desc.add(StatCollector.translateToLocalFormatted(getInfoString("info", 1), getMaxDamage())); desc.add(getTimeLimitDisplay(getActiveTime() - getUseDelay())); desc.add(getExhaustionDisplay(getExhaustion())); } @Override public boolean isActive() { return (breakTimer > 0); } @Override protected float getExhaustion() { return 2.0F - (0.1F * level); } /** Number of ticks that skill will be considered active */ private int getActiveTime() { return 6 + level; } /** Number of ticks before player may attempt to use this skill again */ private int getUseDelay() { return (5 - (level / 2)); // 2 tick usage window at level 1 } /** Maximum amount of damage that may be caused to the opponent's weapon */ private int getMaxDamage() { return (level + 1) * 15; } @Override public boolean canUse(EntityPlayer player) { return super.canUse(player) && !isActive() && PlayerUtils.isWeapon(player.getHeldItem()); } /** * Only allow activation if player is using item, to prevent clashing with Parry */ @Override @SideOnly(Side.CLIENT) public boolean canExecute(EntityPlayer player) { return canUse(player) && PlayerUtils.isBlocking(player); } @Override @SideOnly(Side.CLIENT) public boolean isKeyListener(Minecraft mc, KeyBinding key) { return (key == ZSSKeyHandler.keys[ZSSKeyHandler.KEY_DOWN] || (Config.allowVanillaControls && key == mc.gameSettings.keyBindBack)); } @Override @SideOnly(Side.CLIENT) public boolean keyPressed(Minecraft mc, KeyBinding key, EntityPlayer player) { if (canExecute(player)) { if (Config.requireDoubleTap) { if (ticksTilFail > 0) { PacketDispatcher.sendToServer(new ActivateSkillPacket(this)); ticksTilFail = 0; return true; } else { ticksTilFail = 6; } } else if (key != mc.gameSettings.keyBindBack) { // activate on first press, but not for vanilla key! PacketDispatcher.sendToServer(new ActivateSkillPacket(this)); return true; } } return false; } @Override protected boolean onActivated(World world, EntityPlayer player) { breakTimer = getActiveTime(); playMissSound = true; if (world.isRemote) { KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindUseItem.getKeyCode(), false); KeyBinding.setKeyBindState(ZSSKeyHandler.keys[ZSSKeyHandler.KEY_BLOCK].getKeyCode(), false); player.swingItem(); } return isActive(); } @Override protected void onDeactivated(World world, EntityPlayer player) { breakTimer = 0; } @Override public void onUpdate(EntityPlayer player) { if (isActive()) { if (--breakTimer <= getUseDelay() && playMissSound) { playMissSound = false; WorldUtils.playSoundAtEntity(player, Sounds.SWORD_MISS, 0.4F, 0.5F); } } else if (player.worldObj.isRemote && ticksTilFail > 0) { --ticksTilFail; } } @Override public boolean onBeingAttacked(EntityPlayer player, DamageSource source) { if (source.getSourceOfDamage() instanceof EntityLivingBase) { EntityLivingBase attacker = (EntityLivingBase) source.getSourceOfDamage(); ItemStack stackToDamage = attacker.getHeldItem(); if (breakTimer > getUseDelay() && stackToDamage != null && PlayerUtils.isWeapon(player.getHeldItem())) { breakTimer = getUseDelay(); // only block one attack WorldUtils.playSoundAtEntity(player, Sounds.SWORD_STRIKE, 0.4F, 0.5F); playMissSound = false; if (!player.worldObj.isRemote) { int dmg = Math.max(getMaxDamage() / 3, player.worldObj.rand.nextInt(getMaxDamage())); stackToDamage.damageItem(dmg, attacker); if (stackToDamage.stackSize <= 0) { player.worldObj.playSoundAtEntity(attacker, Sounds.ITEM_BREAK, 0.8F, 0.8F + player.worldObj.rand.nextFloat() * 0.4F); attacker.setCurrentItemOrArmor(0, null); } } TargetUtils.knockTargetBack(attacker, player); return true; } // don't deactivate early, as there is a delay between uses } return false; } }