/**
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.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.EnumAction;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.StatCollector;
import net.minecraft.village.MerchantRecipe;
import net.minecraft.village.MerchantRecipeList;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import zeldaswordskills.ZSSAchievements;
import zeldaswordskills.api.item.IFairyUpgrade;
import zeldaswordskills.api.item.IUnenchantable;
import zeldaswordskills.api.item.IZoom;
import zeldaswordskills.block.tileentity.TileEntityDungeonCore;
import zeldaswordskills.creativetab.ZSSCreativeTabs;
import zeldaswordskills.entity.player.ZSSPlayerInfo;
import zeldaswordskills.entity.player.ZSSPlayerSkills;
import zeldaswordskills.entity.projectile.EntitySeedShot;
import zeldaswordskills.entity.projectile.EntitySeedShot.SeedType;
import zeldaswordskills.ref.Config;
import zeldaswordskills.ref.Sounds;
import zeldaswordskills.skills.SkillBase;
import zeldaswordskills.util.MerchantRecipeHelper;
import zeldaswordskills.util.PlayerUtils;
import zeldaswordskills.util.WorldUtils;
/**
*
* The slingshot can shoot any type of seed to inflict a small amount of damage.
*
* Each type of seed will have a different effect, and some, such as the Deku Nut,
* require a special type of slingshot (upgraded) to shoot properly.
*
*/
public class ItemSlingshot extends BaseModItem implements ICyclableItem, IFairyUpgrade, IUnenchantable, IZoom
{
public static enum Mode {
/** Default Slingshot behavior searches for the first usable seed of any kind */
DEFAULT(null),
DEKU(SeedType.DEKU),
BOMB(SeedType.BOMB),
COCOA(SeedType.COCOA),
GRASS(SeedType.GRASS),
MELON(SeedType.MELON),
PUMPKIN(SeedType.PUMPKIN),
NETHERWART(SeedType.NETHERWART);
private ItemStack seedStack;
private final SeedType type;
private Mode(SeedType type) {
this.type = type;
}
/**
* Returns the seed itemstack required for this mode
*/
public ItemStack getSeedStack() {
if (type != null) {
if (ItemSlingshot.seedToType.isEmpty()) {
ItemSlingshot.initializeSeeds();
}
Item item = ItemSlingshot.typeToSeed.get(type);
if (item != null) {
seedStack = new ItemStack(item, 1, item == Items.dye ? 3 : 0);
}
}
return seedStack;
}
/**
* Returns the next Mode by ordinal position
*/
public Mode next() {
return Mode.values()[(ordinal() + 1) % Mode.values().length];
}
/**
* Returns the previous Mode by ordinal position
*/
public Mode prev() {
return Mode.values()[((ordinal() == 0 ? Mode.values().length : ordinal()) - 1) % Mode.values().length];
}
}
/** The number of seeds this slingshot will fire per shot */
protected final int seedsFired;
/** The angle between each seed fragment */
protected final float spread;
/** Maps seed Items to seed Type (dye item must also check damage value) */
private static final Map<Item, SeedType> seedToType = new HashMap<Item, SeedType>();
/** Maps the seed types to seed Items for consuming seed shot */
private static final Map<SeedType, Item> typeToSeed = new EnumMap<SeedType, Item>(SeedType.class);
private static void initializeSeeds(){
addSeedMapping(SeedType.BOMB, ZSSItems.bombFlowerSeed);
addSeedMapping(SeedType.COCOA, Items.dye);
addSeedMapping(SeedType.DEKU, ZSSItems.dekuNut);
addSeedMapping(SeedType.GRASS, Items.wheat_seeds);
addSeedMapping(SeedType.MELON, Items.melon_seeds);
addSeedMapping(SeedType.NETHERWART, Items.nether_wart);
addSeedMapping(SeedType.PUMPKIN, Items.pumpkin_seeds);
}
private static void addSeedMapping(SeedType type, Item item) {
seedToType.put(item, type);
typeToSeed.put(type, item);
}
public ItemSlingshot() {
this(1, 0);
}
public ItemSlingshot(int seedsFired, float spread) {
super();
this.seedsFired = seedsFired;
this.spread = spread;
setFull3D();
setMaxDamage(0);
setMaxStackSize(1);
setCreativeTab(ZSSCreativeTabs.tabCombat);
}
public Mode getMode(EntityPlayer player) {
return Mode.values()[ZSSPlayerInfo.get(player).slingshotMode % Mode.values().length];
}
private void setMode(EntityPlayer player, Mode mode) {
ZSSPlayerInfo.get(player).slingshotMode = mode.ordinal();
}
@Override
public void nextItemMode(ItemStack stack, EntityPlayer player) {
if (!player.isUsingItem()) {
setMode(player, getMode(player).next());
}
}
@Override
public void prevItemMode(ItemStack stack, EntityPlayer player) {
if (!player.isUsingItem()) {
setMode(player, getMode(player).prev());
}
}
@Override
public int getCurrentMode(ItemStack stack, EntityPlayer player) {
return getMode(player).ordinal();
}
@Override
public void setCurrentMode(ItemStack stack, EntityPlayer player, int mode) {
setMode(player, Mode.values()[mode % Mode.values().length]);
}
@Override
public ItemStack getRenderStackForMode(ItemStack stack, EntityPlayer player) {
ItemStack ret = getMode(player).getSeedStack();
if (ret != null) {
ret.stackSize = 0;
for (ItemStack inv : player.inventory.mainInventory) {
if (inv != null && inv.getItem() == ret.getItem() && inv.getItemDamage() == ret.getItemDamage()) {
ret.stackSize += inv.stackSize;
if (ret.stackSize > 98) {
ret.stackSize = 99;
break;
}
}
}
}
return ret;
}
@Override
@SideOnly(Side.CLIENT)
public float getMaxZoomTime() {
return 20.0F;
}
@Override
@SideOnly(Side.CLIENT)
public float getZoomFactor() {
return 0.15F;
}
@Override
public int getItemEnchantability() {
return 0;
}
@Override
public int getMaxItemUseDuration(ItemStack stack) {
return 72000;
}
@Override
public EnumAction getItemUseAction(ItemStack stack) {
return EnumAction.BOW;
}
@Override
public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) {
if (hasSeeds(player)) {
player.setItemInUse(stack, getMaxItemUseDuration(stack));
}
return stack;
}
@Override
public void onPlayerStoppedUsing(ItemStack stack, World world, EntityPlayer player, int ticksUsed) {
int charge = getMaxItemUseDuration(stack) - ticksUsed;
float f = (float) charge / 20.0F;
f = (f * f + f * 2.0F) / 3.0F;
SeedType type = getSeedType(player);
if (f < 0.3F || type == SeedType.NONE) {
return;
} else if (f > 1.0F) {
f = 1.0F;
}
for (int i = 0; i < seedsFired; ++i) {
EntitySeedShot seedShot = new EntitySeedShot(world, player, f, i + 1, spread).setType(type);
if (f == 1.0F) {
seedShot.setIsCritical(true);
}
float factor = (seedsFired == 1 ? 2.2F : seedsFired < 4 ? 1.4F : 1.0F);
float damage = type.getDamage();
int k = EnchantmentHelper.getEnchantmentLevel(Enchantment.power.effectId, stack);
if (k > 0) {
damage += ((float)(k * 0.25F) + 0.25F);
}
seedShot.setDamage(damage * factor);
int l = EnchantmentHelper.getEnchantmentLevel(Enchantment.punch.effectId, stack);
seedShot.setKnockback(l > 0 ? l : (type == SeedType.MELON ? 1 : 0));
if (type == SeedType.NETHERWART || EnchantmentHelper.getEnchantmentLevel(Enchantment.flame.effectId, stack) > 0) {
seedShot.setFire(100);
}
if (!world.isRemote) {
world.spawnEntityInWorld(seedShot);
}
}
world.playSoundAtEntity(player, Sounds.BOW_RELEASE, 1.0F, 1.0F / (itemRand.nextFloat() * 0.4F + 1.2F) + f * 0.5F);
if (!player.capabilities.isCreativeMode) {
Item seed = typeToSeed.get(type);
PlayerUtils.consumeInventoryItem(player, seed, seed == Items.dye ? 3 : 0, 1);
}
}
@Override
public boolean onLeftClickEntity(ItemStack stack, EntityPlayer player, Entity entity) {
if (!player.worldObj.isRemote && entity instanceof EntityVillager) {
EntityVillager villager = (EntityVillager) entity;
MerchantRecipeList trades = villager.getRecipes(player);
if (trades != null) {
MerchantRecipe trade = new MerchantRecipe(stack.copy(), new ItemStack(Items.emerald, 6 + (2 * seedsFired)));
if (player.worldObj.rand.nextFloat() < 0.2F && MerchantRecipeHelper.addToListWithCheck(trades, trade)) {
PlayerUtils.sendTranslatedChat(player, "chat.zss.trade.generic.sell.0");
} else {
PlayerUtils.sendTranslatedChat(player, "chat.zss.trade.generic.sorry.1");
}
} else {
PlayerUtils.sendTranslatedChat(player, "chat.zss.trade.generic.sorry.0");
}
}
return true;
}
/**
* Returns true if the player has any type of seed in the inventory
*/
protected boolean hasSeeds(EntityPlayer player) {
if (player.capabilities.isCreativeMode) { return true; }
return getSeedType(player) != SeedType.NONE;
}
/**
* Returns the type of seed to be shot or SeedType.NONE if no seed available
*/
protected SeedType getSeedType(EntityPlayer player) {
if (seedToType.isEmpty()) {
ItemSlingshot.initializeSeeds();
}
SeedType selected = getMode(player).type;
for (ItemStack stack : player.inventory.mainInventory) {
if (stack != null && seedToType.containsKey(stack.getItem())) {
SeedType type = seedToType.get(stack.getItem());
if ((type != SeedType.COCOA || stack.getItemDamage() == 3) && (selected == null || type == selected)) {
return type;
}
}
}
return (player.capabilities.isCreativeMode ? (selected == null ? SeedType.GRASS : selected) : SeedType.NONE);
}
@Override
@SideOnly(Side.CLIENT)
public void addInformation(ItemStack stack, EntityPlayer player, List<String> list, boolean advanced) {
list.add(EnumChatFormatting.ITALIC + StatCollector.translateToLocal("tooltip.zss.slingshot.desc.0"));
if (seedsFired > 1) {
list.add(EnumChatFormatting.ITALIC + StatCollector.translateToLocalFormatted("tooltip.zss.slingshot.desc.1", seedsFired));
}
ItemStack mode = getMode(player).getSeedStack();
if (mode != null) {
list.add(EnumChatFormatting.YELLOW + StatCollector.translateToLocalFormatted("tooltip.zss.mode", mode.getDisplayName()));
}
}
@Override
public void handleFairyUpgrade(EntityItem item, EntityPlayer player, TileEntityDungeonCore core) {
ItemStack stack = item.getEntityItem();
BlockPos pos = core.getPos();
if (stack.getItem() == ZSSItems.slingshot && core.consumeRupees(Config.getSlingshotCostOne())) {
item.setDead();
player.triggerAchievement(ZSSAchievements.fairySlingshot);
WorldUtils.spawnItemWithRandom(core.getWorld(), new ItemStack(ZSSItems.scattershot), pos.getX(), pos.getY() + 2, pos.getZ());
core.getWorld().playSoundEffect(pos.getX() + 0.5D, pos.getY() + 1, pos.getZ() + 0.5D, Sounds.SECRET_MEDLEY, 1.0F, 1.0F);
} else if (stack.getItem() == ZSSItems.scattershot && core.consumeRupees(Config.getSlingshotCostTwo())) {
item.setDead();
player.triggerAchievement(ZSSAchievements.fairySupershot);
WorldUtils.spawnItemWithRandom(core.getWorld(), new ItemStack(ZSSItems.supershot), pos.getX(), pos.getY() + 2, pos.getZ());
core.getWorld().playSoundEffect(pos.getX() + 0.5D, pos.getY() + 1, pos.getZ() + 0.5D, Sounds.SECRET_MEDLEY, 1.0F, 1.0F);
} else {
addFairyEnchantments(stack, player, core);
}
}
@Override
public boolean hasFairyUpgrade(ItemStack stack) {
return true;
}
/**
* Checks for and adds any applicable fairy enchantments to the slingshot
*/
private void addFairyEnchantments(ItemStack stack, EntityPlayer player, TileEntityDungeonCore core) {
int hearts = ZSSPlayerSkills.get(player).getSkillLevel(SkillBase.bonusHeart);
int divisor = (seedsFired == 1 ? 5 : seedsFired < 4 ? 7 : 10);
int newLvl = Math.min((hearts / divisor), Enchantment.power.getMaxLevel());
int lvl = newLvl;
boolean flag = false;
boolean playSound = false;
if (stack.hasTagCompound() && stack.getTagCompound().hasKey("ench")) {
NBTTagList enchList = (NBTTagList) stack.getTagCompound().getTag("ench");
for (int i = 0; i < enchList.tagCount(); ++i) {
NBTTagCompound compound = (NBTTagCompound) enchList.getCompoundTagAt(i);
if (compound.getShort("id") == Enchantment.power.effectId) {
int oldLvl = compound.getShort("lvl");
lvl = newLvl - oldLvl;
while (lvl > 0 && core.consumeRupees(divisor * 2)) {
--lvl;
}
newLvl -= lvl;
if (newLvl > oldLvl) {
enchList.removeTag(i);
stack.addEnchantment(Enchantment.power, newLvl);
playSound = true;
}
flag = true;
break;
}
}
}
if (!flag) {
while (lvl > 0 && core.consumeRupees(divisor * 2)) {
--lvl;
}
newLvl -= lvl;
if (newLvl > 0) {
playSound = true;
stack.addEnchantment(Enchantment.power, newLvl);
}
}
BlockPos pos = core.getPos();
if (playSound) {
player.triggerAchievement(ZSSAchievements.fairyEnchantment);
core.getWorld().playSoundEffect(pos.getX() + 0.5D, pos.getY() + 1, pos.getZ() + 0.5D, Sounds.FAIRY_BLESSING, 1.0F, 1.0F);
} 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");
}
}
}