From 634ab607bfbe2062feece374d8ec13c89c0e220e Mon Sep 17 00:00:00 2001 From: Sollace Date: Fri, 1 Feb 2019 01:07:19 +0200 Subject: [PATCH] Fixed various issues with shields --- .../unicopia/particle/Particles.java | 5 + .../unicopia/spell/ICaster.java | 4 + .../unicopia/spell/SpellShield.java | 104 +++++++++++------- .../minelittlepony/util/ProjectileUtil.java | 37 ++++--- 4 files changed, 92 insertions(+), 58 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/particle/Particles.java b/src/main/java/com/minelittlepony/unicopia/particle/Particles.java index 56bb20b7..8f3ceaa7 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/Particles.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/Particles.java @@ -42,6 +42,11 @@ public class Particles { return -id - 1; } + @Nullable + public void spawnParticle(int particleId, boolean ignoreDistance, Vec3d pos, Vec3d vel, int ...pars) { + spawnParticle(particleId, ignoreDistance, pos.x, pos.y, pos.z, vel.x, vel.y, vel.z, pars); + } + @Nullable public void spawnParticle(int particleId, boolean ignoreDistance, Vec3d pos, double speedX, double speedY, double speedZ, int ...pars) { spawnParticle(particleId, ignoreDistance, pos.x, pos.y, pos.z, speedX, speedY, speedZ, pars); diff --git a/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java b/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java index a13e1a10..fb163ea4 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java @@ -46,6 +46,10 @@ public interface ICaster extends IOwned, ILevelle return getEntity().getPosition(); } + default Vec3d getOriginVector() { + return getEntity().getPositionVector(); + } + default void spawnParticles(IShape area, int count, Consumer particleSpawner) { Random rand = getWorld().rand; diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellShield.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellShield.java index fe2b0a04..7ab6716d 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/SpellShield.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellShield.java @@ -1,9 +1,9 @@ package com.minelittlepony.unicopia.spell; import com.minelittlepony.unicopia.Predicates; -import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.UParticles; import com.minelittlepony.unicopia.particle.Particles; +import com.minelittlepony.unicopia.player.IPlayer; import com.minelittlepony.unicopia.player.PlayerSpeciesList; import com.minelittlepony.unicopia.power.IPower; import com.minelittlepony.util.ProjectileUtil; @@ -14,7 +14,6 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; public class SpellShield extends AbstractSpell { @@ -76,66 +75,87 @@ public class SpellShield extends AbstractSpell { double radius = 4 + (level * 2); Entity owner = source.getOwner(); - BlockPos pos = source.getOrigin(); - int x = pos.getX(), y = pos.getY(), z = pos.getZ(); + boolean ownerIsValid = source.getAffinity() != SpellAffinity.BAD && Predicates.MAGI.test(owner); - boolean ownerIsValid = Predicates.MAGI.test(owner); + source.findAllEntitiesInRange(radius) + .filter(entity -> !(ownerIsValid && entity.equals(owner))) + .forEach(i -> { + double dist = Math.sqrt(i.getDistanceSq(source.getOrigin())); - source.findAllEntitiesInRange(radius).filter(entity -> !(ownerIsValid && entity.equals(owner))).forEach(i -> { - double dist = i.getDistance(x, y, z); - - if (ProjectileUtil.isProjectile(i)) { - if (!ProjectileUtil.isProjectileThrownBy(i, owner)) { - if (dist < radius/2) { - i.playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1F, 1); - i.setDead(); - } else { - ricochet(i, pos); - } - } - } else if (i instanceof EntityLivingBase) { - double force = Math.min(0.25F, dist); - - if (i instanceof EntityPlayer) { - force = calculateForce((EntityPlayer)i); - } - - i.addVelocity( - -(x - i.posX) / force, - -(y - i.posY) / force + (dist < 1 ? dist : 0), - -(z - i.posZ) / force); - } - }); + applyRadialEffect(source, i, dist, radius); + }); return true; } - protected double calculateForce(EntityPlayer player) { - Race race = PlayerSpeciesList.instance().getPlayer(player).getPlayerSpecies(); + protected void applyRadialEffect(ICaster source, Entity target, double distance, double radius) { + Vec3d pos = source.getOriginVector(); - double force = 4 * 8; + if (ProjectileUtil.isProjectile(target)) { + if (!ProjectileUtil.isProjectileThrownBy(target, source.getOwner())) { + if (distance < radius/2) { + target.playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1F, 1); + target.setDead(); + } else { + ricochet(target, pos); + } + } + } else if (target instanceof EntityLivingBase) { + double force = Math.min(0.25F, distance); - if (race.canUseEarth()) { - if (player.isSneaking()) { - force *= 16; + if (source.getAffinity() != SpellAffinity.BAD && target instanceof EntityPlayer) { + force *= calculateAdjustedForce(PlayerSpeciesList.instance().getPlayer((EntityPlayer)target)); + } + + applyForce(pos, target, force, distance); + } + } + + /** + * Applies a force to the given entity based on distance from the source. + */ + protected void applyForce(Vec3d pos, Entity target, double force, double distance) { + pos = target.getPositionVector().subtract(pos); + + target.addVelocity( + force / pos.x, + force / pos.y + (distance < 1 ? distance : 0), + force / pos.z + ); + } + + /** + * Returns a force to apply based on the given player's given race. + */ + protected double calculateAdjustedForce(IPlayer player) { + double force = 0.75; + + if (player.getPlayerSpecies().canUseEarth()) { + force /= 2; + + if (player.getOwner().isSneaking()) { + force /= 6; } - } else if (race.canFly()) { - force /= 2; + } else if (player.getPlayerSpecies().canFly()) { + force *= 2; } return force; } - private void ricochet(Entity projectile, BlockPos pos) { - Vec3d position = new Vec3d(projectile.posX, projectile.posY, projectile.posZ); + /** + * Reverses a projectiles direction to deflect it off the shield's surface. + */ + protected void ricochet(Entity projectile, Vec3d pos) { + Vec3d position = projectile.getPositionVector(); Vec3d motion = new Vec3d(projectile.motionX, projectile.motionY, projectile.motionZ); - Vec3d normal = position.subtract(pos.getX(), pos.getY(), pos.getZ()).normalize(); + Vec3d normal = position.subtract(pos).normalize(); Vec3d approach = motion.subtract(normal); if (approach.length() >= motion.length()) { - ProjectileUtil.setThrowableHeading(projectile, normal.x, normal.y, normal.z, (float)motion.length(), 0); + ProjectileUtil.setThrowableHeading(projectile, normal, (float)motion.length(), 0); } } diff --git a/src/main/java/com/minelittlepony/util/ProjectileUtil.java b/src/main/java/com/minelittlepony/util/ProjectileUtil.java index d04324f1..8288de7c 100644 --- a/src/main/java/com/minelittlepony/util/ProjectileUtil.java +++ b/src/main/java/com/minelittlepony/util/ProjectileUtil.java @@ -1,11 +1,14 @@ package com.minelittlepony.util; +import javax.annotation.Nullable; + import net.minecraft.entity.Entity; import net.minecraft.entity.IProjectile; import net.minecraft.entity.projectile.EntityArrow; import net.minecraft.entity.projectile.EntityFireball; import net.minecraft.entity.projectile.EntityLlamaSpit; import net.minecraft.entity.projectile.EntityThrowable; +import net.minecraft.util.math.Vec3d; public class ProjectileUtil { @@ -30,8 +33,8 @@ public class ProjectileUtil { * Checks if the given projectile was thrown by the given entity */ @SuppressWarnings("unchecked") - public static boolean isProjectileThrownBy(Entity throwable, T e) { - if (e == null || !isProjectile(throwable)) { + public static boolean isProjectileThrownBy(Entity throwable, @Nullable T e) { + if (e == null || !isThrowable(throwable)) { return false; } @@ -41,6 +44,7 @@ public class ProjectileUtil { /** * Gets the thrower for a projectile or null */ + @Nullable @SuppressWarnings("unchecked") public static T getThrowingEntity(Entity throwable) { @@ -63,22 +67,23 @@ public class ProjectileUtil { return null; } - /** - * Sets the velocity and heading for a projectile. - * - * @param throwable The projectile - * @param x X Direction component - * @param y Y Direction component - * @param z Z Direction component - * @param velocity Velocity - * @param inaccuracy Inaccuracy - * @return True the projectile's heading was set, false otherwise - */ - public static void setThrowableHeading(Entity throwable, double x, double y, double z, float velocity, float inaccuracy) { + /** + * Sets the velocity and heading for a projectile. + * + * @param throwable The projectile + * @param heading The directional heaving vector + * @param velocity Velocity + * @param inaccuracy Inaccuracy + * @return True the projectile's heading was set, false otherwise + */ + public static void setThrowableHeading(Entity throwable, Vec3d heading, float velocity, float inaccuracy) { + if (throwable instanceof IProjectile) { - ((IProjectile)throwable).shoot(x, y, z, velocity, inaccuracy); + ((IProjectile)throwable).shoot(heading.x, heading.y, heading.z, velocity, inaccuracy); } else { - ((Entity)throwable).setVelocity(x, y, z); + heading = heading.normalize().scale(velocity); + + throwable.addVelocity(heading.x - throwable.motionX, heading.y - throwable.motionY, heading.z - throwable.motionZ); } } }