mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Polish up the siphoning and necro spells
This commit is contained in:
parent
3bb4d36a7e
commit
c9670a3d3c
6 changed files with 208 additions and 90 deletions
|
@ -18,6 +18,7 @@ import net.minecraft.entity.Entity;
|
|||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
|
@ -77,7 +78,15 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
|
|||
}
|
||||
|
||||
default Stream<Entity> findAllEntitiesInRange(double radius, @Nullable Predicate<Entity> test) {
|
||||
return VecHelper.findInRange(getEntity(), getWorld(), getOriginVector(), radius, test).stream();
|
||||
return findAllEntitiesInRange(getOriginVector(), radius, test);
|
||||
}
|
||||
|
||||
default Stream<Entity> findAllEntitiesInRange(Vec3d origin, double radius, @Nullable Predicate<Entity> test) {
|
||||
return VecHelper.findInRange(getEntity(), getWorld(), origin, radius, test).stream();
|
||||
}
|
||||
|
||||
default Stream<Entity> findAllEntitiesInRange(Vec3d origin, double radius) {
|
||||
return findAllEntitiesInRange(origin, radius, null);
|
||||
}
|
||||
|
||||
default Stream<Entity> findAllEntitiesInRange(double radius) {
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.ability.magic.Attached;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.ParticleHandle;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtHelper;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public abstract class AbstractPlacedSpell extends AbstractSpell implements Attached {
|
||||
|
||||
@Nullable
|
||||
protected Vec3d origin;
|
||||
@Nullable
|
||||
protected BlockPos placement;
|
||||
@Nullable
|
||||
private Identifier dimension;
|
||||
|
||||
private final ParticleHandle particlEffect = new ParticleHandle();
|
||||
|
||||
protected AbstractPlacedSpell(SpellType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDead() {
|
||||
super.setDead();
|
||||
particlEffect.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBodyTick(Caster<?> source) {
|
||||
|
||||
if (origin == null) {
|
||||
origin = source.getOriginVector();
|
||||
placement = source.getOrigin();
|
||||
dimension = source.getWorld().getRegistryKey().getValue();
|
||||
}
|
||||
|
||||
if (!source.getWorld().getRegistryKey().getValue().equals(dimension)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (source.isClient()) {
|
||||
particlEffect.ifAbsent(source, spawner -> {
|
||||
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), origin, Vec3d.ZERO);
|
||||
}).ifPresent(p -> {
|
||||
p.attach(source);
|
||||
p.setAttribute(1, getType().getColor());
|
||||
});
|
||||
}
|
||||
|
||||
return onGroundTick(source);
|
||||
}
|
||||
|
||||
protected abstract boolean onGroundTick(Caster<?> source);
|
||||
|
||||
@Override
|
||||
public void toNBT(CompoundTag compound) {
|
||||
super.toNBT(compound);
|
||||
if (placement != null) {
|
||||
compound.put("placement", NbtHelper.fromBlockPos(placement));
|
||||
}
|
||||
if (origin != null) {
|
||||
compound.put("origin", NbtSerialisable.writeVector(origin));
|
||||
}
|
||||
if (dimension != null) {
|
||||
compound.putString("dimension", dimension.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromNBT(CompoundTag compound) {
|
||||
super.fromNBT(compound);
|
||||
if (compound.contains("placement")) {
|
||||
placement = NbtHelper.toBlockPos(compound.getCompound("placement"));
|
||||
}
|
||||
if (compound.contains("origin")) {
|
||||
origin = NbtSerialisable.readVector(compound.getList("origin", 6));
|
||||
}
|
||||
if (compound.contains("dimension")) {
|
||||
dimension = new Identifier(compound.getString("dimension"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ import com.minelittlepony.unicopia.ability.magic.Thrown;
|
|||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
import com.minelittlepony.unicopia.util.VecHelper;
|
||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||
|
||||
|
@ -16,6 +15,7 @@ import net.minecraft.entity.Entity;
|
|||
import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtHelper;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
@ -91,7 +91,7 @@ public class AttractiveSpell extends ShieldSpell implements Thrown {
|
|||
public void toNBT(CompoundTag compound) {
|
||||
super.toNBT(compound);
|
||||
if (homingPos != null) {
|
||||
compound.put("homingPos", NbtSerialisable.writeBlockPos(homingPos));
|
||||
compound.put("homingPos", NbtHelper.fromBlockPos(homingPos));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ public class AttractiveSpell extends ShieldSpell implements Thrown {
|
|||
public void fromNBT(CompoundTag compound) {
|
||||
super.fromNBT(compound);
|
||||
if (compound.contains("homingPos")) {
|
||||
homingPos = NbtSerialisable.readBlockPos(compound.getCompound("homingPos"));
|
||||
homingPos = NbtHelper.toBlockPos(compound.getCompound("homingPos"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.ability.magic.spell;
|
|||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.minelittlepony.unicopia.ability.magic.Attached;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.util.WorldEvent;
|
||||
import com.minelittlepony.unicopia.util.shape.Shape;
|
||||
|
@ -18,7 +17,7 @@ import net.minecraft.util.math.MathHelper;
|
|||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.Difficulty;
|
||||
|
||||
public class NecromancySpell extends AbstractSpell implements Attached {
|
||||
public class NecromancySpell extends AbstractPlacedSpell {
|
||||
|
||||
private final List<EntityType<? extends LivingEntity>> spawns = Lists.newArrayList(
|
||||
EntityType.ZOMBIE,
|
||||
|
@ -31,19 +30,16 @@ public class NecromancySpell extends AbstractSpell implements Attached {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean onBodyTick(Caster<?> source) {
|
||||
public boolean onGroundTick(Caster<?> source) {
|
||||
|
||||
int radius = source.getLevel().get() + 1;
|
||||
int radius = (source.getLevel().get() + 1) * 4;
|
||||
|
||||
if (source.isClient()) {
|
||||
Shape affectRegion = new Sphere(false, radius * 4);
|
||||
|
||||
source.spawnParticles(affectRegion, 5, pos -> {
|
||||
source.spawnParticles(origin, new Sphere(false, radius), 5, pos -> {
|
||||
if (!source.getWorld().isAir(new BlockPos(pos).down())) {
|
||||
source.addParticle(ParticleTypes.FLAME, pos, Vec3d.ZERO);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -51,18 +47,16 @@ public class NecromancySpell extends AbstractSpell implements Attached {
|
|||
return true;
|
||||
}
|
||||
|
||||
float additional = source.getWorld().getLocalDifficulty(source.getOrigin()).getLocalDifficulty();
|
||||
float additional = source.getWorld().getLocalDifficulty(placement).getLocalDifficulty();
|
||||
|
||||
Shape affectRegion = new Sphere(false, radius * 4);
|
||||
Shape affectRegion = new Sphere(false, radius);
|
||||
|
||||
if (source.getWorld().random.nextInt(100) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Vec3d origin = source.getOriginVector();
|
||||
|
||||
if (source.findAllEntitiesInRange(radius * 4, e -> e instanceof ZombieEntity).count() >= 10 * (1 + additional)) {
|
||||
return true;
|
||||
if (source.findAllEntitiesInRange(radius, e -> e instanceof ZombieEntity).count() >= 10 * (1 + additional)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
|
@ -72,12 +66,9 @@ public class NecromancySpell extends AbstractSpell implements Attached {
|
|||
|
||||
if (source.getWorld().isAir(loc.up()) && !source.getWorld().isAir(loc)) {
|
||||
spawnMonster(source, pos);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -85,6 +76,8 @@ public class NecromancySpell extends AbstractSpell implements Attached {
|
|||
int index = (int)MathHelper.nextDouble(source.getWorld().random, 0, spawns.size());
|
||||
LivingEntity zombie = spawns.get(index).create(source.getWorld());
|
||||
|
||||
source.subtractEnergyCost(3);
|
||||
|
||||
zombie.updatePositionAndAngles(pos.x, pos.y, pos.z, 0, 0);
|
||||
zombie.setVelocity(0, 0.3, 0);
|
||||
|
||||
|
|
|
@ -2,12 +2,16 @@ package com.minelittlepony.unicopia.ability.magic.spell;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.minelittlepony.unicopia.Race;
|
||||
import com.minelittlepony.unicopia.ability.magic.Attached;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
||||
import com.minelittlepony.unicopia.util.VecHelper;
|
||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
|
@ -20,21 +24,20 @@ import net.minecraft.util.math.Vec3d;
|
|||
/**
|
||||
* A spell that pulls health from other entities and delivers it to the caster.
|
||||
*/
|
||||
public class SiphoningSpell extends AbstractSpell implements Attached {
|
||||
public class SiphoningSpell extends AbstractPlacedSpell {
|
||||
|
||||
protected SiphoningSpell(SpellType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBodyTick(Caster<?> source) {
|
||||
int radius = 4 + source.getLevel().get();
|
||||
public boolean onGroundTick(Caster<?> source) {
|
||||
|
||||
if (source.isClient()) {
|
||||
Vec3d origin = source.getOriginVector();
|
||||
int direction = !isEnemy(source) ? 1 : -1;
|
||||
int radius = 4 + source.getLevel().get();
|
||||
int direction = isFriendlyTogether(source) ? 1 : -1;
|
||||
|
||||
source.spawnParticles(new Sphere(true, radius, 1, 0, 1), 1, pos -> {
|
||||
source.spawnParticles(origin, new Sphere(true, radius, 1, 0, 1), 1, pos -> {
|
||||
if (!source.getWorld().isAir(new BlockPos(pos).down())) {
|
||||
|
||||
double dist = pos.distanceTo(origin);
|
||||
|
@ -45,24 +48,67 @@ public class SiphoningSpell extends AbstractSpell implements Attached {
|
|||
});
|
||||
}
|
||||
|
||||
LivingEntity owner = source.getMaster();
|
||||
if (source.getWorld().getTime() % 10 != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<LivingEntity> target = source.findAllEntitiesInRange(radius)
|
||||
.filter(e -> e instanceof LivingEntity)
|
||||
.map(e -> (LivingEntity)e)
|
||||
.collect(Collectors.toList());
|
||||
if (isFriendlyTogether(source)) {
|
||||
distributeHealth(source);
|
||||
} else {
|
||||
collectHealth(source);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Stream<LivingEntity> getTargets(Caster<?> source) {
|
||||
return VecHelper.findInRange(null, source.getWorld(), origin, 4 + source.getLevel().get(), e -> e instanceof LivingEntity)
|
||||
.stream()
|
||||
.map(e -> (LivingEntity)e);
|
||||
}
|
||||
|
||||
private void distributeHealth(Caster<?> source) {
|
||||
LivingEntity owner = source.getMaster();
|
||||
DamageSource damage = MagicalDamageSource.create("drain", owner);
|
||||
|
||||
getTargets(source).forEach(e -> {
|
||||
float maxHealthGain = e.getMaxHealth() - e.getHealth();
|
||||
|
||||
source.subtractEnergyCost(0.2F);
|
||||
|
||||
if (maxHealthGain <= 0) {
|
||||
if (source.getWorld().random.nextInt(30) == 0) {
|
||||
onDestroyed(source);
|
||||
} else {
|
||||
e.damage(damage, e.getHealth() / 4);
|
||||
}
|
||||
} else {
|
||||
e.heal((float)Math.min(0.5F * (1 + source.getLevel().get()), maxHealthGain * 0.6));
|
||||
ParticleUtils.spawnParticle(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, e, 0.2F), e.world, e.getPos(), Vec3d.ZERO);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void collectHealth(Caster<?> source) {
|
||||
LivingEntity owner = source.getMaster();
|
||||
float maxHealthGain = owner.getMaxHealth() - owner.getHealth();
|
||||
|
||||
if (maxHealthGain == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<LivingEntity> targets = getTargets(source).collect(Collectors.toList());
|
||||
if (targets.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
float attackAmount = Math.max(maxHealthGain / targets.size(), 0.5F);
|
||||
|
||||
DamageSource damage = MagicalDamageSource.create("drain", owner);
|
||||
|
||||
if (!isFriendlyTogether(source)) {
|
||||
if (owner != null) {
|
||||
float healthGain = 0;
|
||||
float maxHealthGain = owner.getMaxHealth() - owner.getHealth();
|
||||
|
||||
if (maxHealthGain > 0) {
|
||||
float attackAmount = Math.max(maxHealthGain / target.size(), 0.5F);
|
||||
|
||||
for (LivingEntity e : target) {
|
||||
for (LivingEntity e : targets) {
|
||||
if (!e.equals(owner)) {
|
||||
float dealt = Math.min(e.getHealth(), attackAmount);
|
||||
|
||||
|
@ -80,31 +126,12 @@ public class SiphoningSpell extends AbstractSpell implements Attached {
|
|||
}
|
||||
|
||||
e.damage(damage, dealt);
|
||||
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, owner, 0.2F), e, 1);
|
||||
|
||||
healthGain += dealt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
owner.heal(healthGain);
|
||||
}
|
||||
|
||||
} else {
|
||||
target.forEach(e -> {
|
||||
float maxHealthGain = e.getMaxHealth() - e.getHealth();
|
||||
|
||||
if (maxHealthGain <= 0) {
|
||||
if (source.getWorld().random.nextInt(30) == 0) {
|
||||
onDestroyed(source);
|
||||
} else {
|
||||
e.damage(damage, e.getHealth() / 4);
|
||||
}
|
||||
} else {
|
||||
e.heal((float)Math.min(0.5F * (1 + source.getLevel().get()), maxHealthGain * 0.6));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package com.minelittlepony.unicopia.util;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.nbt.DoubleTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public interface NbtSerialisable {
|
||||
/**
|
||||
|
@ -28,21 +30,15 @@ public interface NbtSerialisable {
|
|||
return compound;
|
||||
}
|
||||
|
||||
static CompoundTag writeBlockPos(BlockPos pos) {
|
||||
CompoundTag dest = new CompoundTag();
|
||||
|
||||
dest.putInt("X", pos.getX());
|
||||
dest.putInt("Y", pos.getY());
|
||||
dest.putInt("Z", pos.getZ());
|
||||
|
||||
return dest;
|
||||
static ListTag writeVector(Vec3d vector) {
|
||||
ListTag list = new ListTag();
|
||||
list.add(DoubleTag.of(vector.getX()));
|
||||
list.add(DoubleTag.of(vector.getY()));
|
||||
list.add(DoubleTag.of(vector.getZ()));
|
||||
return list;
|
||||
}
|
||||
|
||||
static BlockPos readBlockPos(CompoundTag compound) {
|
||||
return new BlockPos(
|
||||
compound.getInt("X"),
|
||||
compound.getInt("Y"),
|
||||
compound.getInt("Z")
|
||||
);
|
||||
static Vec3d readVector(ListTag list) {
|
||||
return new Vec3d(list.getDouble(0), list.getDouble(1), list.getDouble(2));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue