Polish up the siphoning and necro spells

This commit is contained in:
Sollace 2021-03-03 20:04:40 +02:00
parent 3bb4d36a7e
commit c9670a3d3c
6 changed files with 208 additions and 90 deletions

View file

@ -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) {

View file

@ -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"));
}
}
}

View file

@ -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"));
}
}

View file

@ -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);

View file

@ -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<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();
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);
}
}

View file

@ -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));
}
}