From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Encode42 <me@encode42.dev>
Date: Tue, 8 Dec 2020 17:15:15 -0500
Subject: [PATCH] Configurable chance for wolves to spawn rabid

Configurable chance to spawn a wolf that is rabid.
Rabid wolves attack all players, mobs, and animals.

diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java
index af2b6bb559d78dd912eee02281f5446f31e55eae..79fde7b4763642dc4941899ab186db9dfab3b574 100644
--- a/src/main/java/net/minecraft/server/EntityLiving.java
+++ b/src/main/java/net/minecraft/server/EntityLiving.java
@@ -2102,6 +2102,7 @@ public abstract class EntityLiving extends Entity {
         }
     }
 
+    public final void setItemInHand(EnumHand enumHand, ItemStack itemStack) { this.a(enumHand, itemStack); } // Purpur - OBFHELPER
     public void a(EnumHand enumhand, ItemStack itemstack) {
         if (enumhand == EnumHand.MAIN_HAND) {
             this.setSlot(EnumItemSlot.MAINHAND, itemstack);
diff --git a/src/main/java/net/minecraft/server/EntityWolf.java b/src/main/java/net/minecraft/server/EntityWolf.java
index 6c25f667eecdf345289a0dbf885c9d71c6a26958..5fe2e9f4bfbdc08690eacd6196e59529dc7953e8 100644
--- a/src/main/java/net/minecraft/server/EntityWolf.java
+++ b/src/main/java/net/minecraft/server/EntityWolf.java
@@ -14,11 +14,42 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable
     private static final DataWatcherObject<Boolean> br = DataWatcher.a(EntityWolf.class, DataWatcherRegistry.i);
     private static final DataWatcherObject<Integer> bs = DataWatcher.a(EntityWolf.class, DataWatcherRegistry.b);
     private static final DataWatcherObject<Integer> bt = DataWatcher.a(EntityWolf.class, DataWatcherRegistry.b);
-    public static final Predicate<EntityLiving> bq = (entityliving) -> {
+    public static Predicate<EntityLiving> vanillaPredicate() { return bq; } public static final Predicate<EntityLiving> bq = (entityliving) -> { // Purpur - OBFHELPER
         EntityTypes<?> entitytypes = entityliving.getEntityType();
 
         return entitytypes == EntityTypes.SHEEP || entitytypes == EntityTypes.RABBIT || entitytypes == EntityTypes.FOX;
     };
+    // Purpur start - rabid wolf spawn chance
+    private boolean isRabid = false;
+    private static final Predicate<EntityLiving> RABID_PREDICATE = e -> e instanceof EntityPlayer || e instanceof EntityInsentient;
+    private final PathfinderGoal PATHFINDER_VANILLA = new PathfinderGoalRandomTargetNonTamed<>(this, EntityAnimal.class, false, vanillaPredicate());
+    private final PathfinderGoal PATHFINDER_RABID = new PathfinderGoalRandomTargetNonTamed<>(this, EntityLiving.class, false, RABID_PREDICATE);
+    private static final class PathfinderGoalAvoidRabidWolves extends PathfinderGoalAvoidTarget<EntityWolf> {
+        private final EntityWolf wolf;
+
+        public PathfinderGoalAvoidRabidWolves(EntityWolf wolf, float distance, double minSpeed, double maxSpeed) {
+            super(wolf, EntityWolf.class, distance, minSpeed, maxSpeed);
+            this.wolf = wolf;
+        }
+
+        @Override
+        public boolean a() { // shouldExecute
+            return super.a() && !this.wolf.isRabid() && this.getTarget() != null && this.getTarget().isRabid(); // wolves which are not rabid run away from rabid wolves
+        }
+
+        @Override
+        public void c() { // startExecuting
+            this.wolf.setGoalTarget(null);
+            super.c();
+        }
+
+        @Override
+        public void e() { // tick
+            this.wolf.setGoalTarget(null);
+            super.e();
+        }
+    }
+    // Purpur end
     private float bu;
     private float bv;
     private boolean bw;
@@ -53,6 +84,37 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable
     int getPurpurBreedTime() {
         return this.world.purpurConfig.wolfBreedingTicks;
     }
+
+    public boolean isRabid() {
+        return this.isRabid;
+    }
+
+    public void setRabid(boolean isRabid) {
+        this.isRabid = isRabid;
+        updatePathfinders(true);
+    }
+
+    public void updatePathfinders(boolean modifyEffects) {
+        this.targetSelector.removeGoal(PATHFINDER_VANILLA);
+        this.targetSelector.removeGoal(PATHFINDER_RABID);
+        if (this.isRabid) {
+            setTamed(false);
+            setOwnerUUID(null);
+            this.targetSelector.addGoal(5, PATHFINDER_RABID);
+            if (modifyEffects) this.addEffect(new MobEffect(MobEffects.CONFUSION, 1200));
+        } else {
+            this.targetSelector.addGoal(5, PATHFINDER_VANILLA);
+            this.pacify();
+            if (modifyEffects) this.removeEffect(MobEffects.CONFUSION);
+        }
+    }
+
+    @Override
+    public GroupDataEntity prepare(WorldAccess worldaccess, DifficultyDamageScaler difficultydamagescaler, EnumMobSpawn enummobspawn, @Nullable GroupDataEntity groupdataentity, @Nullable NBTTagCompound nbttagcompound) {
+        this.isRabid = world.purpurConfig.wolfNaturalRabid > 0.0D && random.nextDouble() <= world.purpurConfig.wolfNaturalRabid;
+        this.updatePathfinders(false);
+        return super.prepare(worldaccess, difficultydamagescaler, enummobspawn, groupdataentity, nbttagcompound);
+    }
     // Purpur end
 
     @Override
@@ -61,6 +123,7 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable
         this.goalSelector.a(1, new PathfinderGoalHasRider(this)); // Purpur
         this.goalSelector.a(2, new PathfinderGoalSit(this));
         this.goalSelector.a(3, new EntityWolf.a<>(this, EntityLlama.class, 24.0F, 1.5D, 1.5D));
+        this.goalSelector.addGoal(3, new PathfinderGoalAvoidRabidWolves(this, 24.0F, 1.5D, 1.5D)); // Purpur
         this.goalSelector.a(4, new PathfinderGoalLeapAtTarget(this, 0.4F));
         this.goalSelector.a(5, new PathfinderGoalMeleeAttack(this, 1.0D, true));
         this.goalSelector.a(6, new PathfinderGoalFollowOwner(this, 1.0D, 10.0F, 2.0F, false));
@@ -74,7 +137,7 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable
         this.targetSelector.a(2, new PathfinderGoalOwnerHurtTarget(this));
         this.targetSelector.a(3, (new PathfinderGoalHurtByTarget(this, new Class[0])).a(new Class[0])); // CraftBukkit - decompile error
         this.targetSelector.a(4, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, 10, true, false, this::a_));
-        this.targetSelector.a(5, new PathfinderGoalRandomTargetNonTamed<>(this, EntityAnimal.class, false, EntityWolf.bq));
+        //this.targetSelector.a(5, new PathfinderGoalRandomTargetNonTamed<>(this, EntityAnimal.class, false, EntityWolf.bq)); // Purpur - moved to updatePathfinders()
         this.targetSelector.a(6, new PathfinderGoalRandomTargetNonTamed<>(this, EntityTurtle.class, false, EntityTurtle.bo));
         this.targetSelector.a(7, new PathfinderGoalNearestAttackableTarget<>(this, EntitySkeletonAbstract.class, false));
         this.targetSelector.a(8, new PathfinderGoalUniversalAngerReset<>(this, true));
@@ -119,6 +182,7 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable
     public void saveData(NBTTagCompound nbttagcompound) {
         super.saveData(nbttagcompound);
         nbttagcompound.setByte("CollarColor", (byte) this.getCollarColor().getColorIndex());
+        nbttagcompound.setBoolean("Purpur.IsRabid", this.isRabid); // Purpur
         this.c(nbttagcompound);
     }
 
@@ -128,6 +192,10 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable
         if (nbttagcompound.hasKeyOfType("CollarColor", 99)) {
             this.setCollarColor(EnumColor.fromColorIndex(nbttagcompound.getInt("CollarColor")));
         }
+        // Purpur start
+        this.isRabid = nbttagcompound.getBoolean("Purpur.IsRabid");
+        this.updatePathfinders(false);
+        // Purpur end
 
         this.a((WorldServer) this.world, nbttagcompound);
     }
@@ -172,6 +240,11 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable
     public void tick() {
         super.tick();
         if (this.isAlive()) {
+            // Purpur start
+            if (this.ticksLived % 300 == 0 && this.isRabid()) {
+                this.addEffect(new MobEffect(MobEffects.CONFUSION, 400));
+            }
+            // Purpur end
             this.bv = this.bu;
             if (this.eY()) {
                 this.bu += (1.0F - this.bu) * 0.4F;
@@ -343,6 +416,20 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable
 
                 return EnumInteractionResult.SUCCESS;
             }
+            // Purpur start
+            else if (this.world.purpurConfig.wolfMilkCuresRabies && itemstack.getItem() == Items.MILK_BUCKET && this.isRabid()) {
+                if (!entityhuman.isCreative()) {
+                    entityhuman.setItemInHand(enumhand, new ItemStack(Items.BUCKET));
+                }
+                this.setRabid(false);
+                for (int i = 0; i < 10; ++i) {
+                    ((WorldServer) world).sendParticles(((WorldServer) world).players, null, Particles.HAPPY_VILLAGER,
+                            locX() + random.nextFloat(), locY() + (random.nextFloat() * 1.5), locZ() + random.nextFloat(), 1,
+                            random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0, true);
+                }
+                return EnumInteractionResult.SUCCESS;
+            }
+            // Purpur end
 
             return super.b(entityhuman, enumhand);
         }
diff --git a/src/main/java/net/minecraft/server/PathfinderGoalAvoidTarget.java b/src/main/java/net/minecraft/server/PathfinderGoalAvoidTarget.java
index 9a4819815c7a4bf2fd4a92c4169ace35f2261704..da29898574d30d5fecc5a44ad7b365564fa686e1 100644
--- a/src/main/java/net/minecraft/server/PathfinderGoalAvoidTarget.java
+++ b/src/main/java/net/minecraft/server/PathfinderGoalAvoidTarget.java
@@ -8,7 +8,7 @@ public class PathfinderGoalAvoidTarget<T extends EntityLiving> extends Pathfinde
     protected final EntityCreature a;
     private final double i;
     private final double j;
-    protected T b;
+    protected T b; protected T getTarget() { return this.b; } // Purpur - OBFHELPER
     protected final float c;
     protected PathEntity d;
     protected final NavigationAbstract e;
@@ -18,12 +18,7 @@ public class PathfinderGoalAvoidTarget<T extends EntityLiving> extends Pathfinde
     private final PathfinderTargetCondition k;
 
     public PathfinderGoalAvoidTarget(EntityCreature entitycreature, Class<T> oclass, float f, double d0, double d1) {
-        Predicate predicate = (entityliving) -> {
-            return true;
-        };
-        Predicate predicate1 = IEntitySelector.e;
-
-        this(entitycreature, oclass, predicate, f, d0, d1, predicate1::test);
+        this(entitycreature, oclass, entityliving -> true, f, d0, d1, IEntitySelector.e::test); // Purpur - decompile fix
     }
 
     public PathfinderGoalAvoidTarget(EntityCreature entitycreature, Class<T> oclass, Predicate<EntityLiving> predicate, float f, double d0, double d1, Predicate<EntityLiving> predicate1) {
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index f7ccf7ce209c047dbfe18539fba6a12ca3765c78..aea3e3ae09d2df797d284104eafb957e8f11a109 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -1161,10 +1161,14 @@ public class PurpurWorldConfig {
 
     public boolean wolfRidable = false;
     public boolean wolfRidableInWater = false;
+    public boolean wolfMilkCuresRabies = true;
+    public double wolfNaturalRabid = 0.0D;
     public int wolfBreedingTicks = 6000;
     private void wolfSettings() {
         wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable);
         wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater);
+        wolfMilkCuresRabies = getBoolean("mobs.wolf.milk-cures-rabid-wolves", wolfMilkCuresRabies);
+        wolfNaturalRabid = getDouble("mobs.wolf.spawn-rabid-chance", wolfNaturalRabid);
         wolfBreedingTicks = getInt("mobs.wolf.breeding-delay-ticks", wolfBreedingTicks);
     }
 
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java
index 5f3314febb2300a9b4f3a7c143cb65811e1d5320..507857ba247d0988e0011d215ea38a3622e78e05 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java
@@ -45,4 +45,16 @@ public class CraftWolf extends CraftTameableAnimal implements Wolf {
     public void setCollarColor(DyeColor color) {
         getHandle().setCollarColor(EnumColor.fromColorIndex(color.getWoolData()));
     }
+
+    // Purpur start
+    @Override
+    public boolean isRabid() {
+        return getHandle().isRabid();
+    }
+
+    @Override
+    public void setRabid(boolean isRabid) {
+        getHandle().setRabid(isRabid);
+    }
+    // Purpur end
 }
