diff --git a/src/main/java/mod/icarus/crimsonrevelations/init/EventHandler.java b/src/main/java/mod/icarus/crimsonrevelations/init/EventHandler.java new file mode 100644 index 0000000..e33f57b --- /dev/null +++ b/src/main/java/mod/icarus/crimsonrevelations/init/EventHandler.java @@ -0,0 +1,66 @@ +package mod.icarus.crimsonrevelations.init; + +import mod.icarus.crimsonrevelations.CrimsonRevelations; +import mod.icarus.crimsonrevelations.item.ItemCRBow; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraftforge.client.event.FOVUpdateEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.registry.GameRegistry; + +@EventBusSubscriber(modid = CrimsonRevelations.MODID) +@GameRegistry.ObjectHolder(CrimsonRevelations.MODID) +public class EventHandler { + // Courtesy of NeRdTheNed + @SubscribeEvent + public void FOV(FOVUpdateEvent event) { + final EntityPlayer eventPlayer = event.getEntity(); + final Item eventItem = eventPlayer.getActiveItemStack().getItem(); + + if (eventItem instanceof ItemCRBow) { + float finalFov = event.getFov(); + final float itemUseCount = ((ItemCRBow) eventItem).getMaxItemUseDuration(eventPlayer.getActiveItemStack()) - eventPlayer.getItemInUseCount(); + /* + * First, we have to reverse the standard bow zoom. + * Minecraft helpfully applies the standard bow zoom + * to any item that is an instance of a ItemBow. + * However, our custom bows draw back at different speeds, + * so the standard zoom is not at the right speed. + * To compensate for this, we just calculate the standard bow zoom, + * and apply it in reverse. + */ + float realBow = itemUseCount / 20.0F; + + if (realBow > 1.0F) { + realBow = 1.0F; + } else { + realBow *= realBow; + } + + /* + * Minecraft uses finalFov *= 1.0F - (realBow * 0.15F) + * to calculate the standard bow zoom. + * To reverse this, we just divide it instead. + */ + finalFov /= 1.0F - (realBow * 0.15F); + /* + * We now calculate and apply our custom bow zoom. + * The only difference between standard bow zoom and custom bow zoom + * is that we change the hardcoded value of 20.0F to + * whatever drawTime is. + */ + float drawTime = 20 * ((ItemCRBow) eventItem).drawTimeMult; + float customBow = itemUseCount / drawTime; + + if (customBow > 1.0F) { + customBow = 1.0F; + } else { + customBow *= customBow; + } + + finalFov *= 1.0F - (customBow * 0.15F); + event.setNewfov(finalFov); + } + } +} diff --git a/src/main/java/mod/icarus/crimsonrevelations/init/RegistryHandler.java b/src/main/java/mod/icarus/crimsonrevelations/init/RegistryHandler.java index 8324093..fd7c5e0 100644 --- a/src/main/java/mod/icarus/crimsonrevelations/init/RegistryHandler.java +++ b/src/main/java/mod/icarus/crimsonrevelations/init/RegistryHandler.java @@ -7,7 +7,7 @@ import mod.icarus.crimsonrevelations.item.ItemCR; import mod.icarus.crimsonrevelations.item.ItemCRSword; import mod.icarus.crimsonrevelations.item.armor.ItemCultistArcherArmor; - +import mod.icarus.crimsonrevelations.item.weapons.ItemBoneBow; import net.minecraft.block.Block; import net.minecraft.block.BlockDoor; import net.minecraft.block.BlockSlab; @@ -69,7 +69,9 @@ public static void registerItems(RegistryEvent.Register event) { setup(new ItemCultistArcherArmor(EntityEquipmentSlot.HEAD), "crimson_archer_helmet"), setup(new ItemCultistArcherArmor(EntityEquipmentSlot.CHEST), "crimson_archer_chestplate"), - setup(new ItemCultistArcherArmor(EntityEquipmentSlot.LEGS), "crimson_archer_leggings") + setup(new ItemCultistArcherArmor(EntityEquipmentSlot.LEGS), "crimson_archer_leggings"), + + setup(new ItemBoneBow(), "bone_bow") ); } diff --git a/src/main/java/mod/icarus/crimsonrevelations/item/ItemCRBow.java b/src/main/java/mod/icarus/crimsonrevelations/item/ItemCRBow.java new file mode 100644 index 0000000..ff78e93 --- /dev/null +++ b/src/main/java/mod/icarus/crimsonrevelations/item/ItemCRBow.java @@ -0,0 +1,134 @@ +package mod.icarus.crimsonrevelations.item; + +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.init.Enchantments; +import net.minecraft.init.Items; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.ItemArrow; +import net.minecraft.item.ItemBow; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.stats.StatList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundCategory; +import net.minecraft.world.World; +import net.minecraftforge.event.ForgeEventFactory; + +public class ItemCRBow extends ItemBow { + public float damageMult; + public float velocityMult; + public float inaccuracy; + public float drawTimeMult; + public EnumRarity rarity; + public Ingredient repairMaterial; + + public ItemCRBow(int durability, float damageMult, float velocityMult, float drawTimeMult, float inaccuracy, EnumRarity rarity, Ingredient repairMaterial) { + this.maxStackSize = 1; + this.setMaxDamage(durability); + this.damageMult = damageMult; + this.velocityMult = velocityMult; + this.drawTimeMult = drawTimeMult; + this.inaccuracy = inaccuracy; + this.rarity = rarity; + this.repairMaterial = repairMaterial; + this.addPropertyOverride(new ResourceLocation("pull"), (ItemStack bow, World world, EntityLivingBase entity) -> { + if (entity == null) { + return 0.0F; + } + + float drawTime = 20.0F * drawTimeMult; + + return (this.getMaxItemUseDuration(bow) - entity.getItemInUseCount()) / drawTime; + }); + } + + @Override + public void onPlayerStoppedUsing(ItemStack itemStack, World world, EntityLivingBase entityLiving, int timeInUse) { + if (entityLiving instanceof EntityPlayer) { + EntityPlayer player = (EntityPlayer) entityLiving; + boolean isInfinityEnchant = player.capabilities.isCreativeMode || EnchantmentHelper.getEnchantmentLevel(Enchantments.INFINITY, itemStack) > 0; + ItemStack stack = this.findAmmo(player); + + float chargeDivider = 1 * drawTimeMult; + + int charge = (int) ((this.getMaxItemUseDuration(itemStack) - timeInUse) / chargeDivider); + charge = ForgeEventFactory.onArrowLoose(itemStack, world, player, charge, !stack.isEmpty() || isInfinityEnchant); + if (charge < 0) return; + + if ((!stack.isEmpty() || isInfinityEnchant)) { + if (stack.isEmpty()) { + stack = new ItemStack(Items.ARROW); + } + + float arrowVelocity = getArrowVelocity(charge); + + if ((double) arrowVelocity >= 0.1D) { + boolean arrowInfinite = player.capabilities.isCreativeMode || (stack.getItem() instanceof ItemArrow && ((ItemArrow) stack.getItem()).isInfinite(stack, itemStack, player)); + + if (!world.isRemote) { + ItemArrow itemArrow = (ItemArrow) (stack.getItem() instanceof ItemArrow ? stack.getItem() : Items.ARROW); + EntityArrow entityArrow = itemArrow.createArrow(world, stack, player); + entityArrow = this.customizeArrow(entityArrow); + entityArrow.shoot(player, player.rotationPitch, player.rotationYaw, 0.0F, (arrowVelocity * 3.0F) * velocityMult, inaccuracy); + + if (arrowVelocity == 1.0F) { + entityArrow.setIsCritical(true); + } + + entityArrow.setDamage(entityArrow.getDamage() * damageMult); + + int power = EnchantmentHelper.getEnchantmentLevel(Enchantments.POWER, itemStack); + + if (power > 0) { + entityArrow.setDamage(entityArrow.getDamage() + (double) power * 0.5D + 0.5D); + } + + int punch = EnchantmentHelper.getEnchantmentLevel(Enchantments.PUNCH, itemStack); + + if (punch > 0) { + entityArrow.setKnockbackStrength(punch); + } + + if (EnchantmentHelper.getEnchantmentLevel(Enchantments.FLAME, itemStack) > 0) { + entityArrow.setFire(100); + } + + itemStack.damageItem(1, player); + + if (arrowInfinite || player.capabilities.isCreativeMode && (stack.getItem() == Items.SPECTRAL_ARROW || stack.getItem() == Items.TIPPED_ARROW)) { + entityArrow.pickupStatus = EntityArrow.PickupStatus.CREATIVE_ONLY; + } + + world.spawnEntity(entityArrow); + } + + world.playSound(null, player.posX, player.posY, player.posZ, SoundEvents.ENTITY_ARROW_SHOOT, SoundCategory.PLAYERS, 1.0F, 1.0F / (itemRand.nextFloat() * 0.4F + 1.2F) + arrowVelocity * 0.5F); + + if (!arrowInfinite && !player.capabilities.isCreativeMode) { + stack.shrink(1); + + if (stack.isEmpty()) { + player.inventory.deleteStack(stack); + } + } + + player.addStat(StatList.getObjectUseStats(this)); + } + } + } + } + + @Override + public EnumRarity getRarity(ItemStack stack) { + return rarity; + } + + @Override + public boolean getIsRepairable(ItemStack toRepair, ItemStack repair) { + return repairMaterial.test(repair) || super.getIsRepairable(toRepair, repair); + } +} diff --git a/src/main/java/mod/icarus/crimsonrevelations/item/weapons/ItemBoneBow.java b/src/main/java/mod/icarus/crimsonrevelations/item/weapons/ItemBoneBow.java new file mode 100644 index 0000000..20c6dd7 --- /dev/null +++ b/src/main/java/mod/icarus/crimsonrevelations/item/weapons/ItemBoneBow.java @@ -0,0 +1,49 @@ +package mod.icarus.crimsonrevelations.item.weapons; + +import mod.icarus.crimsonrevelations.item.ItemCRBow; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.Items; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.Ingredient; + +public class ItemBoneBow extends ItemCRBow { + public ItemBoneBow() { + // Durability, Damage Multiplier, Velocity Multiplier, Draw Time Multipler, Inaccuracy, Rarity, Repair Material + super(512, 1.5F, 1.5F, 0.8F, 0.8F, EnumRarity.UNCOMMON, Ingredient.fromStacks(new ItemStack(Items.BONE))); + } + + @Override + public void onUsingTick(ItemStack stack, EntityLivingBase player, int count) { + int ticks = this.getMaxItemUseDuration(stack) - count; + + if (ticks > 18) { + player.stopActiveHand(); + } + } + + @Override + public boolean canContinueUsing(ItemStack oldStack, ItemStack newStack) { + return true; + } + + @Override + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return false; + } + + @Override + public int getItemEnchantability() { + return 3; + } + + @Override + public EnumRarity getRarity(ItemStack stack) { + return rarity; + } + + @Override + public boolean getIsRepairable(ItemStack toRepair, ItemStack repair) { + return repairMaterial.test(repair) || super.getIsRepairable(toRepair, repair); + } +} diff --git a/src/main/resources/assets/crimsonrevelations/lang/en_us.lang b/src/main/resources/assets/crimsonrevelations/lang/en_us.lang index f2676f2..fabb5ac 100644 --- a/src/main/resources/assets/crimsonrevelations/lang/en_us.lang +++ b/src/main/resources/assets/crimsonrevelations/lang/en_us.lang @@ -2,6 +2,7 @@ itemGroup.CrimsonRevelationsTab=New Crimson Revelations entity.crimsonrevelations.overgrown_taintacle.name=Overgrown Taintacle +item.crimsonrevelations.bone_bow.name=Bow of Bone item.crimsonrevelations.crimson_archer_helmet.name=Crimson Archer Helm item.crimsonrevelations.crimson_archer_chestplate.name=Crimson Archer Chestplate item.crimsonrevelations.crimson_archer_leggings.name=Crimson Archer Leggings diff --git a/src/main/resources/assets/crimsonrevelations/models/item/bone_bow.json b/src/main/resources/assets/crimsonrevelations/models/item/bone_bow.json new file mode 100644 index 0000000..94195ca --- /dev/null +++ b/src/main/resources/assets/crimsonrevelations/models/item/bone_bow.json @@ -0,0 +1,50 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "crimsonrevelations:items/bone_bow_standby" + }, + "display": { + "thirdperson_righthand": { + "rotation": [ -80, 260, -40 ], + "translation": [ -1, -2, 2.5 ], + "scale": [ 0.9, 0.9, 0.9 ] + }, + "thirdperson_lefthand": { + "rotation": [ -80, -280, 40 ], + "translation": [ -1, -2, 2.5 ], + "scale": [ 0.9, 0.9, 0.9 ] + }, + "firstperson_righthand": { + "rotation": [ 0, -90, 25 ], + "translation": [ 1.13, 3.2, 1.13], + "scale": [ 0.68, 0.68, 0.68 ] + }, + "firstperson_lefthand": { + "rotation": [ 0, 90, -25 ], + "translation": [ 1.13, 3.2, 1.13], + "scale": [ 0.68, 0.68, 0.68 ] + } + }, + "overrides": [ + { + "predicate": { + "pulling": 1 + }, + "model": "crimsonrevelations:item/bone_bow_pulling_0" + }, + { + "predicate": { + "pulling": 1, + "pull": 0.65 + }, + "model": "crimsonrevelations:item/bone_bow_pulling_1" + }, + { + "predicate": { + "pulling": 1, + "pull": 0.9 + }, + "model": "crimsonrevelations:item/bone_bow_pulling_2" + } + ] +} diff --git a/src/main/resources/assets/crimsonrevelations/models/item/bone_bow_pulling_0.json b/src/main/resources/assets/crimsonrevelations/models/item/bone_bow_pulling_0.json new file mode 100644 index 0000000..3e0dbf8 --- /dev/null +++ b/src/main/resources/assets/crimsonrevelations/models/item/bone_bow_pulling_0.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "crimsonrevelations:items/bone_bow_pulling_0" + } +} diff --git a/src/main/resources/assets/crimsonrevelations/models/item/bone_bow_pulling_1.json b/src/main/resources/assets/crimsonrevelations/models/item/bone_bow_pulling_1.json new file mode 100644 index 0000000..7a39e7a --- /dev/null +++ b/src/main/resources/assets/crimsonrevelations/models/item/bone_bow_pulling_1.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "crimsonrevelations:items/bone_bow_pulling_1" + } +} diff --git a/src/main/resources/assets/crimsonrevelations/models/item/bone_bow_pulling_2.json b/src/main/resources/assets/crimsonrevelations/models/item/bone_bow_pulling_2.json new file mode 100644 index 0000000..5eb1c39 --- /dev/null +++ b/src/main/resources/assets/crimsonrevelations/models/item/bone_bow_pulling_2.json @@ -0,0 +1,6 @@ +{ + "parent": "item/bow", + "textures": { + "layer0": "crimsonrevelations:items/bone_bow_pulling_2" + } +}