package minefantasy.mf2.item.gadget; import java.util.List; import minefantasy.mf2.MineFantasyII; import minefantasy.mf2.api.archery.AmmoMechanicsMF; import minefantasy.mf2.api.archery.IDisplayMFAmmo; import minefantasy.mf2.api.archery.IFirearm; import minefantasy.mf2.api.archery.ISpecialBow; import minefantasy.mf2.api.crafting.ISpecialSalvage; import minefantasy.mf2.api.crafting.engineer.ICrossbowPart; import minefantasy.mf2.api.weapon.IDamageModifier; import minefantasy.mf2.api.weapon.IDamageType; import minefantasy.mf2.entity.EntityArrowMF; import minefantasy.mf2.entity.EntityMine; import minefantasy.mf2.item.archery.ItemArrowMF; import minefantasy.mf2.item.list.ComponentListMF; import minefantasy.mf2.item.list.CreativeTabMF; import minefantasy.mf2.item.list.ToolListMF; import minefantasy.mf2.mechanics.BombDispenser; import minefantasy.mf2.mechanics.CombatMechanics; import net.minecraft.block.BlockDispenser; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.item.EnumRarity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.IIcon; import net.minecraft.util.StatCollector; import net.minecraft.world.World; import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public class ItemCrossbow extends Item implements IFirearm, IDisplayMFAmmo, IDamageModifier, IDamageType, IScope, ISpecialSalvage { public ItemCrossbow() { String name = "MF_CrossbowCustom"; this.setCreativeTab(CreativeTabMF.tabGadget); GameRegistry.registerItem(this, name, MineFantasyII.MODID); this.setUnlocalizedName(name); this.setFull3D(); this.setTextureName("minefantasy2:gun/stock/cross_stock_wood"); this.setMaxDamage(150); this.setMaxStackSize(1); } @Override public EnumAction getItemUseAction(ItemStack item) { String action = getUseAction(item); if(action.equalsIgnoreCase("reload")) { return EnumAction.block; } return EnumAction.bow; } @Override public ItemStack onItemRightClick(ItemStack item, World world, EntityPlayer user) { if(user.isSneaking())//OPEN INV { user.openGui(MineFantasyII.instance, 1, user.worldObj, 1, 0, 0); return item; } ItemStack loaded = AmmoMechanicsMF.getArrowOnBow(item); if(loaded == null || user.isSwingInProgress)//RELOAD { startUse(user, item, "reload"); return item; } else //FIRE { } startUse(user, item, "fire"); return item; } @Override public ItemStack onEaten(ItemStack item, World world, EntityPlayer user) { user.swingItem(); ItemStack loaded = AmmoMechanicsMF.getArrowOnBow(item); ItemStack storage = AmmoMechanicsMF.getAmmo(item); String action = getUseAction(item); if(action.equalsIgnoreCase("reload") && storage != null)//RELOAD { boolean success = false; if(loaded == null) { ItemStack ammo = storage.copy(); ammo.stackSize = 1; AmmoMechanicsMF.consumeAmmo(user, item); AmmoMechanicsMF.putAmmoOnFirearm(item, ammo); success = true; } else if(loaded.isItemEqual(storage) && loaded.stackSize < getAmmoCapacity(item)) { AmmoMechanicsMF.consumeAmmo(user, item); ++loaded.stackSize; AmmoMechanicsMF.putAmmoOnFirearm(item, loaded); success = true; } if(success) { user.playSound("random.click", 1.0F, 1.0F); } } return super.onEaten(item, world, user); } @Override public void onUsingTick(ItemStack item, EntityPlayer player, int time) { ItemStack loaded = AmmoMechanicsMF.getArrowOnBow(item); int max = getMaxItemUseDuration(item); if(time == (max-5) && getUseAction(item).equalsIgnoreCase("reload") && (loaded == null || loaded.stackSize < getAmmoCapacity(item))) { player.playSound("minefantasy2:weapon.crossbowload", 1.0F, 1 / (getFullValue(item, "speed") / 4F)); } } @Override public void onPlayerStoppedUsing(ItemStack item, World world, EntityPlayer user, int time) { ItemStack loaded = AmmoMechanicsMF.getArrowOnBow(item); String action = getUseAction(item); if(action.equalsIgnoreCase("fire") && this.onFireArrow(user.worldObj, AmmoMechanicsMF.getArrowOnBow(item), item, user, this.getFullValue(item, "power"), false)) { if(loaded != null) { --loaded.stackSize; AmmoMechanicsMF.putAmmoOnFirearm(item, (loaded.stackSize > 0 ? loaded : null)); } recoilUser(user, getFullValue(item, "recoil")); AmmoMechanicsMF.damageFirearm(item, user, 1); } stopUse(item); } public void startUse(EntityPlayer user, ItemStack item, String action) { setUseAction(item, action); if(user != null) user.setItemInUse(item, getMaxItemUseDuration(item)); } public void stopUse(ItemStack item) { startUse(null, item, "null"); } public static String useTypeNBT = "MF_ActionInUse"; public static void setUseAction(ItemStack item, String action) { AmmoMechanicsMF.getNBT(item).setString(useTypeNBT, action); } public static String getUseAction(ItemStack item) { String action = AmmoMechanicsMF.getNBT(item).getString(useTypeNBT); return action != null ? action : "null"; } private void recoilUser(EntityPlayer user, float value) { float str = CombatMechanics.getStrengthEnhancement(user)+1; value /= str; float angle = value*10F; user.rotationPitch -= itemRand.nextFloat()*angle; user.rotationYawHead += itemRand.nextFloat()*angle-0.5F; } @Override public int getMaxItemUseDuration(ItemStack item) { String action = getUseAction(item); if(action.equalsIgnoreCase("reload")) { return (int)(getFullValue(item, "speed")*20F); } return 72000; } @Override public void addInformation(ItemStack item, EntityPlayer user, List list, boolean fullInfo) { super.addInformation(item, user, list, fullInfo); list.add(StatCollector.translateToLocalFormatted("attribute.crossbow.power.name", getFullValue(item, "power"))); list.add(StatCollector.translateToLocalFormatted("attribute.crossbow.speed.name", getFullValue(item, "speed"))); list.add(StatCollector.translateToLocalFormatted("attribute.crossbow.recoil.name", getFullValue(item, "recoil"))); list.add(StatCollector.translateToLocalFormatted("attribute.crossbow.spread.name", getFullValue(item, "spread"))); list.add(StatCollector.translateToLocalFormatted("attribute.crossbow.capacity.name", getAmmoCapacity(item))); list.add(StatCollector.translateToLocalFormatted("attribute.crossbow.bash.name", getMeleeDmg(item))); } public String getItemStackDisplayName(ItemStack item) { String base = getNameModifier(item, "stock"); String arms = getNameModifier(item, "mechanism"); String mod = getNameModifier(item, "mod"); String fullName = "Crossbow"; if(base != null)fullName=base; if(arms != null)fullName=arms + " " + fullName; if(mod != null)fullName=mod + " " + fullName; return fullName; } private static final String partNBT = "MineFantasy_GunPiece_"; public static void setPart(String part, ItemStack item, int id) { NBTTagCompound nbt = getNBT(item); nbt.setInteger(partNBT+part, id); } public static int getPart(String part, ItemStack item) { NBTTagCompound nbt = getNBT(item); if(nbt.hasKey(partNBT+part)) { return nbt.getInteger(partNBT+part); } return -1; } /** * Constructs a crossbow with a list of parts */ public ItemStack constructCrossbow(ICrossbowPart...crossbowParts) { ItemStack crossbow = new ItemStack(this); for(ICrossbowPart part : crossbowParts) { if(part != null) { setPart(crossbow, part); } } return crossbow; } /** * Adds a part to a crossbow */ public ItemStack setPart(ItemStack item, ICrossbowPart part) { setPart(part.getComponentType(), item, part.getID()); return item; } public static NBTTagCompound getNBT(ItemStack item) { if(!item.hasTagCompound())item.setTagCompound(new NBTTagCompound()); return item.getTagCompound(); } @Override @SideOnly(Side.CLIENT) public IIcon getIcon(ItemStack item, int layer) { IIcon stock = getPartIcon(item, "stock"); if(stock != null && layer == 0) { return stock; } IIcon muzzle = getPartIcon(item, "muzzle"); if(muzzle != null && layer == 1) { return muzzle; } IIcon mod = getPartIcon(item, "mod"); if(mod != null && layer == 2) { return mod; } IIcon head = getPartIcon(item, "mechanism"); return head != null ? head : getIconIndex(item); } @Override @SideOnly(Side.CLIENT) public boolean requiresMultipleRenderPasses() { return true; } @Override @SideOnly(Side.CLIENT) public int getRenderPasses(int metadata) { return 4; } @Override public void getSubItems(Item item, CreativeTabs tab, List list) { list.add(constructCrossbow((ICrossbowPart)ComponentListMF.crossbow_handle_wood, (ICrossbowPart)ComponentListMF.cross_arms_basic)); list.add(constructCrossbow((ICrossbowPart)ComponentListMF.crossbow_stock_wood, (ICrossbowPart)ComponentListMF.cross_arms_light)); list.add(constructCrossbow((ICrossbowPart)ComponentListMF.crossbow_stock_wood, (ICrossbowPart)ComponentListMF.cross_arms_basic, (ICrossbowPart)ComponentListMF.cross_ammo)); list.add(constructCrossbow((ICrossbowPart)ComponentListMF.crossbow_stock_wood, (ICrossbowPart)ComponentListMF.cross_arms_heavy, (ICrossbowPart)ComponentListMF.cross_bayonet)); list.add(constructCrossbow((ICrossbowPart)ComponentListMF.crossbow_stock_iron, (ICrossbowPart)ComponentListMF.cross_arms_advanced, (ICrossbowPart)ComponentListMF.cross_scope)); } @SideOnly(Side.CLIENT) public IIcon getPartIcon(ItemStack item, String partname) { if(partname.equalsIgnoreCase("string")) { return strings[AmmoMechanicsMF.getArrowOnBow(item) != null ? 1 : 0]; } ICrossbowPart part = ItemCrossbowPart.getPart(partname, getPart(partname, item)); if(part != null) { return part.getIcon(); } return null; } public String getNameModifier(ItemStack item, String partname) { ICrossbowPart part = ItemCrossbowPart.getPart(partname, getPart(partname, item)); if(part != null) { String name = part.getUnlocalisedName(); if(name != null) { return StatCollector.translateToLocal(name); } } return null; } /** * Get the modifier for a part (such as power, speed, recoil, capacity and spread) */ public float getModifierForPart(ItemStack item, String partName, String variable) { ICrossbowPart part = ItemCrossbowPart.getPart(partName, getPart(partName, item)); if(part != null) { return part.getModifier(variable); } return 0F; } private String[] fullParts = new String[]{"mod", "muzzle", "mechanism", "stock"}; /** * Checks all "fullParts" for value modifiers */ public float getFullValue(ItemStack item, String variable) { float min = variable.equalsIgnoreCase("speed") ? 0.5F: 0F; float value = 0F; for(String part: fullParts) { value += getModifierForPart(item, part, variable); } return Math.max(min, value); } @Override public int getAmmoCapacity(ItemStack item) { return 1 + (int)getModifierForPart(item, "mod", "capacity");//only mod affects capacity } public float getMeleeDmg(ItemStack item) { return 1 + getModifierForPart(item, "muzzle", "bash");//only muzzle affects capacity } @Override public boolean canAcceptAmmo(ItemStack weapon, String ammo) { return ammo.equalsIgnoreCase("bolt"); } @Override public float[] getDamageRatio(Object... implement) { if(implement.length > 0 && implement[0] instanceof ItemStack) { if(this.getMeleeDmg((ItemStack)implement[0]) > 1.0F)//Bayonet is used { return new float[]{0F, 0F, 1F}; } } return new float[]{0F, 1F, 0F}; } @Override public float getPenetrationLevel(Object implement) { return 0; } private IIcon[] strings; @Override @SideOnly(Side.CLIENT) public void registerIcons(IIconRegister reg) { super.registerIcons(reg); strings = new IIcon[2]; strings[0] = reg.registerIcon("minefantasy2:gun/mechanism/cross_string_unload"); strings[1] = reg.registerIcon("minefantasy2:gun/mechanism/cross_string_load"); } @Override public float modifyDamage(ItemStack item, EntityLivingBase wielder, Entity hit, float initialDam, boolean properHit) { return initialDam + this.getMeleeDmg(item)-1; } public boolean onFireArrow(World world, ItemStack arrow, ItemStack bow, EntityPlayer user, float charge, boolean infinite) { if(arrow == null || !(arrow.getItem() instanceof ItemArrowMF)) { return false; } ItemArrowMF ammo = (ItemArrowMF)arrow.getItem(); if(!(ammo.getAmmoType(arrow).equalsIgnoreCase("bolt"))) { return false; } //TODO Arrow entity instance EntityArrowMF entArrow = ammo.getFiredArrow(new EntityArrowMF(world, user, getFullValue(bow, "spread"), charge*2.0F), arrow); int var9 = EnchantmentHelper.getEnchantmentLevel(Enchantment.power.effectId, bow); entArrow.setPower(1+(0.25F*var9)); int var10 = EnchantmentHelper.getEnchantmentLevel(Enchantment.punch.effectId, bow); if (var10 > 0) { entArrow.setKnockbackStrength(var10); } if (EnchantmentHelper.getEnchantmentLevel(Enchantment.flame.effectId, bow) > 0) { entArrow.setFire(100); } if(infinite) { entArrow.canBePickedUp = 2; } if(bow != null && bow.getItem() != null && bow.getItem() instanceof ISpecialBow) { entArrow = (EntityArrowMF) ((ISpecialBow)bow.getItem()).modifyArrow(bow, entArrow); } if (!world.isRemote) { world.spawnEntityInWorld(entArrow); } world.playSoundAtEntity(user, "minefantasy2:weapon.crossbow_fire", 1.0F, 1.0F); return true; } @Override public float getZoom(ItemStack item) { return getUseAction(item).equalsIgnoreCase("fire") ? getModifierForPart(item, "mod", "zoom") : 0F;//only mod affects zoom; } @Override public Object[] getSalvage(ItemStack item) { return new Object[] { getItem(item, "stock"), getItem(item, "mechanism"), getItem(item, "muzzle"), getItem(item, "mod") }; } private Object getItem(ItemStack item, String type) { return ItemCrossbowPart.getPart(type, this.getPart(type, item)); } @Override public int getMaxDamage(ItemStack item) { return super.getMaxDamage(item) + (int)getFullValue(item, "durability"); } }