From 28e294803ea261b6a62ac494158b499e50b79910 Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 5 Mar 2019 14:29:16 +0200 Subject: [PATCH] Added support for thrown spells. Projectiles with a spell attached. --- .../unicopia/entity/EntityProjectile.java | 102 ++++++++++++++++-- .../unicopia/item/ItemSpell.java | 8 +- .../unicopia/item/ItemStaff.java | 3 +- .../unicopia/item/ItemTomato.java | 4 +- .../unicopia/spell/IRangedEffect.java | 16 +++ .../unicopia/spell/ITossedEffect.java | 33 ++++++ .../unicopia/spell/IUseAction.java | 4 +- .../unicopia/spell/SpellAwkward.java | 29 ++++- .../unicopia/spell/SpellFire.java | 8 +- .../unicopia/spell/SpellIce.java | 4 +- .../unicopia/spell/SpellPortal.java | 3 +- .../unicopia/tossable/DispenserBehaviour.java | 35 ++++++ .../unicopia/tossable/ITossable.java | 19 ++++ .../ITossableItem.java} | 50 +-------- 14 files changed, 247 insertions(+), 71 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/spell/IRangedEffect.java create mode 100644 src/main/java/com/minelittlepony/unicopia/spell/ITossedEffect.java create mode 100644 src/main/java/com/minelittlepony/unicopia/tossable/DispenserBehaviour.java create mode 100644 src/main/java/com/minelittlepony/unicopia/tossable/ITossable.java rename src/main/java/com/minelittlepony/unicopia/{item/ITossable.java => tossable/ITossableItem.java} (55%) diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java index 170e8ef3..5c9b6d5c 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityProjectile.java @@ -1,7 +1,14 @@ package com.minelittlepony.unicopia.entity; -import com.minelittlepony.unicopia.item.ITossable; +import com.minelittlepony.unicopia.network.EffectSync; +import com.minelittlepony.unicopia.spell.ICaster; +import com.minelittlepony.unicopia.spell.IMagicEffect; +import com.minelittlepony.unicopia.spell.SpellAffinity; +import com.minelittlepony.unicopia.spell.SpellRegistry; +import com.minelittlepony.unicopia.tossable.ITossable; +import com.minelittlepony.unicopia.tossable.ITossableItem; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IProjectile; import net.minecraft.entity.projectile.EntitySnowball; @@ -16,13 +23,19 @@ import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; -public class EntityProjectile extends EntitySnowball { +public class EntityProjectile extends EntitySnowball implements IMagicals, ICaster { private static final DataParameter ITEM = EntityDataManager .createKey(EntityProjectile.class, DataSerializers.ITEM_STACK); + private static final DataParameter DAMAGE = EntityDataManager .createKey(EntityProjectile.class, DataSerializers.FLOAT); + private static final DataParameter EFFECT = EntityDataManager + .createKey(EntitySpell.class, DataSerializers.COMPOUND_TAG); + + private final EffectSync effectDelegate = new EffectSync<>(this, EFFECT); + public EntityProjectile(World world) { super(world); } @@ -39,12 +52,57 @@ public class EntityProjectile extends EntitySnowball { protected void entityInit() { getDataManager().register(ITEM, ItemStack.EMPTY); getDataManager().register(DAMAGE, (float)0); + getDataManager().register(EFFECT, new NBTTagCompound()); } public ItemStack getItem() { ItemStack stack = getDataManager().get(ITEM); - return stack == null ? ItemStack.EMPTY : stack; + return stack == null ? ItemStack.EMPTY : stack; + } + + @Override + public Entity getEntity() { + return this; + } + + @Override + public void setOwner(EntityLivingBase owner) { + thrower = owner; + } + + @Override + public EntityLivingBase getOwner() { + return getThrower(); + } + + @Override + public int getCurrentLevel() { + return 1; + } + + @Override + public void setCurrentLevel(int level) { + } + + @Override + public SpellAffinity getAffinity() { + return hasEffect() ? SpellAffinity.NEUTRAL : getEffect().getAffinity(); + } + + @Override + public void setEffect(IMagicEffect effect) { + effectDelegate.set(effect); + } + + @Override + public T getEffect(Class type, boolean update) { + return effectDelegate.get(type, update); + } + + @Override + public boolean hasEffect() { + return effectDelegate.has(); } public void setItem(ItemStack stack) { @@ -71,6 +129,27 @@ public class EntityProjectile extends EntitySnowball { } else { setItem(itemstack); } + + if (compound.hasKey("effect")) { + setEffect(SpellRegistry.instance().createEffectFromNBT(compound.getCompoundTag("effect"))); + } + } + + @Override + public void onUpdate() { + super.onUpdate(); + + if (hasEffect()) { + if (getEffect().getDead()) { + setDead(); + } else { + getEffect().update(this); + } + + if (world.isRemote) { + getEffect().render(this); + } + } } @Override @@ -93,6 +172,10 @@ public class EntityProjectile extends EntitySnowball { if (!itemstack.isEmpty()) { compound.setTag("Item", itemstack.writeToNBT(new NBTTagCompound())); } + + if (hasEffect()) { + compound.setTag("effect", SpellRegistry.instance().serializeEffectToNBT(getEffect())); + } } @Override @@ -101,8 +184,15 @@ public class EntityProjectile extends EntitySnowball { if (result.typeOfHit == RayTraceResult.Type.BLOCK) { Item item = getItem().getItem(); - if (item instanceof ITossable) { - ((ITossable)item).onImpact(world, result.getBlockPos(), world.getBlockState(result.getBlockPos())); + if (item instanceof ITossableItem) { + ((ITossableItem)item).onImpact(world, result.getBlockPos(), world.getBlockState(result.getBlockPos())); + } + + if (hasEffect()) { + IMagicEffect effect = this.getEffect(); + if (effect instanceof ITossable) { + ((ITossable)effect).onImpact(world, result.getBlockPos(), world.getBlockState(result.getBlockPos())); + } } } @@ -110,8 +200,6 @@ public class EntityProjectile extends EntitySnowball { result.entityHit.attackEntityFrom(DamageSource.causeThrownDamage(this, getThrower()), getThrowDamage()); } - - if (!world.isRemote) { world.setEntityState(this, (byte)3); setDead(); diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemSpell.java b/src/main/java/com/minelittlepony/unicopia/item/ItemSpell.java index 1bb32617..746fcb68 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/ItemSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/item/ItemSpell.java @@ -154,14 +154,8 @@ public class ItemSpell extends Item implements ICastable { @Override public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { - Entity target = VecHelper.getLookedAtEntity(player, 5); - ItemStack stack = player.getHeldItem(hand); - if (target == null) { - return new ActionResult(EnumActionResult.PASS, stack); - } - if (!SpellRegistry.stackHasEnchantment(stack)) { return new ActionResult(EnumActionResult.FAIL, stack); } @@ -169,7 +163,7 @@ public class ItemSpell extends Item implements ICastable { IUseAction effect = SpellRegistry.instance().getUseActionFrom(stack); if (effect != null) { - SpellCastResult result = effect.onUse(stack, getAffinity(stack), player, world, target); + SpellCastResult result = effect.onUse(stack, getAffinity(stack), player, world, VecHelper.getLookedAtEntity(player, 5)); if (result != SpellCastResult.NONE) { if (result == SpellCastResult.PLACE && !player.capabilities.isCreativeMode) { diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemStaff.java b/src/main/java/com/minelittlepony/unicopia/item/ItemStaff.java index 80ff197b..a35bd838 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/ItemStaff.java +++ b/src/main/java/com/minelittlepony/unicopia/item/ItemStaff.java @@ -8,6 +8,7 @@ import javax.annotation.Nullable; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.minelittlepony.unicopia.Predicates; +import com.minelittlepony.unicopia.tossable.ITossableItem; import com.minelittlepony.util.lang.ClientLocale; import net.minecraft.block.Block; @@ -32,7 +33,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; -public class ItemStaff extends ItemSword implements ITossable { +public class ItemStaff extends ItemSword implements ITossableItem { protected static final UUID ATTACK_REACH_MODIFIER = UUID.fromString("FA235E1C-4280-A865-B01B-CBAE9985ACA3"); diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java b/src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java index 036a67e6..75e9ab6e 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java +++ b/src/main/java/com/minelittlepony/unicopia/item/ItemTomato.java @@ -2,6 +2,8 @@ package com.minelittlepony.unicopia.item; import com.minelittlepony.unicopia.forgebullshit.IMultiItem; import com.minelittlepony.unicopia.player.PlayerSpeciesList; +import com.minelittlepony.unicopia.tossable.ITossableItem; + import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; @@ -17,7 +19,7 @@ import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -public class ItemTomato extends ItemFood implements ITossable, IMultiItem { +public class ItemTomato extends ItemFood implements ITossableItem, IMultiItem { private final String name; diff --git a/src/main/java/com/minelittlepony/unicopia/spell/IRangedEffect.java b/src/main/java/com/minelittlepony/unicopia/spell/IRangedEffect.java new file mode 100644 index 00000000..2eea5293 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/spell/IRangedEffect.java @@ -0,0 +1,16 @@ +package com.minelittlepony.unicopia.spell; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.ItemStack; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public interface IRangedEffect extends IMagicEffect { + void onImpact(World world, BlockPos pos, IBlockState state); + + default SoundEvent getThrowSound(ItemStack stack) { + return SoundEvents.ENTITY_SNOWBALL_THROW; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/spell/ITossedEffect.java b/src/main/java/com/minelittlepony/unicopia/spell/ITossedEffect.java new file mode 100644 index 00000000..3043f625 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/spell/ITossedEffect.java @@ -0,0 +1,33 @@ +package com.minelittlepony.unicopia.spell; + +import com.minelittlepony.unicopia.entity.EntityProjectile; +import com.minelittlepony.unicopia.init.UItems; +import com.minelittlepony.unicopia.tossable.ITossable; + +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.SoundCategory; +import net.minecraft.world.World; + +public interface ITossedEffect extends IMagicEffect, ITossable> { + + default void toss(ICaster caster) { + World world = caster.getWorld(); + + Entity entity = caster.getOwner(); + + world.playSound(null, entity.posX, entity.posY, entity.posZ, getThrowSound(caster), SoundCategory.NEUTRAL, 0.5F, 0.4F / (world.rand.nextFloat() * 0.4F + 0.8F)); + + if (!world.isRemote) { + EntityProjectile projectile = new EntityProjectile(world, caster.getOwner()); + + projectile.setItem(new ItemStack(UItems.spell)); + projectile.setThrowDamage(getThrowDamage(caster)); + projectile.setOwner(caster.getOwner()); + projectile.setEffect(this); + projectile.shoot(entity, entity.rotationPitch, entity.rotationYaw, 0, 1.5F, 1); + + world.spawnEntity(projectile); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/spell/IUseAction.java b/src/main/java/com/minelittlepony/unicopia/spell/IUseAction.java index 83d9603f..33642726 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/IUseAction.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/IUseAction.java @@ -1,6 +1,6 @@ package com.minelittlepony.unicopia.spell; -import javax.annotation.Nonnull; +import javax.annotation.Nullable; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; @@ -43,5 +43,5 @@ public interface IUseAction { * * @return ActionResult for the type of action to perform */ - SpellCastResult onUse(ItemStack stack, SpellAffinity affinity, EntityPlayer player, World world, @Nonnull Entity hitEntity); + SpellCastResult onUse(ItemStack stack, SpellAffinity affinity, EntityPlayer player, World world, @Nullable Entity hitEntity); } diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellAwkward.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellAwkward.java index bf6b7203..8a54ea5a 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/SpellAwkward.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellAwkward.java @@ -2,13 +2,22 @@ package com.minelittlepony.unicopia.spell; import java.util.List; +import javax.annotation.Nullable; + import com.google.common.collect.Lists; import com.minelittlepony.util.shape.Sphere; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; -public class SpellAwkward extends AbstractSpell { +public class SpellAwkward extends AbstractSpell implements ITossedEffect, IUseAction { private final List names = Lists.newArrayList(EnumParticleTypes.getParticleNames()); @@ -60,4 +69,22 @@ public class SpellAwkward extends AbstractSpell { default: return true; } } + + @Override + public void onImpact(World world, BlockPos pos, IBlockState state) { + // noop + } + + @Override + public SpellCastResult onUse(ItemStack stack, SpellAffinity affinity, EntityPlayer player, World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ) { + return SpellCastResult.PLACE; + } + + @Override + public SpellCastResult onUse(ItemStack stack, SpellAffinity affinity, EntityPlayer player, World world, @Nullable Entity hitEntity) { + + CasterUtils.toCaster(player).ifPresent(this::toss); + + return SpellCastResult.NONE; + } } diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellFire.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellFire.java index 946946d1..ce07f9ea 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/SpellFire.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellFire.java @@ -1,6 +1,6 @@ package com.minelittlepony.unicopia.spell; -import javax.annotation.Nonnull; +import javax.annotation.Nullable; import com.minelittlepony.unicopia.Predicates; import com.minelittlepony.unicopia.entity.IMagicals; @@ -114,7 +114,11 @@ public class SpellFire extends AbstractSpell.RangedAreaSpell implements IUseActi } @Override - public SpellCastResult onUse(ItemStack stack, SpellAffinity affinity, EntityPlayer player, World world, @Nonnull Entity hitEntity) { + public SpellCastResult onUse(ItemStack stack, SpellAffinity affinity, EntityPlayer player, World world, @Nullable Entity hitEntity) { + if (hitEntity == null) { + return SpellCastResult.NONE; + } + return applyEntitySingle(player, world, hitEntity) ? SpellCastResult.DEFAULT : SpellCastResult.NONE; } diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellIce.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellIce.java index e4c7631e..272c1a8c 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/SpellIce.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellIce.java @@ -1,5 +1,7 @@ package com.minelittlepony.unicopia.spell; +import javax.annotation.Nullable; + import com.minelittlepony.unicopia.init.UMaterials; import com.minelittlepony.util.MagicalDamageSource; import com.minelittlepony.util.PosHelper; @@ -96,7 +98,7 @@ public class SpellIce extends AbstractSpell.RangedAreaSpell implements IUseActio } @Override - public SpellCastResult onUse(ItemStack stack, SpellAffinity affinity, EntityPlayer player, World world, Entity hitEntity) { + public SpellCastResult onUse(ItemStack stack, SpellAffinity affinity, EntityPlayer player, World world, @Nullable Entity hitEntity) { if (hitEntity != null && applyEntitySingle(player, hitEntity)) { return SpellCastResult.DEFAULT; } diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellPortal.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellPortal.java index 39dfe27d..7852bc7c 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/SpellPortal.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellPortal.java @@ -4,7 +4,6 @@ import java.util.Locale; import java.util.Optional; import java.util.UUID; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.minelittlepony.unicopia.entity.EntitySpell; @@ -127,7 +126,7 @@ public class SpellPortal extends AbstractSpell.RangedAreaSpell implements IUseAc } @Override - public SpellCastResult onUse(ItemStack stack, SpellAffinity affinity, EntityPlayer player, World world, @Nonnull Entity hitEntity) { + public SpellCastResult onUse(ItemStack stack, SpellAffinity affinity, EntityPlayer player, World world, @Nullable Entity hitEntity) { return SpellCastResult.NONE; } diff --git a/src/main/java/com/minelittlepony/unicopia/tossable/DispenserBehaviour.java b/src/main/java/com/minelittlepony/unicopia/tossable/DispenserBehaviour.java new file mode 100644 index 00000000..1c8a3131 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/tossable/DispenserBehaviour.java @@ -0,0 +1,35 @@ +package com.minelittlepony.unicopia.tossable; + +import net.minecraft.block.BlockDispenser; +import net.minecraft.dispenser.BehaviorDefaultDispenseItem; +import net.minecraft.dispenser.IBlockSource; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; + +class DispenserBehaviour extends BehaviorDefaultDispenseItem { + @Override + public ItemStack dispenseStack(IBlockSource source, ItemStack stack) { + ITossableItem tossable = (ITossableItem)stack.getItem(); + + if (tossable.canBeThrown(stack)) { + return shootStack(source, stack); + } + + return super.dispenseStack(source, stack); + } + + public ItemStack shootStack(IBlockSource source, ItemStack stack) { + return ((ITossableItem)stack.getItem()).toss(source.getWorld(), + BlockDispenser.getDispensePosition(source), + (EnumFacing)source.getBlockState().getValue(BlockDispenser.FACING), + stack, getProjectileInaccuracy(), getProjectileVelocity()); + } + + protected float getProjectileInaccuracy() { + return 6.0F; + } + + protected float getProjectileVelocity() { + return 1.1F; + } +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/tossable/ITossable.java b/src/main/java/com/minelittlepony/unicopia/tossable/ITossable.java new file mode 100644 index 00000000..b95b0c9a --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/tossable/ITossable.java @@ -0,0 +1,19 @@ +package com.minelittlepony.unicopia.tossable; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.SoundEvents; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public interface ITossable { + void onImpact(World world, BlockPos pos, IBlockState state); + + default SoundEvent getThrowSound(T stack) { + return SoundEvents.ENTITY_SNOWBALL_THROW; + } + + default int getThrowDamage(T stack) { + return 0; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/ITossable.java b/src/main/java/com/minelittlepony/unicopia/tossable/ITossableItem.java similarity index 55% rename from src/main/java/com/minelittlepony/unicopia/item/ITossable.java rename to src/main/java/com/minelittlepony/unicopia/tossable/ITossableItem.java index ad32e5e1..b97b0657 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/ITossable.java +++ b/src/main/java/com/minelittlepony/unicopia/tossable/ITossableItem.java @@ -1,45 +1,29 @@ -package com.minelittlepony.unicopia.item; +package com.minelittlepony.unicopia.tossable; import com.minelittlepony.unicopia.entity.EntityProjectile; import net.minecraft.block.BlockDispenser; -import net.minecraft.block.state.IBlockState; -import net.minecraft.dispenser.BehaviorDefaultDispenseItem; import net.minecraft.dispenser.IBehaviorDispenseItem; -import net.minecraft.dispenser.IBlockSource; import net.minecraft.dispenser.IPosition; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.stats.StatList; import net.minecraft.util.EnumFacing; import net.minecraft.util.SoundCategory; -import net.minecraft.util.SoundEvent; -import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -public interface ITossable { - IBehaviorDispenseItem dispenserBehavior = new ITossable.DispenserBehaviour(); +public interface ITossableItem extends ITossable { + IBehaviorDispenseItem dispenserBehavior = new DispenserBehaviour(); boolean canBeThrown(ItemStack stack); - void onImpact(World world, BlockPos pos, IBlockState state); - default Item setDispenseable() { BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject((Item)(Object)this, dispenserBehavior); return (Item)(Object)this; } - default SoundEvent getThrowSound(ItemStack stack) { - return SoundEvents.ENTITY_SNOWBALL_THROW; - } - - default int getThrowDamage(ItemStack stack) { - return 0; - } - default void toss(World world, ItemStack itemstack, EntityPlayer player) { if (!player.capabilities.isCreativeMode) { itemstack.shrink(1); @@ -74,32 +58,4 @@ public interface ITossable { return stack; } - - class DispenserBehaviour extends BehaviorDefaultDispenseItem { - @Override - public ItemStack dispenseStack(IBlockSource source, ItemStack stack) { - ITossable tossable = (ITossable)stack.getItem(); - - if (tossable.canBeThrown(stack)) { - return shootStack(source, stack); - } - - return super.dispenseStack(source, stack); - } - - public ItemStack shootStack(IBlockSource source, ItemStack stack) { - return ((ITossable)stack.getItem()).toss(source.getWorld(), - BlockDispenser.getDispensePosition(source), - (EnumFacing)source.getBlockState().getValue(BlockDispenser.FACING), - stack, getProjectileInaccuracy(), getProjectileVelocity()); - } - - protected float getProjectileInaccuracy() { - return 6.0F; - } - - protected float getProjectileVelocity() { - return 1.1F; - } - } }