mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Added support for thrown spells. Projectiles with a spell attached.
This commit is contained in:
parent
41923f82e1
commit
28e294803e
14 changed files with 247 additions and 71 deletions
|
@ -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<EntityLivingBase> {
|
||||
|
||||
private static final DataParameter<ItemStack> ITEM = EntityDataManager
|
||||
.createKey(EntityProjectile.class, DataSerializers.ITEM_STACK);
|
||||
|
||||
private static final DataParameter<Float> DAMAGE = EntityDataManager
|
||||
.createKey(EntityProjectile.class, DataSerializers.FLOAT);
|
||||
|
||||
private static final DataParameter<NBTTagCompound> EFFECT = EntityDataManager
|
||||
.createKey(EntitySpell.class, DataSerializers.COMPOUND_TAG);
|
||||
|
||||
private final EffectSync<EntityLivingBase> 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 extends IMagicEffect> T getEffect(Class<T> 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();
|
||||
|
|
|
@ -154,14 +154,8 @@ public class ItemSpell extends Item implements ICastable {
|
|||
@Override
|
||||
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
|
||||
|
||||
Entity target = VecHelper.getLookedAtEntity(player, 5);
|
||||
|
||||
ItemStack stack = player.getHeldItem(hand);
|
||||
|
||||
if (target == null) {
|
||||
return new ActionResult<ItemStack>(EnumActionResult.PASS, stack);
|
||||
}
|
||||
|
||||
if (!SpellRegistry.stackHasEnchantment(stack)) {
|
||||
return new ActionResult<ItemStack>(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) {
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<ICaster<?>> {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<String> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<T> {
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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<ItemStack> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue