mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-23 21:38:00 +01:00
Fixed various issues with shields
This commit is contained in:
parent
6e071b9113
commit
634ab607bf
4 changed files with 92 additions and 58 deletions
|
@ -42,6 +42,11 @@ public class Particles<Particle> {
|
|||
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);
|
||||
|
|
|
@ -46,6 +46,10 @@ public interface ICaster<E extends EntityLivingBase> extends IOwned<E>, ILevelle
|
|||
return getEntity().getPosition();
|
||||
}
|
||||
|
||||
default Vec3d getOriginVector() {
|
||||
return getEntity().getPositionVector();
|
||||
}
|
||||
|
||||
default void spawnParticles(IShape area, int count, Consumer<Vec3d> particleSpawner) {
|
||||
Random rand = getWorld().rand;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <T extends Entity> boolean isProjectileThrownBy(Entity throwable, T e) {
|
||||
if (e == null || !isProjectile(throwable)) {
|
||||
public static <T extends Entity> 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 extends Entity> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue