From c9670a3d3c98359b56bb3936a353594a5ade862c Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 3 Mar 2021 20:04:40 +0200 Subject: [PATCH] Polish up the siphoning and necro spells --- .../unicopia/ability/magic/Caster.java | 11 +- .../magic/spell/AbstractPlacedSpell.java | 93 ++++++++++++ .../ability/magic/spell/AttractiveSpell.java | 6 +- .../ability/magic/spell/NecromancySpell.java | 27 ++-- .../ability/magic/spell/SiphoningSpell.java | 135 +++++++++++------- .../unicopia/util/NbtSerialisable.java | 26 ++-- 6 files changed, 208 insertions(+), 90 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractPlacedSpell.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java index d7aac342..7d92f682 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java @@ -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 extends Owned, Levelled, Affi } default Stream findAllEntitiesInRange(double radius, @Nullable Predicate test) { - return VecHelper.findInRange(getEntity(), getWorld(), getOriginVector(), radius, test).stream(); + return findAllEntitiesInRange(getOriginVector(), radius, test); + } + + default Stream findAllEntitiesInRange(Vec3d origin, double radius, @Nullable Predicate test) { + return VecHelper.findInRange(getEntity(), getWorld(), origin, radius, test).stream(); + } + + default Stream findAllEntitiesInRange(Vec3d origin, double radius) { + return findAllEntitiesInRange(origin, radius, null); } default Stream findAllEntitiesInRange(double radius) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractPlacedSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractPlacedSpell.java new file mode 100644 index 00000000..68ce05fc --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractPlacedSpell.java @@ -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")); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AttractiveSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AttractiveSpell.java index 86b3989d..5d314813 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AttractiveSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AttractiveSpell.java @@ -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")); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/NecromancySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/NecromancySpell.java index 85bef602..3648b190 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/NecromancySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/NecromancySpell.java @@ -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> 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); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SiphoningSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SiphoningSpell.java index 55c9b920..34cd6504 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SiphoningSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SiphoningSpell.java @@ -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,66 +48,90 @@ public class SiphoningSpell extends AbstractSpell implements Attached { }); } - LivingEntity owner = source.getMaster(); + if (source.getWorld().getTime() % 10 != 0) { + return true; + } - List 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 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 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(); + float healthGain = 0; - if (maxHealthGain > 0) { - float attackAmount = Math.max(maxHealthGain / target.size(), 0.5F); + for (LivingEntity e : targets) { + if (!e.equals(owner)) { + float dealt = Math.min(e.getHealth(), attackAmount); - for (LivingEntity e : target) { - if (!e.equals(owner)) { - float dealt = Math.min(e.getHealth(), attackAmount); + if (e instanceof PlayerEntity) { + Pony player = Pony.of((PlayerEntity)e); - if (e instanceof PlayerEntity) { - Pony player = Pony.of((PlayerEntity)e); + Race race = player.getSpecies(); - Race race = player.getSpecies(); - - if (race.canCast()) { - dealt /= 2; - } - if (race.canUseEarth()) { - dealt *= 2; - } - } - - e.damage(damage, dealt); - - healthGain += dealt; - } + if (race.canCast()) { + dealt /= 2; + } + if (race.canUseEarth()) { + dealt *= 2; } } - owner.heal(healthGain); + e.damage(damage, dealt); + ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, owner, 0.2F), e, 1); + + healthGain += dealt; } - - } 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; + owner.heal(healthGain); } } diff --git a/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java b/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java index 7dc746db..cbe4b6a6 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java +++ b/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java @@ -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)); } }