From 7858a4f9cd8e54bccf1cec49dcabaa0b5860b798 Mon Sep 17 00:00:00 2001 From: William Blake Galbreath Date: Sat, 4 Apr 2020 00:08:16 -0500 Subject: [PATCH] Add phantom flames --- docs/source/configuration.rst | 7 ++ patches/server/0123-test.patch | 210 +++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 patches/server/0123-test.patch diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst index eba17b240..53694f60f 100644 --- a/docs/source/configuration.rst +++ b/docs/source/configuration.rst @@ -997,6 +997,13 @@ mobs * orbit-crystal-radius - **default**: 0.0 - **description**: Radius which phantoms scan for crystals to orbit. Value of 0 disables feature + * flames + * damage + - **default**: 1.0 + - **description**: The amount of direct damage from phantom flames + * fire-time + - **default**: 8 + - **description**: Number of seconds an entity is set on fire when hit by flames * pig * ridable diff --git a/patches/server/0123-test.patch b/patches/server/0123-test.patch new file mode 100644 index 000000000..d4982c3ca --- /dev/null +++ b/patches/server/0123-test.patch @@ -0,0 +1,210 @@ +From 135cc7eb7d220a35aa51f1c8007d482c941fa12c Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 3 Apr 2020 23:13:23 -0500 +Subject: [PATCH] test + +--- + .../net/minecraft/server/EntityPhantom.java | 22 ++- + .../net/pl3x/purpur/PurpurWorldConfig.java | 4 + + .../net/pl3x/purpur/entity/PhantomFlames.java | 126 ++++++++++++++++++ + 3 files changed, 150 insertions(+), 2 deletions(-) + create mode 100644 src/main/java/net/pl3x/purpur/entity/PhantomFlames.java + +diff --git a/src/main/java/net/minecraft/server/EntityPhantom.java b/src/main/java/net/minecraft/server/EntityPhantom.java +index 580c48b34e..77b69cd362 100644 +--- a/src/main/java/net/minecraft/server/EntityPhantom.java ++++ b/src/main/java/net/minecraft/server/EntityPhantom.java +@@ -84,9 +84,8 @@ public class EntityPhantom extends EntityFlying implements IMonster { + this.getAttributeMap().b(GenericAttributes.ATTACK_DAMAGE); + // Purpur start + if (world != null && world.purpurConfig.phantomRidable) { +- this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(0.01D); + this.getAttributeMap().b(GenericAttributes.FLYING_SPEED); +- this.getAttributeInstance(GenericAttributes.FLYING_SPEED).setValue(0.6000000238418579D); ++ this.getAttributeInstance(GenericAttributes.FLYING_SPEED).setValue(3.0D); + } + // Purpur end + } +@@ -183,6 +182,25 @@ public class EntityPhantom extends EntityFlying implements IMonster { + public boolean isCirclingCrystal() { + return crystalPosition != null; + } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (hasRider() && getRider().getBukkitEntity().hasPermission("allow.special.phantom")) { ++ shoot(); ++ } ++ return false; ++ } ++ ++ public boolean shoot() { ++ org.bukkit.Location loc = ((org.bukkit.entity.LivingEntity) getBukkitEntity()).getEyeLocation(); ++ loc.setPitch(-loc.getPitch()); ++ org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(100).add(loc.toVector()); ++ ++ net.pl3x.purpur.entity.PhantomFlames flames = new net.pl3x.purpur.entity.PhantomFlames(world, this); ++ flames.shoot(target.getX() - locX(), target.getY() - locY(), target.getZ() - locZ(), 1.0F, 5.0F); ++ world.addEntity(flames); ++ return true; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 6446ee7d79..6123abaed6 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -682,6 +682,8 @@ public class PurpurWorldConfig { + public double phantomAttackedByCrystalRadius = 0.0D; + public float phantomAttackedByCrystalDamage = 1.0F; + public double phantomOrbitCrystalRadius = 0.0D; ++ public float phantomFlameDamage = 1.0F; ++ public int phantomFlameFireTime = 8; + private void phantomSettings() { + phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); + phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); +@@ -692,6 +694,8 @@ public class PurpurWorldConfig { + phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius); + phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage); + phantomOrbitCrystalRadius = getDouble("mobs.phantom.orbit-crystal-radius", phantomOrbitCrystalRadius); ++ phantomFlameDamage = (float) getDouble("mobs.phantom.flames.damage", phantomFlameDamage); ++ phantomFlameFireTime = getInt("mobs.phantom.flames.fire-time", phantomFlameFireTime); + } + + public boolean pigRidable = false; +diff --git a/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java b/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java +new file mode 100644 +index 0000000000..f9e680efd2 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java +@@ -0,0 +1,126 @@ ++package net.pl3x.purpur.entity; ++ ++import net.minecraft.server.DamageSource; ++import net.minecraft.server.Entity; ++import net.minecraft.server.EntityLiving; ++import net.minecraft.server.EntityLlamaSpit; ++import net.minecraft.server.EntityPhantom; ++import net.minecraft.server.EntityTypes; ++import net.minecraft.server.IProjectile; ++import net.minecraft.server.Material; ++import net.minecraft.server.MathHelper; ++import net.minecraft.server.MovingObjectPosition; ++import net.minecraft.server.MovingObjectPositionEntity; ++import net.minecraft.server.NBTTagCompound; ++import net.minecraft.server.Packet; ++import net.minecraft.server.PacketPlayOutSpawnEntity; ++import net.minecraft.server.Particles; ++import net.minecraft.server.ProjectileHelper; ++import net.minecraft.server.RayTrace; ++import net.minecraft.server.Vec3D; ++import net.minecraft.server.World; ++import net.minecraft.server.WorldServer; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++ ++public class PhantomFlames extends EntityLlamaSpit implements IProjectile { ++ public EntityLiving phantom; ++ public int ticksLived; ++ ++ public PhantomFlames(EntityTypes entitytypes, World world) { ++ super(entitytypes, world); ++ } ++ ++ public PhantomFlames(World world, EntityPhantom phantom) { ++ this(EntityTypes.LLAMA_SPIT, world); ++ this.phantom = phantom; ++ ++ setPosition(phantom.locX() - (double) (phantom.getWidth() + 1.0F) * 0.5D * (double) MathHelper.sin(phantom.getBodyRotation() * ((float) Math.PI / 180F)), phantom.getHeadY() - (double) 0.1F, phantom.locZ() + (double) (phantom.getWidth() + 1.0F) * 0.5D * (double) MathHelper.cos(phantom.getBodyRotation() * ((float) Math.PI / 180F))); ++ } ++ ++ @Override ++ public boolean canSaveToDisk() { ++ return false; ++ } ++ ++ @Override ++ public void tick() { ++ setFlag(6, isGlowing()); ++ entityBaseTick(); ++ ++ Vec3D mot = getMot(); ++ ++ MovingObjectPosition hitResult = ProjectileHelper.getHitResult(this, getBoundingBox().expandTowards(mot).expand(1.0D), (entity) -> !entity.isSpectator() && entity != phantom && entity != phantom.getRider(), RayTrace.BlockCollisionOption.OUTLINE, true); ++ if (hitResult != null) { ++ onHit(hitResult); ++ } ++ ++ mot = mot.scale(0.99F); ++ setMot(mot); ++ setPosition(locX() + mot.x, locY() + mot.y, locZ() + mot.z); ++ ++ Vec3D m = mot.scale(2.0); ++ for (int i = 0; i < 5; i++) { ++ ((WorldServer) world).sendParticles(null, Particles.FLAME, ++ locX() + random.nextFloat() / 2 - 0.25F, ++ locY() + random.nextFloat() / 2 - 0.25F, ++ locZ() + random.nextFloat() / 2 - 0.25F, ++ 0, m.getX(), m.getY(), m.getZ(), 0.1, true); ++ } ++ ++ if (!world.containsMaterial(getBoundingBox(), Material.AIR)) { ++ die(); ++ } ++ if (++ticksLived > 20) { ++ die(); ++ } ++ } ++ ++ @Override ++ public void shoot(double x, double y, double z, float speed, float inaccuracy) { ++ setMot(new Vec3D(x, y, z).normalize().add( ++ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, ++ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, ++ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy) ++ .scale(speed)); ++ } ++ ++ public void onHit(MovingObjectPosition rayTrace) { ++ CraftEventFactory.callProjectileHitEvent(this, rayTrace); ++ ++ switch (rayTrace.getType()) { ++ case BLOCK: ++ die(); ++ break; ++ case ENTITY: ++ if (phantom != null) { ++ Entity entity = ((MovingObjectPositionEntity) rayTrace).getEntity(); ++ entity.damageEntity(DamageSource.indirectMobAttack(this, phantom).setProjectile(), world.purpurConfig.phantomFlameDamage); ++ if (world.purpurConfig.phantomFlameFireTime > 0) { ++ entity.setOnFire(world.purpurConfig.phantomFlameFireTime); ++ } ++ } ++ die(); ++ } ++ } ++ ++ @Override ++ public void a(MovingObjectPosition movingobjectposition) { ++ } ++ ++ @Override ++ protected void initDatawatcher() { ++ } ++ ++ @Override ++ protected void a(NBTTagCompound nbttagcompound) { ++ } ++ ++ @Override ++ protected void b(NBTTagCompound nbttagcompound) { ++ } ++ ++ @Override ++ public Packet L() { ++ return new PacketPlayOutSpawnEntity(this); ++ } ++} +-- +2.24.0 +