mirror of
https://github.com/PurpurMC/Purpur.git
synced 2026-02-22 10:57:43 +01:00
Upstream has released updates that appear to apply and compile correctly Paper Changes: 12dec20 Bump paerweight to 1.1.7 e33ed89 Get short commit ref using a more proper method 7d6147d Remove now unneeded patch due to paperweight 1.1.7 e72fa41 Update task dependency for includeMappings so the new task isn't skipped 0ad5526 Trim whitspace off of git hash (oops) Tuinity Changes: e878ba9 Update paper 2bd2849 Bring back fix codec spam patch
284 lines
12 KiB
Diff
284 lines
12 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
|
Date: Thu, 9 May 2019 18:26:06 -0500
|
|
Subject: [PATCH] Phantoms attracted to crystals and crystals shoot phantoms
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
|
|
index b643a2449e329560c936c0a06fb4cc494d0737a7..92e65f3fbc8f5d77bb8cc31e7a7780c2589f4227 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java
|
|
@@ -32,6 +32,12 @@ public class EndCrystal extends Entity {
|
|
private static final EntityDataAccessor<Boolean> DATA_SHOW_BOTTOM = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.BOOLEAN);
|
|
public int time;
|
|
public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals
|
|
+ // Purpur start
|
|
+ private net.minecraft.world.entity.monster.Phantom targetPhantom;
|
|
+ private int phantomBeamTicks = 0;
|
|
+ private int phantomDamageCooldown = 0;
|
|
+ private int idleCooldown = 0;
|
|
+ // Purpur end
|
|
|
|
public EndCrystal(EntityType<? extends EndCrystal> type, Level world) {
|
|
super(type, world);
|
|
@@ -81,7 +87,50 @@ public class EndCrystal extends Entity {
|
|
// Paper end
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ if (level.purpurConfig.phantomAttackedByCrystalRadius <= 0 || --idleCooldown > 0) {
|
|
+ return; // on cooldown
|
|
+ }
|
|
+
|
|
+ if (targetPhantom == null) {
|
|
+ for (net.minecraft.world.entity.monster.Phantom phantom : level.getEntitiesOfClass(net.minecraft.world.entity.monster.Phantom.class, getBoundingBox().inflate(level.purpurConfig.phantomAttackedByCrystalRadius))) {
|
|
+ if (phantom.hasLineOfSight(this)) {
|
|
+ attackPhantom(phantom);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ setBeamTarget(new BlockPos(targetPhantom).offset(0, -2, 0));
|
|
+ if (--phantomBeamTicks > 0 && targetPhantom.isAlive()) {
|
|
+ phantomDamageCooldown--;
|
|
+ if (targetPhantom.hasLineOfSight(this)) {
|
|
+ if (phantomDamageCooldown <= 0) {
|
|
+ phantomDamageCooldown = 20;
|
|
+ targetPhantom.hurt(DamageSource.indirectMagic(this, this), level.purpurConfig.phantomAttackedByCrystalDamage);
|
|
+ }
|
|
+ } else {
|
|
+ forgetPhantom(); // no longer in sight
|
|
+ }
|
|
+ } else {
|
|
+ forgetPhantom(); // attacked long enough
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void attackPhantom(net.minecraft.world.entity.monster.Phantom phantom) {
|
|
+ phantomDamageCooldown = 0;
|
|
+ phantomBeamTicks = 60;
|
|
+ targetPhantom = phantom;
|
|
+ }
|
|
+
|
|
+ private void forgetPhantom() {
|
|
+ targetPhantom = null;
|
|
+ setBeamTarget(null);
|
|
+ phantomBeamTicks = 0;
|
|
+ phantomDamageCooldown = 0;
|
|
+ idleCooldown = 60;
|
|
}
|
|
+ // Purpur end
|
|
|
|
@Override
|
|
protected void addAdditionalSaveData(CompoundTag nbt) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
|
index 5e069ac0c57d2a3a23f6e4483d12ce298d172691..916c29d08fbcf245ad6f50f8e8cc173677b01081 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java
|
|
@@ -50,6 +50,7 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
Vec3 moveTargetPoint;
|
|
BlockPos anchorPoint;
|
|
Phantom.AttackPhase attackPhase;
|
|
+ Vec3 crystalPosition; // Purpur
|
|
|
|
public Phantom(EntityType<? extends Phantom> type, Level world) {
|
|
super(type, world);
|
|
@@ -117,6 +118,24 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
public void initAttributes() {
|
|
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level.purpurConfig.phantomMaxHealth);
|
|
}
|
|
+
|
|
+ @Override
|
|
+ protected net.minecraft.world.level.storage.loot.LootContext.Builder createLootContext(boolean causedByPlayer, DamageSource source) {
|
|
+ boolean dropped = false;
|
|
+ if (lastHurtByPlayer == null && source.getEntity() instanceof net.minecraft.world.entity.boss.enderdragon.EndCrystal) {
|
|
+ if (random.nextInt(5) < 1) {
|
|
+ dropped = spawnAtLocation(new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.PHANTOM_MEMBRANE)) != null;
|
|
+ }
|
|
+ }
|
|
+ if (!dropped) {
|
|
+ return super.createLootContext(causedByPlayer, source);
|
|
+ }
|
|
+ return new net.minecraft.world.level.storage.loot.LootContext.Builder((net.minecraft.server.level.ServerLevel) level);
|
|
+ }
|
|
+
|
|
+ public boolean isCirclingCrystal() {
|
|
+ return crystalPosition != null;
|
|
+ }
|
|
// Purpur end
|
|
|
|
@Override
|
|
@@ -131,11 +150,17 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
|
|
@Override
|
|
protected void registerGoals() {
|
|
- this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur
|
|
- this.goalSelector.addGoal(1, new Phantom.PhantomAttackStrategyGoal());
|
|
- this.goalSelector.addGoal(2, new Phantom.PhantomSweepAttackGoal());
|
|
- this.goalSelector.addGoal(3, new Phantom.PhantomCircleAroundAnchorGoal());
|
|
- this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur
|
|
+ // Purpur start
|
|
+ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this));
|
|
+ if (level.purpurConfig.phantomOrbitCrystalRadius > 0) {
|
|
+ this.goalSelector.addGoal(1, new FindCrystalGoal(this));
|
|
+ this.goalSelector.addGoal(2, new OrbitCrystalGoal(this));
|
|
+ }
|
|
+ this.goalSelector.addGoal(3, new Phantom.PhantomAttackStrategyGoal());
|
|
+ this.goalSelector.addGoal(4, new Phantom.PhantomSweepAttackGoal());
|
|
+ this.goalSelector.addGoal(5, new Phantom.PhantomCircleAroundAnchorGoal());
|
|
+ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this));
|
|
+ // Purpur end
|
|
this.targetSelector.addGoal(1, new Phantom.PhantomAttackPlayerTargetGoal());
|
|
}
|
|
|
|
@@ -325,6 +350,124 @@ public class Phantom extends FlyingMob implements Enemy {
|
|
private AttackPhase() {}
|
|
}
|
|
|
|
+ // Purpur start
|
|
+ class FindCrystalGoal extends Goal {
|
|
+ private final Phantom phantom;
|
|
+ private net.minecraft.world.entity.boss.enderdragon.EndCrystal crystal;
|
|
+ private Comparator<net.minecraft.world.entity.boss.enderdragon.EndCrystal> comparator;
|
|
+
|
|
+ FindCrystalGoal(Phantom phantom) {
|
|
+ this.phantom = phantom;
|
|
+ this.comparator = Comparator.comparingDouble(phantom::distanceToSqr);
|
|
+ this.setFlags(EnumSet.of(Flag.LOOK));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canUse() {
|
|
+ double range = maxTargetRange();
|
|
+ List<net.minecraft.world.entity.boss.enderdragon.EndCrystal> crystals = level.getEntitiesOfClass(net.minecraft.world.entity.boss.enderdragon.EndCrystal.class, phantom.getBoundingBox().inflate(range));
|
|
+ if (crystals.isEmpty()) {
|
|
+ return false;
|
|
+ }
|
|
+ crystals.sort(comparator);
|
|
+ crystal = crystals.get(0);
|
|
+ if (phantom.distanceToSqr(crystal) > range * range) {
|
|
+ crystal = null;
|
|
+ return false;
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canContinueToUse() {
|
|
+ if (crystal == null || !crystal.isAlive()) {
|
|
+ return false;
|
|
+ }
|
|
+ double range = maxTargetRange();
|
|
+ return phantom.distanceToSqr(crystal) <= (range * range) * 2;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void start() {
|
|
+ phantom.crystalPosition = new Vec3(crystal.getX(), crystal.getY() + (phantom.random.nextInt(10) + 10), crystal.getZ());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void stop() {
|
|
+ crystal = null;
|
|
+ phantom.crystalPosition = null;
|
|
+ super.stop();
|
|
+ }
|
|
+
|
|
+ private double maxTargetRange() {
|
|
+ return phantom.level.purpurConfig.phantomOrbitCrystalRadius;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ class OrbitCrystalGoal extends Goal {
|
|
+ private final Phantom phantom;
|
|
+ private float offset;
|
|
+ private float radius;
|
|
+ private float verticalChange;
|
|
+ private float direction;
|
|
+
|
|
+ OrbitCrystalGoal(Phantom phantom) {
|
|
+ this.phantom = phantom;
|
|
+ this.setFlags(EnumSet.of(Flag.MOVE));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean canUse() {
|
|
+ return phantom.isCirclingCrystal();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void start() {
|
|
+ this.radius = 5.0F + phantom.random.nextFloat() * 10.0F;
|
|
+ this.verticalChange = -4.0F + phantom.random.nextFloat() * 9.0F;
|
|
+ this.direction = phantom.random.nextBoolean() ? 1.0F : -1.0F;
|
|
+ updateOffset();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void tick() {
|
|
+ if (phantom.random.nextInt(350) == 0) {
|
|
+ this.verticalChange = -4.0F + phantom.random.nextFloat() * 9.0F;
|
|
+ }
|
|
+ if (phantom.random.nextInt(250) == 0) {
|
|
+ ++this.radius;
|
|
+ if (this.radius > 15.0F) {
|
|
+ this.radius = 5.0F;
|
|
+ this.direction = -this.direction;
|
|
+ }
|
|
+ }
|
|
+ if (phantom.random.nextInt(450) == 0) {
|
|
+ this.offset = phantom.random.nextFloat() * 2.0F * 3.1415927F;
|
|
+ updateOffset();
|
|
+ }
|
|
+ if (phantom.moveTargetPoint.distanceToSqr(phantom.getX(), phantom.getY(), phantom.getZ()) < 4.0D) {
|
|
+ updateOffset();
|
|
+ }
|
|
+ if (phantom.moveTargetPoint.y < phantom.getY() && !phantom.level.isEmptyBlock(new BlockPos(phantom).below(1))) {
|
|
+ this.verticalChange = Math.max(1.0F, this.verticalChange);
|
|
+ updateOffset();
|
|
+ }
|
|
+ if (phantom.moveTargetPoint.y > phantom.getY() && !phantom.level.isEmptyBlock(new BlockPos(phantom).above(1))) {
|
|
+ this.verticalChange = Math.min(-1.0F, this.verticalChange);
|
|
+ updateOffset();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void updateOffset() {
|
|
+ this.offset += this.direction * 15.0F * 0.017453292F;
|
|
+ phantom.moveTargetPoint = phantom.crystalPosition.add(
|
|
+ this.radius * Mth.cos(this.offset),
|
|
+ -4.0F + this.verticalChange,
|
|
+ this.radius * Mth.sin(this.offset));
|
|
+ }
|
|
+ }
|
|
+ // Purpur end
|
|
+
|
|
private class PhantomMoveControl extends net.pl3x.purpur.controller.FlyingMoveControllerWASD { // Purpur
|
|
|
|
private float speed = 0.1F;
|
|
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
|
|
index c4a6af80a2093a261935caac40b702bb827e998a..e3bd27513287ba77efd3f2c2418b83b7646ea5e2 100644
|
|
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
|
|
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
|
|
@@ -919,6 +919,9 @@ public class PurpurWorldConfig {
|
|
public int phantomFlameFireTime = 8;
|
|
public boolean phantomAllowGriefing = false;
|
|
public double phantomMaxHealth = 20.0D;
|
|
+ public double phantomAttackedByCrystalRadius = 0.0D;
|
|
+ public float phantomAttackedByCrystalDamage = 1.0F;
|
|
+ public double phantomOrbitCrystalRadius = 0.0D;
|
|
private void phantomSettings() {
|
|
phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable);
|
|
phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater);
|
|
@@ -932,6 +935,9 @@ public class PurpurWorldConfig {
|
|
set("mobs.phantom.attributes.max_health", oldValue);
|
|
}
|
|
phantomMaxHealth = getDouble("mobs.phantom.attributes.max_health", phantomMaxHealth);
|
|
+ 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);
|
|
}
|
|
|
|
public boolean pigRidable = false;
|