/**
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.HashMultimap;
import com.google.common.collect.Multimap;
import mods.battlegear2.api.weapons.IBattlegearWeapon;
import net.minecraft.block.Block;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.monster.IMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.StatCollector;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants;
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.ZSSAchievements;
import zeldaswordskills.api.entity.IParryModifier;
import zeldaswordskills.api.item.IFairyUpgrade;
import zeldaswordskills.api.item.ISacredFlame;
import zeldaswordskills.api.item.ISwingSpeed;
import zeldaswordskills.api.item.IUnenchantable;
import zeldaswordskills.api.item.IWeapon;
import zeldaswordskills.block.BlockSacredFlame;
import zeldaswordskills.block.tileentity.TileEntityDungeonCore;
import zeldaswordskills.creativetab.ZSSCreativeTabs;
import zeldaswordskills.ref.Config;
import zeldaswordskills.ref.Sounds;
import zeldaswordskills.util.PlayerUtils;
import zeldaswordskills.util.WorldUtils;
/**
*
* Base class for all ZSS Swords.
*
* These require an anvil to be repaired, and if broken only a skilled blacksmith
* is able to fix it.
*
*/
@Optional.Interface(iface="mods.battlegear2.api.weapons.IBattlegearWeapon", modid="battlegear2", striprefs=true)
public class ItemZeldaSword extends BaseModItemSword implements IBattlegearWeapon, IFairyUpgrade, IParryModifier, ISacredFlame, ISwingSpeed, IUnenchantable, IWeapon
{
/** Original ItemSword's field is private, but this has the same functionality */
protected final float weaponDamage;
/** Original ItemSword's field is private, so store tool material in case it's needed */
protected final ToolMaterial toolMaterial;
/** Whether this sword is considered a 'master' sword for purposes of skills and such*/
protected boolean isMaster = false;
/** Whether this sword requires two hands */
protected final boolean twoHanded;
/** Additional swing time */
protected final int swingSpeed;
/** Additional exhaustion added each swing */
protected final float exhaustion;
/** Whether this sword will give the 'broken' version when it breaks */
protected boolean givesBrokenItem = true;
/**
* Default constructor for single-handed weapons with no swing speed or exhaustion penalties
*/
public ItemZeldaSword(ToolMaterial material, float bonusDamage) {
this(material, bonusDamage, false, 0, 0.0F);
}
/**
* Default constructor for two-handed weapons; if two-handed, default values of
* 15 and 0.3F are used for swing speed and exhaustion, respectively.
*/
public ItemZeldaSword(ToolMaterial material, float bonusDamage, boolean twoHanded) {
this(material, bonusDamage, twoHanded, (twoHanded ? 15 : 0), (twoHanded ? 0.3F : 0.0F));
}
public ItemZeldaSword(ToolMaterial material, float bonusDamage, boolean twoHanded, int swingSpeed, float exhaustion) {
super(material);
this.setNoRepair();
this.toolMaterial = material;
this.weaponDamage = 4.0F + bonusDamage + material.getDamageVsEntity();
this.twoHanded = twoHanded;
this.swingSpeed = Math.max(0, swingSpeed);
this.exhaustion = Math.max(0.0F, exhaustion);
setCreativeTab(ZSSCreativeTabs.tabCombat);
}
/**
* Flags this sword as a 'master' sword, which also sets no item on break to true
*/
public ItemZeldaSword setMasterSword() {
setNoItemOnBreak();
isMaster = true;
return this;
}
/** Whether this sword is considered a 'master' sword for purposes of skills and such*/
public boolean isMasterSword() {
return isMaster;
}
/**
* Sets this sword to not give the broken item version when the sword breaks
*/
public ItemZeldaSword setNoItemOnBreak() {
givesBrokenItem = false;
return this;
}
@Override
public float getOffensiveModifier(EntityLivingBase entity, ItemStack stack) {
return (twoHanded ? 0.25F : 0.0F);
}
@Override
public float getDefensiveModifier(EntityLivingBase entity, ItemStack stack) {
return 0;
}
@Override
public float getExhaustion() {
return exhaustion;
}
@Override
public int getSwingSpeed() {
return swingSpeed;
}
@Override
public int getItemEnchantability() {
return (isMaster ? 0 : super.getItemEnchantability());
}
@Override
public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase attacker) {
stack.damageItem(1, attacker);
onStackDamaged(stack, attacker);
return true;
}
@Override
public boolean onBlockDestroyed(ItemStack stack, World world, Block block, BlockPos pos, EntityLivingBase entity) {
if ((double) block.getBlockHardness(world, pos) != 0.0D) {
stack.damageItem((stack.getItem() == ZSSItems.swordGiant ? stack.getMaxDamage() + 1 : 2), entity);
onStackDamaged(stack, entity);
}
return true;
}
/**
* Called when the stack is damaged; if stack size is 0, gives appropriate broken sword item
*/
protected void onStackDamaged(ItemStack stack, EntityLivingBase entity) {
if (stack.stackSize == 0 && givesBrokenItem && entity instanceof EntityPlayer) {
ItemStack broken = ItemBrokenSword.getBrokenSwordFor(this);
if (broken != null) {
PlayerUtils.addItemToInventory((EntityPlayer) entity, broken);
}
}
}
/**
* Override to add custom weapon damage field rather than vanilla ItemSword's field
*/
@Override
public Multimap<String, AttributeModifier> getItemAttributeModifiers() {
Multimap<String, AttributeModifier> multimap = HashMultimap.create();
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"));
if (stack.getItem() == ZSSItems.swordTempered) {
if (stack.hasTagCompound() && stack.getTagCompound().hasKey("zssHitCount")) {
list.add(EnumChatFormatting.ITALIC + StatCollector.translateToLocalFormatted("tooltip.zss.sword_tempered.desc.1",stack.getTagCompound().getInteger("zssHitCount")));
}
} else if (stack.getItem() == ZSSItems.swordGolden) {
if (stack.hasTagCompound() && stack.getTagCompound().hasKey("SacredFlames")) {
int level = stack.getTagCompound().getInteger("SacredFlames");
for (int i = 1; i < 5; ++i) { // bits 1, 2, and 4
if (i != 3 && (level & i) != 0) {
BlockSacredFlame.EnumType flame = BlockSacredFlame.EnumType.byMetadata((level & i));
list.add(EnumChatFormatting.ITALIC + StatCollector.translateToLocalFormatted("tooltip.zss.sword_golden.desc.1", StatCollector.translateToLocal("tile.zss.sacred_flame." + flame.getName() + ".name")));
}
}
}
}
}
@Override
public void handleFairyUpgrade(EntityItem item, EntityPlayer player, TileEntityDungeonCore core) {
BlockPos pos = core.getPos();
ItemStack stack = item.getEntityItem();
if (stack.hasTagCompound() && stack.getTagCompound().hasKey("zssHitCount") && stack.getTagCompound().getInteger("zssHitCount") > Config.getRequiredKills()) {
item.setDead();
WorldUtils.spawnItemWithRandom(core.getWorld(), new ItemStack(ZSSItems.swordGolden), pos.getX(), pos.getY() + 2, pos.getZ());
core.getWorld().playSoundEffect(pos.getX() + 0.5D, pos.getY() + 1, pos.getZ() + 0.5D, Sounds.FAIRY_BLESSING, 1.0F, 1.0F);
PlayerUtils.sendTranslatedChat(player, "chat.zss.sword.blessing");
player.triggerAchievement(ZSSAchievements.swordGolden);
} else {
core.getWorld().playSoundEffect(pos.getX() + 0.5D, pos.getY() + 1, pos.getZ() + 0.5D, Sounds.FAIRY_LAUGH, 1.0F, 1.0F);
PlayerUtils.sendTranslatedChat(player, "chat.zss.fairy.laugh.unworthy");
}
}
@Override
public boolean hasFairyUpgrade(ItemStack stack) {
return this == ZSSItems.swordTempered;
}
/**
* Call when a player kills a mob with the Tempered Sword to increment the foes slain count
* There is no need to check if the held item is correct, as that is done here
*/
public static void onKilledMob(EntityPlayer player, IMob mob) {
if (!player.worldObj.isRemote && player.getHeldItem() != null && player.getHeldItem().getItem() == ZSSItems.swordTempered) {
ItemStack stack = player.getHeldItem();
NBTTagCompound tag = stack.getTagCompound();
if (tag == null) { tag = new NBTTagCompound(); }
tag.setInteger("zssHitCount", tag.getInteger("zssHitCount") + 1);
stack.setTagCompound(tag);
if (tag.getInteger("zssHitCount") > Config.getRequiredKills()) {
player.triggerAchievement(ZSSAchievements.swordEvil);
}
}
}
@Override
public boolean onActivatedSacredFlame(ItemStack stack, World world, EntityPlayer player, BlockSacredFlame.EnumType flame, boolean isActive) {
return false;
}
@Override
public boolean onClickedSacredFlame(ItemStack stack, World world, EntityPlayer player, BlockSacredFlame.EnumType flame, boolean isActive) {
if (world.isRemote) {
return false;
} else if (this == ZSSItems.swordGolden && isActive) {
NBTTagCompound tag = stack.getTagCompound();
if (tag == null) { tag = new NBTTagCompound(); }
if ((tag.getInteger("SacredFlames") & flame.getBit()) == 0) {
tag.setInteger("SacredFlames", tag.getInteger("SacredFlames") | flame.getBit());
stack.setTagCompound(tag);
world.playSoundAtEntity(player, Sounds.FLAME_ABSORB, 1.0F, 1.0F);
PlayerUtils.sendTranslatedChat(player, "chat.zss.sacred_flame.new",
new ChatComponentTranslation(stack.getUnlocalizedName() + ".name"),
new ChatComponentTranslation("tile.zss.sacred_flame." + flame.getName() + ".name"));
player.triggerAchievement(ZSSAchievements.swordFlame);
addSacredFlameEnchantments(stack, flame);
return true;
} else {
PlayerUtils.sendTranslatedChat(player, "chat.zss.sacred_flame.old.same", new ChatComponentTranslation(stack.getUnlocalizedName() + ".name"));
}
} else {
if (isActive) {
PlayerUtils.sendTranslatedChat(player, "chat.zss.sacred_flame.incorrect.sword");
} else {
PlayerUtils.sendTranslatedChat(player, "chat.zss.sacred_flame.inactive");
}
}
WorldUtils.playSoundAtEntity(player, Sounds.SWORD_MISS, 0.4F, 0.5F);
return false;
}
/**
* Adds appropriate enchantments to Golden Sword when bathing in one of the Sacred Flames
* @param type metadata value of the Sacred Flame
*/
private void addSacredFlameEnchantments(ItemStack stack, BlockSacredFlame.EnumType flame) {
switch(flame) {
case DIN: stack.addEnchantment(Enchantment.fireAspect, 2); break;
case FARORE: stack.addEnchantment(Enchantment.knockback, 2); break;
case NAYRU: stack.addEnchantment(Enchantment.looting, 3); break;
}
boolean flag = false;
NBTTagList enchList = stack.getTagCompound().getTagList("ench", Constants.NBT.TAG_COMPOUND);
for (int i = 0; i < enchList.tagCount(); ++i) {
NBTTagCompound compound = enchList.getCompoundTagAt(i);
if (compound.getShort("id") == Enchantment.sharpness.effectId) {
short lvl = compound.getShort("lvl");
if (lvl < Enchantment.sharpness.getMaxLevel()) {
enchList.removeTag(i);
stack.addEnchantment(Enchantment.sharpness, lvl + 1);
}
flag = true;
break;
}
}
if (!flag) {
stack.addEnchantment(Enchantment.sharpness, 1);
}
}
@Override
public boolean isSword(ItemStack stack) {
return true;
}
@Override
public boolean isWeapon(ItemStack stack) {
return true;
}
@Method(modid="battlegear2")
@Override
public boolean sheatheOnBack(ItemStack stack) {
return true;
}
@Method(modid="battlegear2")
@Override
public boolean isOffhandWieldable(ItemStack stack, EntityPlayer player) {
return !twoHanded && (!isMaster || Config.allowOffhandMaster());
}
@Method(modid="battlegear2")
@Override
public boolean allowOffhand(ItemStack main, ItemStack offhand, EntityPlayer player) {
return !twoHanded;
}
}