/**
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.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import zeldaswordskills.client.ZSSClientEvents;
import zeldaswordskills.client.ZSSKeyHandler;
import zeldaswordskills.entity.player.ZSSPlayerInfo;
import zeldaswordskills.entity.player.ZSSPlayerSkills;
import zeldaswordskills.network.PacketDispatcher;
import zeldaswordskills.network.bidirectional.ActivateSkillPacket;
import zeldaswordskills.ref.Config;
import zeldaswordskills.skills.SkillActive;
import zeldaswordskills.util.PlayerUtils;
/**
*
* RISING CUT
* Description: Rising slash flings enemy upward
* Activation: Jump while sneaking and attack
* Effect: Attacks target for normal sword damage and knocks the target into the air
* Range: 2 + level blocks
* Exhaustion: 3.0F - (level * 0.2F)
* Special: May only be used while locked on to a target
*
* Requires onRenderTick to be called each render tick while active.
*
*/
public class RisingCut extends SkillActive
{
/** Flag for activation; set when player jumps while sneaking */
@SideOnly(Side.CLIENT)
private int ticksTilFail;
/** True while animation is in progress */
private int activeTimer;
/** Stores the entity struck to add velocity on the next update */
private Entity entityHit;
public RisingCut(String name) {
super(name);
}
private RisingCut(RisingCut skill) {
super(skill);
}
@Override
public RisingCut newInstance() {
return new RisingCut(this);
}
@Override
@SideOnly(Side.CLIENT)
public void addInformation(List<String> desc, EntityPlayer player) {
desc.add(getRangeDisplay(2 + level));
desc.add(getExhaustionDisplay(getExhaustion()));
}
@Override
public boolean isActive() {
return activeTimer > 0;
}
@Override
protected float getExhaustion() {
return 3.0F - (level * 0.2F);
}
@Override
public boolean canUse(EntityPlayer player) {
return super.canUse(player) && !isActive() && !player.isUsingItem() && PlayerUtils.isSword(player.getHeldItem());
}
@Override
@SideOnly(Side.CLIENT)
public boolean canExecute(EntityPlayer player) {
return ticksTilFail > 0 && player.motionY > 0.0D && canUse(player);
}
@Override
@SideOnly(Side.CLIENT)
public boolean isKeyListener(Minecraft mc, KeyBinding key) {
return (key == mc.gameSettings.keyBindJump || key == ZSSKeyHandler.keys[ZSSKeyHandler.KEY_ATTACK]
|| (Config.allowVanillaControls && key == mc.gameSettings.keyBindAttack));
}
/**
* Flags the skill as ready to be activated when the player next attacks,
* provided {@link #canExecute} still returns true at that time
*/
@Override
@SideOnly(Side.CLIENT)
public boolean keyPressed(Minecraft mc, KeyBinding key, EntityPlayer player) {
if (key == mc.gameSettings.keyBindJump) {
if (!isActive() && !player.isUsingItem() && player.isSneaking()) {
ticksTilFail = 3; // this allows canExecute to return true for 3 ticks
return true;
}
} else if (canExecute(player)) {
PacketDispatcher.sendToServer(new ActivateSkillPacket(this));
ZSSClientEvents.performComboAttack(mc, ZSSPlayerSkills.get(player).getTargetingSkill());
return true;
}
return false;
}
@Override
protected boolean onActivated(World world, EntityPlayer player) {
activeTimer = 5 + level;
entityHit = null;
player.motionY += 0.3D + (0.115D * level);
ZSSPlayerInfo.get(player).reduceFallAmount += level;
return isActive();
}
@Override
protected void onDeactivated(World world, EntityPlayer player) {
activeTimer = 0;
}
@Override
public void onUpdate(EntityPlayer player) {
if (player.worldObj.isRemote && ticksTilFail > 0) {
--ticksTilFail;
}
if (isActive()) {
--activeTimer;
if (entityHit != null) {
if (!entityHit.isDead) {
double addY = 0.3D + (0.125D * level);
double resist = 1.0D;
if (entityHit instanceof EntityLivingBase) {
resist = 1.0D - ((EntityLivingBase) entityHit).getEntityAttribute(SharedMonsterAttributes.knockbackResistance).getAttributeValue();
}
entityHit.addVelocity(0.0D, addY * resist, 0.0D);
}
entityHit = null;
}
}
}
@Override
@SideOnly(Side.CLIENT)
public boolean onRenderTick(EntityPlayer player, float partialTickTime) {
player.swingProgress = 0.5F; // keep sword extended
return false; // return false so targeting camera remains locked on target
}
/**
* Call when an entity is damaged to flag the entity for velocity update next tick.
* This is necessary because adding velocity right before the entity is damaged fails.
*/
@Override
public float postImpact(EntityPlayer player, EntityLivingBase entity, float amount) {
boolean flag = !(entity instanceof EntityPlayer) || !PlayerUtils.isBlocking((EntityPlayer) entity);
this.entityHit = (flag ? entity : null);
return amount;
}
}