From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Thu, 10 Dec 2020 16:44:54 -0600
Subject: [PATCH] Configurable entity base attributes


diff --git a/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java b/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java
index ce40df98f61b9176989c0000d078597d44e996e2..e6c5d21da445c9b66dcca33d9029d1768bbe046a 100644
--- a/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java
+++ b/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java
@@ -81,6 +81,18 @@ public class EntityBat extends EntityAmbient {
             setMot(mot.a(0.9D));
         }
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.batMaxHealth);
+        this.getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(this.world.purpurConfig.batFollowRange);
+        this.getAttributeInstance(GenericAttributes.KNOCKBACK_RESISTANCE).setValue(this.world.purpurConfig.batKnockbackResistance);
+        this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(this.world.purpurConfig.batMovementSpeed);
+        this.getAttributeInstance(GenericAttributes.FLYING_SPEED).setValue(this.world.purpurConfig.batFlyingSpeed);
+        this.getAttributeInstance(GenericAttributes.ARMOR).setValue(this.world.purpurConfig.batArmor);
+        this.getAttributeInstance(GenericAttributes.ARMOR_TOUGHNESS).setValue(this.world.purpurConfig.batArmorToughness);
+        this.getAttributeInstance(GenericAttributes.ATTACK_KNOCKBACK).setValue(this.world.purpurConfig.batAttackKnockback);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java
index 9e40fd6585592ccd1deff1d8319c57660474c053..c39a7a6d7f391debd632a199eeec8ded6189ad76 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java
@@ -181,6 +181,11 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.beeBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.beeMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCat.java b/src/main/java/net/minecraft/world/entity/animal/EntityCat.java
index 079b95ef465f7155f426a2c87a4a50f8369d0a18..7143b0801be7877762e41da336ea5e4e57f2e463 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityCat.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityCat.java
@@ -127,6 +127,11 @@ public class EntityCat extends EntityTameableAnimal {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.catBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.catMaxHealth);
+    }
     // Purpur end
 
     public MinecraftKey eU() {
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java b/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java
index ab54e809f735cea7d84366d2bc205351f8992bef..51fd3d955c866cc09bb09abe1b6d23caad2d7e85 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java
@@ -70,6 +70,7 @@ public class EntityChicken extends EntityAnimal {
         if (world.purpurConfig.chickenRetaliate) {
             this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue(2.0D);
         }
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.chickenMaxHealth);
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCod.java b/src/main/java/net/minecraft/world/entity/animal/EntityCod.java
index 897e0d5ca44a0c475634f08e7d4fcf129ee197ab..07c6dc6a1b9af7b9662f4dd4b4a2ddfcbe600c34 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityCod.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityCod.java
@@ -4,6 +4,7 @@ import net.minecraft.sounds.SoundEffect;
 import net.minecraft.sounds.SoundEffects;
 import net.minecraft.world.damagesource.DamageSource;
 import net.minecraft.world.entity.EntityTypes;
+import net.minecraft.world.entity.ai.attributes.GenericAttributes;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.Items;
 import net.minecraft.world.level.World;
@@ -24,6 +25,11 @@ public class EntityCod extends EntityFishSchool {
     public boolean isRidableInWater() {
         return true;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.codMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCow.java b/src/main/java/net/minecraft/world/entity/animal/EntityCow.java
index 93589a2b86e6663d93f6b536b853996c08db549a..2a8c0537fbb68577a3da3f8d07c16e9ca18b224d 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityCow.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityCow.java
@@ -59,6 +59,11 @@ public class EntityCow extends EntityAnimal {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.cowBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.cowMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java b/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java
index 880c3aaf4e684209879dc921480619e7c61ee4a0..6b32b3e4877efa64942838a07af5d48cd4e33a80 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java
@@ -128,6 +128,11 @@ public class EntityDolphin extends EntityWaterAnimal {
         }
         return false;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.dolphinMaxHealth);
+    }
     // Purpur end
 
     @Nullable
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java
index 7bf546a1b2a80179962ed08a35d86f0a28eda3c2..b8b0ee65798dc94d707fa64bd53fdda5506331d9 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java
@@ -164,6 +164,11 @@ public class EntityFox extends EntityAnimal {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.foxBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.foxMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java b/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java
index 23e614f0c3cf1178acff8e72e0441c42c658e76b..9ee82c908008190e31034e614c241fc7a66248e1 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java
@@ -80,6 +80,11 @@ public class EntityIronGolem extends EntityGolem implements IEntityAngerable {
     public boolean isRidableInWater() {
         return world.purpurConfig.ironGolemRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.ironGolemMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java
index ab4a8ee6e1912f230cbf3353eb42c3bc8a9db58e..4b7e21a611d87410805722c30c9ee77212b33348 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java
@@ -24,6 +24,7 @@ import net.minecraft.world.entity.EntityLightning;
 import net.minecraft.world.entity.EntityTypes;
 import net.minecraft.world.entity.EnumMobSpawn;
 import net.minecraft.world.entity.IShearable;
+import net.minecraft.world.entity.ai.attributes.GenericAttributes;
 import net.minecraft.world.entity.item.EntityItem;
 import net.minecraft.world.entity.player.EntityHuman;
 import net.minecraft.world.item.Item;
@@ -72,6 +73,11 @@ public class EntityMushroomCow extends EntityCow implements IShearable {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.mooshroomBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.mooshroomMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java b/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java
index cff2ff5a8beef739f0515832e072e7e390ac388f..12534673afe0b05868a5f400c9e59c22dfcf12d6 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java
@@ -79,6 +79,11 @@ public class EntityOcelot extends EntityAnimal {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.ocelotBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.ocelotMaxHealth);
+    }
     // Purpur end
 
     private boolean isTrusting() {
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java b/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java
index e6952c0a8d90eb4b133c517d97299f2c3db7e329..94141b8c1ad62e6d187726734d25dd0ee5535618 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java
@@ -34,6 +34,7 @@ import net.minecraft.world.entity.EnumItemSlot;
 import net.minecraft.world.entity.EnumMobSpawn;
 import net.minecraft.world.entity.GroupDataEntity;
 import net.minecraft.world.entity.IEntitySelector;
+import net.minecraft.world.entity.ai.attributes.AttributeModifiable;
 import net.minecraft.world.entity.ai.attributes.AttributeProvider;
 import net.minecraft.world.entity.ai.attributes.GenericAttributes;
 import net.minecraft.world.entity.ai.control.ControllerMove;
@@ -126,6 +127,12 @@ public class EntityPanda extends EntityAnimal {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.pandaBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.pandaMaxHealth);
+        updateAttributes();
+    }
     // Purpur end
 
     @Override
@@ -598,9 +605,12 @@ public class EntityPanda extends EntityAnimal {
         return this.random.nextBoolean() ? this.getMainGene() : this.getHiddenGene();
     }
 
-    public void fg() {
+    public void fg() { updateAttributes(); } public void updateAttributes() { // Purpur - OBFHELPER
         if (this.isWeak()) {
-            this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(10.0D);
+            // Purpur start
+            AttributeModifiable maxHealth = this.getAttributeInstance(GenericAttributes.MAX_HEALTH);
+            maxHealth.setValue(maxHealth.getValue() / 2);
+            // Purpur end
         }
 
         if (this.isLazy()) {
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java
index 5463e1779422ff19499727a000fdfbbfc38809a8..efa4318989893c946e9d7671d0dead6c4a6e315f 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java
@@ -176,6 +176,11 @@ public class EntityParrot extends EntityPerchable implements EntityBird {
     public int getPurpurBreedTime() {
         return 6000;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.parrotMaxHealth);
+    }
     // Purpur end
 
     @Nullable
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPig.java b/src/main/java/net/minecraft/world/entity/animal/EntityPig.java
index 5aa8806063186bec36b38adc51e2ea82bf6ff21a..8d24855f230a5ca6280f885d5b1c26ecf5b91395 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityPig.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityPig.java
@@ -82,6 +82,11 @@ public class EntityPig extends EntityAnimal implements ISteerable, ISaddleable {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.pigBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.pigMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java b/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java
index 2306abb72ea76a52fd6f27648c4815ad99f8f005..5a496d55b40f98609b0a9aac25929f6b5c0311ba 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java
@@ -121,6 +121,11 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.polarBearBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.polarBearMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java b/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java
index 38fe79872b4b7f4ad4a030fbdf505efbc0352fc0..0d32590cf4cfdd95da6aceac5190d42c8e966ce7 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java
@@ -20,6 +20,7 @@ import net.minecraft.world.entity.EntityPose;
 import net.minecraft.world.entity.EntitySize;
 import net.minecraft.world.entity.EntityTypes;
 import net.minecraft.world.entity.EnumMonsterType;
+import net.minecraft.world.entity.ai.attributes.GenericAttributes;
 import net.minecraft.world.entity.ai.goal.PathfinderGoal;
 import net.minecraft.world.entity.player.EntityHuman;
 import net.minecraft.world.item.ItemStack;
@@ -49,6 +50,11 @@ public class EntityPufferFish extends EntityFish {
     public boolean isRidableInWater() {
         return true;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.pufferfishMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java
index 0b706404895b69fbca79502a327ec20b47ed99f0..284c52276b2fd816990c23b7b8a9ee50e70ab005 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java
@@ -91,6 +91,11 @@ public class EntityRabbit extends EntityAnimal {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.rabbitBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.rabbitMaxHealth);
+    }
     // Purpur end
 
     // CraftBukkit start - code from constructor
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java b/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java
index bf565671c167162b3d935447961f0d44ed4a2779..36e60360193cb0cfd8fef03f964e0fa90002f8bc 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java
@@ -4,6 +4,7 @@ import net.minecraft.sounds.SoundEffect;
 import net.minecraft.sounds.SoundEffects;
 import net.minecraft.world.damagesource.DamageSource;
 import net.minecraft.world.entity.EntityTypes;
+import net.minecraft.world.entity.ai.attributes.GenericAttributes;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.Items;
 import net.minecraft.world.level.World;
@@ -24,6 +25,11 @@ public class EntitySalmon extends EntityFishSchool {
     public boolean isRidableInWater() {
         return true;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.salmonMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java b/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java
index ff6fc821085e4430a3b1008140b0b7fcacc59d2e..365f70117a287fab2fbf63ee8d89a10ac70b2f1b 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java
@@ -126,6 +126,11 @@ public class EntitySheep extends EntityAnimal implements IShearable {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.sheepBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.sheepMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java
index 28b5c22ecfe573ac9d91b74e54ebd3e3c5e6373f..88db8ff8cb415b84ab98cc0550c705d5a472230c 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java
@@ -61,6 +61,11 @@ public class EntitySnowman extends EntityGolem implements IShearable, IRangedEnt
     public boolean isRidableInWater() {
         return world.purpurConfig.snowGolemRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.snowGolemMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java b/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java
index be48e12dd6c9a390bf383129953bcd3d1f818427..1e7632d2ca4440dee4e406e26da61411ec5bc88f 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java
@@ -86,6 +86,11 @@ public class EntitySquid extends EntityWaterAnimal {
     public boolean isInWater() {
         return this.inWater || world.purpurConfig.squidsCanFly;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.squidMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java b/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java
index 478e55475ccc1410a442f4e30a1cbc08f479dbda..7d0982b8756b9e6c12cf4acae765ff651b846250 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java
@@ -14,6 +14,7 @@ import net.minecraft.world.damagesource.DamageSource;
 import net.minecraft.world.entity.EntityTypes;
 import net.minecraft.world.entity.EnumMobSpawn;
 import net.minecraft.world.entity.GroupDataEntity;
+import net.minecraft.world.entity.ai.attributes.GenericAttributes;
 import net.minecraft.world.item.EnumColor;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.Items;
@@ -47,6 +48,11 @@ public class EntityTropicalFish extends EntityFishSchool {
     public boolean isRidableInWater() {
         return true;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.tropicalFishMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java b/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java
index a16f586934f24e599d00bf793f06d3f9134ed29d..2da43c75c5767973c43e42af37c0d0d9d3a27859 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java
@@ -106,6 +106,11 @@ public class EntityTurtle extends EntityAnimal {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.turtleBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.turtleMaxHealth);
+    }
     // Purpur end
 
     public void setHomePos(BlockPosition blockposition) {
diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java
index e33aadead6e6c5e0a7b39ef95e7aeb0f0092a94e..090903fbc8f6cd1522c7afb358f708f5ae3395f4 100644
--- a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java
+++ b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java
@@ -188,6 +188,11 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable
         setCollarColor(world.purpurConfig.wolfDefaultCollarColor);
         super.tame(entityhuman);
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.wolfMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java
index c830bf6e5e38f5ebacc07673c3d67e4157c8c2b5..c6e39fe54cc402869b2e9eaea1830ba1ccc9ffc1 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java
@@ -51,6 +51,21 @@ public class EntityHorse extends EntityHorseAbstract {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.horseBreedingTicks;
     }
+
+    @Override
+    public float generateMaxHealth() {
+        return (float) generateMaxHealth(this.world.purpurConfig.horseMaxHealthMin, this.world.purpurConfig.horseMaxHealthMax);
+    }
+
+    @Override
+    public double generateJumpStrength() {
+        return generateJumpStrength(this.world.purpurConfig.horseJumpStrengthMin, this.world.purpurConfig.horseJumpStrengthMax);
+    }
+
+    @Override
+    public double generateMovementSpeed() {
+        return generateMovementSpeed(this.world.purpurConfig.horseMovementSpeedMin, this.world.purpurConfig.horseMovementSpeedMax);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java
index d4556fa190c754406d0c65baae941fb23af3f81f..1d938f324bc08c05b44c72b5a2927016ed599cf2 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java
@@ -120,6 +120,32 @@ public abstract class EntityHorseAbstract extends EntityAnimal implements IInven
     public boolean isRidableInWater() {
         return false;
     }
+
+    protected double generateMaxHealth(double min, double max) {
+        if (min == max) return min;
+        int diff = MathHelper.floor(max - min);
+        double base = max - diff;
+        int first = MathHelper.floor((double) diff / 2);
+        int rest = diff - first;
+        return base + random.nextInt(first + 1) + random.nextInt(rest + 1);
+    }
+
+    protected double generateJumpStrength(double min, double max) {
+        if (min == max) return min;
+        return min + (max - min) * this.random.nextDouble();
+    }
+
+    protected double generateMovementSpeed(double min, double max) {
+        if (min == max) return min;
+        return min + (max - min) * this.random.nextDouble();
+    }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.generateMaxHealth());
+        this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(this.generateMovementSpeed());
+        this.getAttributeInstance(GenericAttributes.JUMP_STRENGTH).setValue(this.generateJumpStrength());
+    }
     // Purpur end
 
     @Override
@@ -928,15 +954,15 @@ public abstract class EntityHorseAbstract extends EntityAnimal implements IInven
 
     }
 
-    protected float fp() {
+    protected float fp() { return generateMaxHealth(); } public float generateMaxHealth() { // Purpur - OBFHELPER
         return 15.0F + (float) this.random.nextInt(8) + (float) this.random.nextInt(9);
     }
 
-    protected double fq() {
+    protected double fq() { return generateJumpStrength(); } public double generateJumpStrength() { // Purpur - OBFHELPER
         return 0.4000000059604645D + this.random.nextDouble() * 0.2D + this.random.nextDouble() * 0.2D + this.random.nextDouble() * 0.2D;
     }
 
-    protected double fr() {
+    protected double fr() { return generateMovementSpeed(); } public double generateMovementSpeed() { // Purpur - OBFHELPER
         return (0.44999998807907104D + this.random.nextDouble() * 0.3D + this.random.nextDouble() * 0.3D + this.random.nextDouble() * 0.3D) * 0.25D;
     }
 
@@ -1059,7 +1085,7 @@ public abstract class EntityHorseAbstract extends EntityAnimal implements IInven
             groupdataentity = new EntityAgeable.a(0.2F);
         }
 
-        this.eK();
+        //this.eK(); // Purpur
         return super.prepare(worldaccess, difficultydamagescaler, enummobspawn, (GroupDataEntity) groupdataentity, nbttagcompound);
     }
 }
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java
index 3b44394dcba8e9905aca46e6e585ee6d7a87de44..589986b36c12dd2774a87e1d22aafd6d3052f123 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java
@@ -26,6 +26,21 @@ public class EntityHorseDonkey extends EntityHorseChestedAbstract {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.donkeyBreedingTicks;
     }
+
+    @Override
+    public float generateMaxHealth() {
+        return (float) generateMaxHealth(this.world.purpurConfig.donkeyMaxHealthMin, this.world.purpurConfig.donkeyMaxHealthMax);
+    }
+
+    @Override
+    public double generateJumpStrength() {
+        return generateJumpStrength(this.world.purpurConfig.donkeyJumpStrengthMin, this.world.purpurConfig.donkeyJumpStrengthMax);
+    }
+
+    @Override
+    public double generateMovementSpeed() {
+        return generateMovementSpeed(this.world.purpurConfig.donkeyMovementSpeedMin, this.world.purpurConfig.donkeyMovementSpeedMax);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java
index 0536112357e0321dbb902331467b847894a4c11b..9cc1a371dfbb0305fa47e69665a12a6901224edc 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java
@@ -25,7 +25,23 @@ public class EntityHorseMule extends EntityHorseChestedAbstract {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.muleBreedingTicks;
     }
+
+    @Override
+    public float generateMaxHealth() {
+        return (float) generateMaxHealth(this.world.purpurConfig.muleMaxHealthMin, this.world.purpurConfig.muleMaxHealthMax);
+    }
+
+    @Override
+    public double generateJumpStrength() {
+        return generateJumpStrength(this.world.purpurConfig.muleJumpStrengthMin, this.world.purpurConfig.muleJumpStrengthMax);
+    }
+
+    @Override
+    public double generateMovementSpeed() {
+        return generateMovementSpeed(this.world.purpurConfig.muleMovementSpeedMin, this.world.purpurConfig.muleMovementSpeedMax);
+    }
     // Purpur end
+
     @Override
     protected SoundEffect getSoundAmbient() {
         super.getSoundAmbient();
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java
index 28c6e3745c61d0670bf7f3a324169472250e25f4..0fe21fde809aa72305b1145b994a7aafe3f03112 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java
@@ -48,6 +48,21 @@ public class EntityHorseSkeleton extends EntityHorseAbstract {
     public int getPurpurBreedTime() {
         return 6000;
     }
+
+    @Override
+    public float generateMaxHealth() {
+        return (float) generateMaxHealth(this.world.purpurConfig.skeletonHorseMaxHealthMin, this.world.purpurConfig.skeletonHorseMaxHealthMax);
+    }
+
+    @Override
+    public double generateJumpStrength() {
+        return generateJumpStrength(this.world.purpurConfig.skeletonHorseJumpStrengthMin, this.world.purpurConfig.skeletonHorseJumpStrengthMax);
+    }
+
+    @Override
+    public double generateMovementSpeed() {
+        return generateMovementSpeed(this.world.purpurConfig.skeletonHorseMovementSpeedMin, this.world.purpurConfig.skeletonHorseMovementSpeedMax);
+    }
     // Purpur end
 
     public static AttributeProvider.Builder eL() {
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java
index c776f18722d1aa73f53da66ef6b37564eeaddd2a..1820c2d225d1fa919de2b1c0593370a8a17b4b6a 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java
@@ -40,6 +40,21 @@ public class EntityHorseZombie extends EntityHorseAbstract {
     public int getPurpurBreedTime() {
         return 6000;
     }
+
+    @Override
+    public float generateMaxHealth() {
+        return (float) generateMaxHealth(this.world.purpurConfig.zombieHorseMaxHealthMin, this.world.purpurConfig.zombieHorseMaxHealthMax);
+    }
+
+    @Override
+    public double generateJumpStrength() {
+        return generateJumpStrength(this.world.purpurConfig.zombieHorseJumpStrengthMin, this.world.purpurConfig.zombieHorseJumpStrengthMax);
+    }
+
+    @Override
+    public double generateMovementSpeed() {
+        return generateMovementSpeed(this.world.purpurConfig.zombieHorseMovementSpeedMin, this.world.purpurConfig.zombieHorseMovementSpeedMax);
+    }
     // Purpur end
 
     public static AttributeProvider.Builder eL() {
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java
index b3d51abc9bad9cad6fdc5dbdc2bf09d43a565f98..762fed5ba27474951c1962e6f034e8494b1035d6 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java
@@ -113,6 +113,21 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.llamaBreedingTicks;
     }
+
+    @Override
+    public float generateMaxHealth() {
+        return (float) generateMaxHealth(this.world.purpurConfig.llamaMaxHealthMin, this.world.purpurConfig.llamaMaxHealthMax);
+    }
+
+    @Override
+    public double generateJumpStrength() {
+        return generateJumpStrength(this.world.purpurConfig.llamaJumpStrengthMin, this.world.purpurConfig.llamaJumpStrengthMax);
+    }
+
+    @Override
+    public double generateMovementSpeed() {
+        return generateMovementSpeed(this.world.purpurConfig.llamaMovementSpeedMin, this.world.purpurConfig.llamaMovementSpeedMax);
+    }
     // Purpur end
 
     public void setStrength(int i) {
diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java
index 0fb651bcde1109b0eb30b60226d3512648dceb41..73f59982d70093d308c6dc6a9a5693347c2699b7 100644
--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java
@@ -42,6 +42,21 @@ public class EntityLlamaTrader extends EntityLlama {
     public boolean hasSaddle() {
         return super.hasSaddle() || isTamed();
     }
+
+    @Override
+    public float generateMaxHealth() {
+        return (float) generateMaxHealth(this.world.purpurConfig.llamaTraderMaxHealthMin, this.world.purpurConfig.llamaTraderMaxHealthMax);
+    }
+
+    @Override
+    public double generateJumpStrength() {
+        return generateJumpStrength(this.world.purpurConfig.llamaTraderJumpStrengthMin, this.world.purpurConfig.llamaTraderJumpStrengthMax);
+    }
+
+    @Override
+    public double generateMovementSpeed() {
+        return generateMovementSpeed(this.world.purpurConfig.llamaTraderMovementSpeedMin, this.world.purpurConfig.llamaTraderMovementSpeedMax);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java
index 7f583c6c15f0191219eb911d901ea28d86c11489..999a6d17eccd6305c0063e1558abfe70d72c39fe 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java
@@ -147,6 +147,11 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster {
     public double getMaxY() {
         return world.purpurConfig.enderDragonMaxY;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.enderDragonMaxHealth);
+    }
     // Purpur end
 
     public static AttributeProvider.Builder m() {
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java b/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java
index 9a109ed062e5abedaad295383aca6441321da276..45e69d2f8da4c5babfd2e67055cc0a4c6d3baac7 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java
@@ -72,6 +72,11 @@ public class EntityBlaze extends EntityMonster {
             setMot(mot.a(0.9D));
         }
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.blazeMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java b/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java
index 27baf5cde99d8f25b1e7583c30339fcc71a3786f..72b298642f17c13f0f5959034e345a47f1e7ae26 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java
@@ -34,6 +34,11 @@ public class EntityCaveSpider extends EntitySpider {
     public boolean isRidableInWater() {
         return world.purpurConfig.caveSpiderRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.caveSpiderMaxHealth);
+    }
     // Purpur end
 
     public static AttributeProvider.Builder m() {
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java
index 2cb9908a5c53528b2e02a1231752adc5ad8354f8..62d40f726355283baddde349c52bee0599bb293c 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java
@@ -137,6 +137,11 @@ public class EntityCreeper extends EntityMonster {
         }
         return getForward() == 0 && getStrafe() == 0; // do not jump if standing still
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.creeperMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java b/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java
index 93946f4e3cad07e20189a44ce512682b4cbc163b..926a38adb52b7d99ce2a9fcc52eb4878a2abdbcf 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java
@@ -97,6 +97,15 @@ public class EntityDrowned extends EntityZombie implements IRangedEntity {
     public boolean jockeyTryExistingChickens() {
         return world.purpurConfig.drownedJockeyTryExistingChickens;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.drownedMaxHealth);
+    }
+
+    protected void generateReinforcementsChance() {
+        this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * this.world.purpurConfig.drownedSpawnReinforcements);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java
index 18b3f8d1fadd1424327261d92b49977a35c4948c..478ac5bfdc69b5c3e24906bb5e0ea1dff81cea98 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java
@@ -96,6 +96,11 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable {
     public boolean isRidableInWater() {
         return world.purpurConfig.endermanRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.endermanMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java b/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java
index 1c87bea9de812e57f8ccd3c9aa85330af87ed240..0e1d60a744fb41d2c31950572720b8899281df47 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java
@@ -47,6 +47,11 @@ public class EntityEndermite extends EntityMonster {
     public boolean isRidableInWater() {
         return world.purpurConfig.endermiteRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.endermiteMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java b/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java
index 55607910183155080e3d96296421438d17f19c8f..8d7b8d2ac9a7340e2cfd0d1b8963e4e4d97e8bc8 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java
@@ -59,6 +59,11 @@ public class EntityEvoker extends EntityIllagerWizard {
     public boolean isRidableInWater() {
         return world.purpurConfig.evokerRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.evokerMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java b/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java
index 8784647f512d280ee0a092ecd406321268359314..5c39a9aec865d25a9aa5edcfd3a0fd6d1166cbd1 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java
@@ -73,6 +73,11 @@ public class EntityGhast extends EntityFlying implements IMonster {
             setMot(mot.a(0.9D));
         }
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.ghastMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java b/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java
index 6980b6988549b37a33d204a6e84c9e81d384a57a..248c64ea21de214bfbb2fa39f289382fd4f76202 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java
@@ -86,6 +86,11 @@ public class EntityGuardian extends EntityMonster {
     public boolean isRidableInWater() {
         return true;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.guardianMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java b/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java
index 16b8606be2835dccdfa75f29827be4b88aaa1810..b06897c3d9dfc4612b0711eee5f225224e07ae91 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java
@@ -40,6 +40,11 @@ public class EntityGuardianElder extends EntityGuardian {
     public boolean isRidableInWater() {
         return true;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.elderGuardianMaxHealth);
+    }
     // Purpur end
 
     public static AttributeProvider.Builder m() {
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java b/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java
index 15ed51a2746c09538a425fce25fa25f2619b7033..626a207cdb727866cb75f4e53a6880867c1ca195 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java
@@ -44,6 +44,15 @@ public class EntityMagmaCube extends EntitySlime {
     public float getJumpHeight() {
         return 0.42F * this.getBlockJumpFactor(); // from EntityLiving
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.generateMaxHealth());
+    }
+
+    public String getMaxHealthEquation() {
+        return world.purpurConfig.magmaCubeMaxHealth;
+    }
     // Purpur end
 
     public static AttributeProvider.Builder m() {
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java
index a836839b17cbda8ac269f032b141ba448e3bab8c..902b26d609aef8dd46e8875cb7c06f187511e8d5 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java
@@ -120,6 +120,11 @@ public class EntityPhantom extends EntityFlying implements IMonster {
         world.addEntity(flames);
         return true;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.phantomMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java
index 8db9c62093b2f075face65030cb91c24fb6c2dbf..736c45bae020158866514bc760c05a929f47c531 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java
@@ -80,6 +80,15 @@ public class EntityPigZombie extends EntityZombie implements IEntityAngerable {
     public boolean jockeyTryExistingChickens() {
         return world.purpurConfig.zombifiedPiglinJockeyTryExistingChickens;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.zombifiedPiglinMaxHealth);
+    }
+
+    protected void generateReinforcementsChance() {
+        this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * this.world.purpurConfig.zombifiedPiglinSpawnReinforcements);
+    }
     // Purpur end
 
     @Override
@@ -268,7 +277,7 @@ public class EntityPigZombie extends EntityZombie implements IEntityAngerable {
 
     @Override
     protected void eV() {
-        this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(0.0D);
+        generateReinforcementsChance(); // Purpur
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java b/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java
index 2a4ac6e608650d56cc2b564e715b7b685e7f3f62..43a1a31db5ddfd30b66c63c6b2cceb1dcf62e412 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java
@@ -72,6 +72,11 @@ public class EntityPillager extends EntityIllagerAbstract implements ICrossbow {
     public boolean isRidableInWater() {
         return world.purpurConfig.pillagerRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.pillagerMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java b/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java
index dc1ca7b334e89b4d0be775b6f6e6f4222ea02dcc..80c3cd540a46e249e85586e8d7a2f0f6226091fc 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java
@@ -81,6 +81,11 @@ public class EntityRavager extends EntityRaider {
         double speed = this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getBaseValue();
         getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(speed);
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.ravagerMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java b/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java
index 0294ab119407dc45a40c8444fb5a91e154017234..a735ac7644f8fe6924349fbd9e8984f678d0b9c2 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java
@@ -82,6 +82,11 @@ public class EntityShulker extends EntityGolem implements IMonster {
     public boolean isRidableInWater() {
         return world.purpurConfig.shulkerRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.shulkerMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java b/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java
index c0601af022d85c7b03463f0df975d713c0366b2c..a0a1e5977a3cbc8e9befd827dd1e15352a2c0c39 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java
@@ -49,6 +49,11 @@ public class EntitySilverfish extends EntityMonster {
     public boolean isRidableInWater() {
         return world.purpurConfig.silverfishRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.silverfishMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java
index 0b8517d4e83d14ddf8b6d1f1cf4c538f9e4cc68f..8ee51897af1199b9bed05ddf90fe914a7b214b91 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java
@@ -5,6 +5,7 @@ import net.minecraft.sounds.SoundEffects;
 import net.minecraft.world.damagesource.DamageSource;
 import net.minecraft.world.entity.Entity;
 import net.minecraft.world.entity.EntityTypes;
+import net.minecraft.world.entity.ai.attributes.GenericAttributes;
 import net.minecraft.world.item.Items;
 import net.minecraft.world.level.IMaterial;
 import net.minecraft.world.level.World;
@@ -25,6 +26,11 @@ public class EntitySkeleton extends EntitySkeletonAbstract {
     public boolean isRidableInWater() {
         return world.purpurConfig.skeletonRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.skeletonMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java
index 8484000a1b0d9c252d6fab205b1e316e3f6f33bd..a75a7785406143325b0364737dd1667aad464018 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java
@@ -9,6 +9,7 @@ import net.minecraft.world.effect.MobEffect;
 import net.minecraft.world.effect.MobEffects;
 import net.minecraft.world.entity.EntityTypes;
 import net.minecraft.world.entity.EnumMobSpawn;
+import net.minecraft.world.entity.ai.attributes.GenericAttributes;
 import net.minecraft.world.entity.projectile.EntityArrow;
 import net.minecraft.world.entity.projectile.EntityTippedArrow;
 import net.minecraft.world.item.ItemStack;
@@ -31,6 +32,11 @@ public class EntitySkeletonStray extends EntitySkeletonAbstract {
     public boolean isRidableInWater() {
         return world.purpurConfig.strayRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.strayMaxHealth);
+    }
     // Purpur end
 
     public static boolean a(EntityTypes<EntitySkeletonStray> entitytypes, WorldAccess worldaccess, EnumMobSpawn enummobspawn, BlockPosition blockposition, Random random) {
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java
index cb52c4e63ac487d55dc16accca6976f44f904112..62f1808a456f46a6c7fbb5e030d9ed6546676a3d 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java
@@ -44,6 +44,11 @@ public class EntitySkeletonWither extends EntitySkeletonAbstract {
     public boolean isRidableInWater() {
         return world.purpurConfig.witherSkeletonRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.witherSkeletonMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java b/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java
index 0cbe3032fd3b048b0eb8ec3d8592a662c69c9e30..ce0d52a501dbff7c4eb70270bafa3e2a77599107 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java
@@ -51,6 +51,7 @@ import com.destroystokyo.paper.event.entity.SlimeChangeDirectionEvent;
 import com.destroystokyo.paper.event.entity.SlimeSwimEvent;
 import com.destroystokyo.paper.event.entity.SlimeTargetLivingEntityEvent;
 import com.destroystokyo.paper.event.entity.SlimeWanderEvent;
+import javax.script.ScriptException;
 import org.bukkit.entity.LivingEntity;
 import org.bukkit.entity.Slime;
 // Paper end
@@ -65,6 +66,7 @@ import org.bukkit.event.entity.SlimeSplitEvent;
 public class EntitySlime extends EntityInsentient implements IMonster {
 
     private static final DataWatcherObject<Integer> bo = DataWatcher.a(EntitySlime.class, DataWatcherRegistry.b);
+    private static javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); // Purpur
     public float b;
     public float c;
     public float d;
@@ -104,6 +106,30 @@ public class EntitySlime extends EntityInsentient implements IMonster {
         }
         return true; // do not jump() in wasd controller, let vanilla controller handle
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.generateMaxHealth());
+    }
+
+    public String getMaxHealthEquation() {
+        return world.purpurConfig.slimeMaxHealth;
+    }
+
+    public double generateMaxHealth() {
+        int size = getSize();
+        Double maxHealth = world.purpurConfig.slimeMaxHealthCache.get(size);
+        if (maxHealth == null) {
+            try {
+                scriptEngine.eval("size = " + size);
+                maxHealth = (double) scriptEngine.eval(getMaxHealthEquation());
+            } catch (Exception e) {
+                maxHealth = (double) size * size;
+            }
+            world.purpurConfig.slimeMaxHealthCache.put(size, maxHealth);
+        }
+        return maxHealth;
+    }
     // Purpur end
 
     @Override
@@ -130,7 +156,7 @@ public class EntitySlime extends EntityInsentient implements IMonster {
         this.datawatcher.set(EntitySlime.bo, i);
         this.af();
         this.updateSize();
-        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue((double) (i * i));
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(generateMaxHealth()); // Purpur
         this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue((double) (0.2F + 0.1F * (float) i));
         this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue((double) i);
         if (flag) {
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java b/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java
index fbf7c31f57f6dbfac997480eb7db55efc15ef4cc..9b596aa061aa1d4ddfd66361d5277089c3e18246 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java
@@ -61,6 +61,11 @@ public class EntitySpider extends EntityMonster {
     public boolean isRidableInWater() {
         return world.purpurConfig.spiderRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.spiderMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java
index cba66a08feceeeaf7c123da595fc7b12c5749783..892aa844a98ae0d192737c6fc6df0a219256a47b 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java
@@ -110,6 +110,11 @@ public class EntityStrider extends EntityAnimal implements ISteerable, ISaddleab
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.striderBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.striderMaxHealth);
+    }
     // Purpur end
 
     public static boolean c(EntityTypes<EntityStrider> entitytypes, GeneratorAccess generatoraccess, EnumMobSpawn enummobspawn, BlockPosition blockposition, Random random) {
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityVex.java b/src/main/java/net/minecraft/world/entity/monster/EntityVex.java
index 4301ece0a04f3f2b4d198a684d0ca314deef2aef..69d47697442fa80fbed08a11bb9e66057d059101 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityVex.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityVex.java
@@ -92,6 +92,11 @@ public class EntityVex extends EntityMonster {
     public boolean b(float f, float f1) {
         return false; //  no fall damage please
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.vexMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java b/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java
index 28d345e87f45fa839bc3bd758f79f34aba546db7..caaa27248637255ad9e8db20ca839a980e01bfb6 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java
@@ -70,6 +70,11 @@ public class EntityVindicator extends EntityIllagerAbstract {
     public boolean isRidableInWater() {
         return world.purpurConfig.vindicatorRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.vindicatorMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java b/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java
index c4663c5b02363bd1499ce1f3b50027f8aa7c68e7..a119923ee8d8ac00892f594a8af6d392f818b59c 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java
@@ -74,6 +74,11 @@ public class EntityWitch extends EntityRaider implements IRangedEntity {
     public boolean isRidableInWater() {
         return world.purpurConfig.witchRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.witchMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java b/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java
index c5b1ce9268d6e6f3ec26eda4b5d8e7ae2a2ea672..17c96e8eaa5cde028024f5ad4b853e3399a942d5 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java
@@ -72,6 +72,11 @@ public class EntityZoglin extends EntityMonster implements IMonster, IOglin {
     public boolean isRidableInWater() {
         return world.purpurConfig.zoglinRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.zoglinMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java
index 88264b7b2c21a377f4b0dd857065e40165f0acde..7112db516e62ca75a445482005c524129b84f54c 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java
@@ -130,6 +130,15 @@ public class EntityZombie extends EntityMonster {
     public boolean jockeyTryExistingChickens() {
         return world.purpurConfig.zombieJockeyTryExistingChickens;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.zombieMaxHealth);
+    }
+
+    protected void generateReinforcementsChance() {
+        this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * this.world.purpurConfig.zombieSpawnReinforcements);
+    }
     // Purpur end
 
     @Override
@@ -612,7 +621,7 @@ public class EntityZombie extends EntityMonster {
     }
 
     protected void eV() {
-        this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * 0.10000000149011612D);
+        generateReinforcementsChance(); // Purpur
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java
index ad801fc394fbb83cf280ee96f962e7f311615d72..c060d93d9f3332b514a1400dec14f2035c058e48 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java
@@ -11,6 +11,7 @@ import net.minecraft.world.entity.Entity;
 import net.minecraft.world.entity.EntityLiving;
 import net.minecraft.world.entity.EntityTypes;
 import net.minecraft.world.entity.EnumMobSpawn;
+import net.minecraft.world.entity.ai.attributes.GenericAttributes;
 import net.minecraft.world.entity.player.EntityHuman;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.level.World;
@@ -47,6 +48,15 @@ public class EntityZombieHusk extends EntityZombie {
     public boolean jockeyTryExistingChickens() {
         return world.purpurConfig.huskJockeyTryExistingChickens;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.huskMaxHealth);
+    }
+
+    protected void generateReinforcementsChance() {
+        this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * this.world.purpurConfig.huskSpawnReinforcements);
+    }
     // Purpur end
 
     public static boolean a(EntityTypes<EntityZombieHusk> entitytypes, WorldAccess worldaccess, EnumMobSpawn enummobspawn, BlockPosition blockposition, Random random) {
diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java
index b8395c7317494adf36010080931a1c8635ab6cfa..aeeee97a87680f072188d1fcc9ec55b5ca762295 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java
@@ -29,6 +29,7 @@ import net.minecraft.world.entity.EnumItemSlot;
 import net.minecraft.world.entity.EnumMobSpawn;
 import net.minecraft.world.entity.GroupDataEntity;
 import net.minecraft.world.entity.ReputationHandler;
+import net.minecraft.world.entity.ai.attributes.GenericAttributes;
 import net.minecraft.world.entity.ai.village.ReputationEvent;
 import net.minecraft.world.entity.npc.EntityVillager;
 import net.minecraft.world.entity.npc.VillagerData;
@@ -95,6 +96,15 @@ public class EntityZombieVillager extends EntityZombie implements VillagerDataHo
     public boolean jockeyTryExistingChickens() {
         return world.purpurConfig.zombieVillagerJockeyTryExistingChickens;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.zombieVillagerMaxHealth);
+    }
+
+    protected void generateReinforcementsChance() {
+        this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * this.world.purpurConfig.zombieVillagerSpawnReinforcements);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java
index 828d01abe8202a246ce07c1c652a17cbc829d904..b271df48d04f12a68e0b7abf2f1375749a9a0f08 100644
--- a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java
+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java
@@ -76,6 +76,11 @@ public class EntityHoglin extends EntityAnimal implements IMonster, IOglin {
     public int getPurpurBreedTime() {
         return this.world.purpurConfig.hoglinBreedingTicks;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.hoglinMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java
index 8c6f5273ed2ab4ec63b7854e290f790b2eca8c2f..99fc16aae085da564c5236e68925a8a2225f5c27 100644
--- a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java
+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java
@@ -80,6 +80,11 @@ public class EntityPiglin extends EntityPiglinAbstract implements ICrossbow {
     public boolean isRidableInWater() {
         return world.purpurConfig.piglinRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.piglinMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java
index da2220b08a9cd9c2d7d3fd06702e6690e12f095e..c441d6b2ce29d914a29c2f39d70adb14e9ab31a6 100644
--- a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java
+++ b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java
@@ -49,6 +49,11 @@ public class EntityPiglinBrute extends EntityPiglinAbstract {
     public boolean isRidableInWater() {
         return world.purpurConfig.piglinBruteRidableInWater;
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.piglinBruteMaxHealth);
+    }
     // Purpur end
 
     public static AttributeProvider.Builder eS() {
diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java
index 0924e0c13b3c57e46f6dc40232707088f96e98c7..16933de70a23414859019e19545bfa5baa38091a 100644
--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java
@@ -167,6 +167,11 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation
     public boolean a(EntityHuman entityhuman) {
         return world.purpurConfig.villagerCanBeLeashed && !this.isLeashed();
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.villagerMaxHealth);
+    }
     // Purpur end
 
     @Override
diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java
index 90cbef7fe8803295f82bddd6709fdf303aedcaba..b84916c0c58fd208ef5547299f8db8462d1c42fe 100644
--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java
+++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java
@@ -18,6 +18,7 @@ import net.minecraft.world.entity.EntityAgeable;
 import net.minecraft.world.entity.EntityExperienceOrb;
 import net.minecraft.world.entity.EntityInsentient;
 import net.minecraft.world.entity.EntityTypes;
+import net.minecraft.world.entity.ai.attributes.GenericAttributes;
 import net.minecraft.world.entity.ai.goal.PathfinderGoal;
 import net.minecraft.world.entity.ai.goal.PathfinderGoalAvoidTarget;
 import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat;
@@ -110,6 +111,11 @@ public class EntityVillagerTrader extends EntityVillagerAbstract {
     public boolean a(EntityHuman entityhuman) {
         return world.purpurConfig.villagerTraderCanBeLeashed && !this.isLeashed();
     }
+
+    @Override
+    public void initAttributes() {
+        this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.villagerTraderMaxHealth);
+    }
     // Purpur - end
 
     @Nullable
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 6f1ea7f760bd3a4ab6ba0787776b4017f9e6d52e..c423bc6a535a61dc7deed0b2c5f94eb1633aa1a3 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -496,30 +496,58 @@ public class PurpurWorldConfig {
     public boolean batRidable = false;
     public boolean batRidableInWater = false;
     public double batMaxY = 256D;
+    public double batMaxHealth = 6.0D;
+    public double batFollowRange = 16.0D;
+    public double batKnockbackResistance = 0.0D;
+    public double batMovementSpeed = 0.6D;
+    public double batFlyingSpeed = 0.6D;
+    public double batArmor = 0.0D;
+    public double batArmorToughness = 0.0D;
+    public double batAttackKnockback = 0.0D;
     private void batSettings() {
         batRidable = getBoolean("mobs.bat.ridable", batRidable);
         batRidableInWater = getBoolean("mobs.bat.ridable-in-water", batRidableInWater);
         batMaxY = getDouble("mobs.bat.ridable-max-y", batMaxY);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.bat.attributes.max-health", batMaxHealth);
+            set("mobs.bat.attributes.max-health", null);
+            set("mobs.bat.attributes.max_health", oldValue);
+        }
+        batMaxHealth = getDouble("mobs.bat.attributes.max_health", batMaxHealth);
     }
 
     public boolean beeRidable = false;
     public boolean beeRidableInWater = false;
     public double beeMaxY = 256D;
     public int beeBreedingTicks = 6000;
+    public double beeMaxHealth = 10.0D;
     private void beeSettings() {
         beeRidable = getBoolean("mobs.bee.ridable", beeRidable);
         beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater);
         beeMaxY = getDouble("mobs.bee.ridable-max-y", beeMaxY);
         beeBreedingTicks = getInt("mobs.bee.breeding-delay-ticks", beeBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.bee.attributes.max-health", beeMaxHealth);
+            set("mobs.bee.attributes.max-health", null);
+            set("mobs.bee.attributes.max_health", oldValue);
+        }
+        beeMaxHealth = getDouble("mobs.bee.attributes.max_health", beeMaxHealth);
     }
 
     public boolean blazeRidable = false;
     public boolean blazeRidableInWater = false;
     public double blazeMaxY = 256D;
+    public double blazeMaxHealth = 20.0D;
     private void blazeSettings() {
         blazeRidable = getBoolean("mobs.blaze.ridable", blazeRidable);
         blazeRidableInWater = getBoolean("mobs.blaze.ridable-in-water", blazeRidableInWater);
         blazeMaxY = getDouble("mobs.blaze.ridable-max-y", blazeMaxY);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.blaze.attributes.max-health", blazeMaxHealth);
+            set("mobs.blaze.attributes.max-health", null);
+            set("mobs.blaze.attributes.max_health", oldValue);
+        }
+        blazeMaxHealth = getDouble("mobs.blaze.attributes.max_health", blazeMaxHealth);
     }
 
     public boolean catRidable = false;
@@ -528,6 +556,7 @@ public class PurpurWorldConfig {
     public int catSpawnSwampHutScanRange = 16;
     public int catSpawnVillageScanRange = 48;
     public int catBreedingTicks = 6000;
+    public double catMaxHealth = 10.0D;
     private void catSettings() {
         catRidable = getBoolean("mobs.cat.ridable", catRidable);
         catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater);
@@ -535,51 +564,92 @@ public class PurpurWorldConfig {
         catSpawnSwampHutScanRange = getInt("mobs.cat.scan-range-for-other-cats.swamp-hut", catSpawnSwampHutScanRange);
         catSpawnVillageScanRange = getInt("mobs.cat.scan-range-for-other-cats.village", catSpawnVillageScanRange);
         catBreedingTicks = getInt("mobs.cat.breeding-delay-ticks", catBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.cat.attributes.max-health", catMaxHealth);
+            set("mobs.cat.attributes.max-health", null);
+            set("mobs.cat.attributes.max_health", oldValue);
+        }
+        catMaxHealth = getDouble("mobs.cat.attributes.max_health", catMaxHealth);
     }
 
     public boolean caveSpiderRidable = false;
     public boolean caveSpiderRidableInWater = false;
+    public double caveSpiderMaxHealth = 12.0D;
     private void caveSpiderSettings() {
         caveSpiderRidable = getBoolean("mobs.cave_spider.ridable", caveSpiderRidable);
         caveSpiderRidableInWater = getBoolean("mobs.cave_spider.ridable-in-water", caveSpiderRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.cave_spider.attributes.max-health", caveSpiderMaxHealth);
+            set("mobs.cave_spider.attributes.max-health", null);
+            set("mobs.cave_spider.attributes.max_health", oldValue);
+        }
+        caveSpiderMaxHealth = getDouble("mobs.cave_spider.attributes.max_health", caveSpiderMaxHealth);
     }
 
     public boolean chickenRidable = false;
     public boolean chickenRidableInWater = false;
     public boolean chickenRetaliate = false;
     public int chickenBreedingTicks = 6000;
+    public double chickenMaxHealth = 4.0D;
     private void chickenSettings() {
         chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable);
         chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater);
         chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate);
         chickenBreedingTicks = getInt("mobs.chicken.breeding-delay-ticks", chickenBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.chicken.attributes.max-health", chickenMaxHealth);
+            set("mobs.chicken.attributes.max-health", null);
+            set("mobs.chicken.attributes.max_health", oldValue);
+        }
+        chickenMaxHealth = getDouble("mobs.chicken.attributes.max_health", chickenMaxHealth);
     }
 
     public boolean codRidable = false;
+    public double codMaxHealth = 3.0D;
     private void codSettings() {
         codRidable = getBoolean("mobs.cod.ridable", codRidable);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.cod.attributes.max-health", codMaxHealth);
+            set("mobs.cod.attributes.max-health", null);
+            set("mobs.cod.attributes.max_health", oldValue);
+        }
+        codMaxHealth = getDouble("mobs.cod.attributes.max_health", codMaxHealth);
     }
 
     public boolean cowRidable = false;
     public boolean cowRidableInWater = false;
     public int cowFeedMushrooms = 0;
     public int cowBreedingTicks = 6000;
+    public double cowMaxHealth = 10.0D;
     private void cowSettings() {
         cowRidable = getBoolean("mobs.cow.ridable", cowRidable);
         cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater);
         cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms);
         cowBreedingTicks = getInt("mobs.cow.breeding-delay-ticks", cowBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.cow.attributes.max-health", cowMaxHealth);
+            set("mobs.cow.attributes.max-health", null);
+            set("mobs.cow.attributes.max_health", oldValue);
+        }
+        cowMaxHealth = getDouble("mobs.cow.attributes.max_health", cowMaxHealth);
     }
 
     public boolean creeperRidable = false;
     public boolean creeperRidableInWater = false;
     public boolean creeperAllowGriefing = true;
     public double creeperChargedChance = 0.0D;
+    public double creeperMaxHealth = 20.0D;
     private void creeperSettings() {
         creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable);
         creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater);
         creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing);
         creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.creeper.attributes.max-health", creeperMaxHealth);
+            set("mobs.creeper.attributes.max-health", null);
+            set("mobs.creeper.attributes.max_health", oldValue);
+        }
+        creeperMaxHealth = getDouble("mobs.creeper.attributes.max_health", creeperMaxHealth);
     }
 
     public boolean dolphinRidable = false;
@@ -587,19 +657,45 @@ public class PurpurWorldConfig {
     public float dolphinSpitSpeed = 1.0F;
     public float dolphinSpitDamage = 2.0F;
     public boolean dolphinDisableTreasureSearching = false;
+    public double dolphinMaxHealth = 10.0D;
     private void dolphinSettings() {
         dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable);
         dolphinSpitCooldown = getInt("mobs.dolphin.spit.cooldown", dolphinSpitCooldown);
         dolphinSpitSpeed = (float) getDouble("mobs.dolphin.spit.speed", dolphinSpitSpeed);
         dolphinSpitDamage = (float) getDouble("mobs.dolphin.spit.damage", dolphinSpitDamage);
         dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.dolphin.attributes.max-health", dolphinMaxHealth);
+            set("mobs.dolphin.attributes.max-health", null);
+            set("mobs.dolphin.attributes.max_health", oldValue);
+        }
+        dolphinMaxHealth = getDouble("mobs.dolphin.attributes.max_health", dolphinMaxHealth);
     }
 
     public boolean donkeyRidableInWater = false;
     public int donkeyBreedingTicks = 6000;
+    public double donkeyMaxHealthMin = 15.0D;
+    public double donkeyMaxHealthMax = 30.0D;
+    public double donkeyJumpStrengthMin = 0.5D;
+    public double donkeyJumpStrengthMax = 0.5D;
+    public double donkeyMovementSpeedMin = 0.175D;
+    public double donkeyMovementSpeedMax = 0.175D;
     private void donkeySettings() {
         donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater);
         donkeyBreedingTicks = getInt("mobs.donkey.breeding-delay-ticks", donkeyBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldMin = getDouble("mobs.donkey.attributes.max-health.min", donkeyMaxHealthMin);
+            double oldMax = getDouble("mobs.donkey.attributes.max-health.max", donkeyMaxHealthMax);
+            set("mobs.donkey.attributes.max-health", null);
+            set("mobs.donkey.attributes.max_health.min", oldMin);
+            set("mobs.donkey.attributes.max_health.max", oldMax);
+        }
+        donkeyMaxHealthMin = getDouble("mobs.donkey.attributes.max_health.min", donkeyMaxHealthMin);
+        donkeyMaxHealthMax = getDouble("mobs.donkey.attributes.max_health.max", donkeyMaxHealthMax);
+        donkeyJumpStrengthMin = getDouble("mobs.donkey.attributes.jump_strength.min", donkeyJumpStrengthMin);
+        donkeyJumpStrengthMax = getDouble("mobs.donkey.attributes.jump_strength.max", donkeyJumpStrengthMax);
+        donkeyMovementSpeedMin = getDouble("mobs.donkey.attributes.movement_speed.min", donkeyMovementSpeedMin);
+        donkeyMovementSpeedMax = getDouble("mobs.donkey.attributes.movement_speed.max", donkeyMovementSpeedMax);
     }
 
     public boolean drownedRidable = false;
@@ -607,73 +703,135 @@ public class PurpurWorldConfig {
     public boolean drownedJockeyOnlyBaby = true;
     public double drownedJockeyChance = 0.05D;
     public boolean drownedJockeyTryExistingChickens = true;
+    public double drownedMaxHealth = 20.0D;
+    public double drownedSpawnReinforcements = 0.1D;
     private void drownedSettings() {
         drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable);
         drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater);
         drownedJockeyOnlyBaby = getBoolean("mobs.drowned.jockey.only-babies", drownedJockeyOnlyBaby);
         drownedJockeyChance = getDouble("mobs.drowned.jockey.chance", drownedJockeyChance);
         drownedJockeyTryExistingChickens = getBoolean("mobs.drowned.jockey.try-existing-chickens", drownedJockeyTryExistingChickens);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.drowned.attributes.max-health", drownedMaxHealth);
+            set("mobs.drowned.attributes.max-health", null);
+            set("mobs.drowned.attributes.max_health", oldValue);
+        }
+        drownedMaxHealth = getDouble("mobs.drowned.attributes.max_health", drownedMaxHealth);
+        drownedSpawnReinforcements = getDouble("mobs.drowned.attributes.spawn_reinforcements", drownedSpawnReinforcements);
     }
 
     public boolean elderGuardianRidable = false;
+    public double elderGuardianMaxHealth = 80.0D;
     private void elderGuardianSettings() {
         elderGuardianRidable = getBoolean("mobs.elder_guardian.ridable", elderGuardianRidable);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.elder_guardian.attributes.max-health", elderGuardianMaxHealth);
+            set("mobs.elder_guardian.attributes.max-health", null);
+            set("mobs.elder_guardian.attributes.max_health", oldValue);
+        }
+        elderGuardianMaxHealth = getDouble("mobs.elder_guardian.attributes.max_health", elderGuardianMaxHealth);
     }
 
     public boolean enderDragonRidable = false;
     public boolean enderDragonRidableInWater = false;
     public double enderDragonMaxY = 256D;
     public boolean enderDragonAlwaysDropsFullExp = false;
+    public double enderDragonMaxHealth = 200.0D;
     private void enderDragonSettings() {
         enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable);
         enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater);
         enderDragonMaxY = getDouble("mobs.ender_dragon.ridable-max-y", enderDragonMaxY);
         enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp);
+        if (PurpurConfig.version < 8) {
+            double oldValue = getDouble("mobs.ender_dragon.max-health", enderDragonMaxHealth);
+            set("mobs.ender_dragon.max-health", null);
+            set("mobs.ender_dragon.attributes.max_health", oldValue);
+        } else if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.ender_dragon.attributes.max-health", enderDragonMaxHealth);
+            set("mobs.ender_dragon.attributes.max-health", null);
+            set("mobs.ender_dragon.attributes.max_health", oldValue);
+        }
+        enderDragonMaxHealth = getDouble("mobs.ender_dragon.attributes.max_health", enderDragonMaxHealth);
     }
 
     public boolean endermanRidable = false;
     public boolean endermanRidableInWater = false;
     public boolean endermanAllowGriefing = true;
     public boolean endermanDespawnEvenWithBlock = false;
+    public double endermanMaxHealth = 40.0D;
     private void endermanSettings() {
         endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable);
         endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater);
         endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing);
         endermanDespawnEvenWithBlock = getBoolean("mobs.enderman.can-despawn-with-held-block", endermanDespawnEvenWithBlock);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.enderman.attributes.max-health", endermanMaxHealth);
+            set("mobs.enderman.attributes.max-health", null);
+            set("mobs.enderman.attributes.max_health", oldValue);
+        }
+        endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth);
     }
 
     public boolean endermiteRidable = false;
     public boolean endermiteRidableInWater = false;
+    public double endermiteMaxHealth = 8.0D;
     private void endermiteSettings() {
         endermiteRidable = getBoolean("mobs.endermite.ridable", endermiteRidable);
         endermiteRidableInWater = getBoolean("mobs.endermite.ridable-in-water", endermiteRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.endermite.attributes.max-health", endermiteMaxHealth);
+            set("mobs.endermite.attributes.max-health", null);
+            set("mobs.endermite.attributes.max_health", oldValue);
+        }
+        endermiteMaxHealth = getDouble("mobs.endermite.attributes.max_health", endermiteMaxHealth);
     }
 
     public boolean evokerRidable = false;
     public boolean evokerRidableInWater = false;
+    public double evokerMaxHealth = 24.0D;
     private void evokerSettings() {
         evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable);
         evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.evoker.attributes.max-health", evokerMaxHealth);
+            set("mobs.evoker.attributes.max-health", null);
+            set("mobs.evoker.attributes.max_health", oldValue);
+        }
+        evokerMaxHealth = getDouble("mobs.evoker.attributes.max_health", evokerMaxHealth);
     }
 
     public boolean foxRidable = false;
     public boolean foxRidableInWater = false;
     public boolean foxTypeChangesWithTulips = false;
     public int foxBreedingTicks = 6000;
+    public double foxMaxHealth = 10.0D;
     private void foxSettings() {
         foxRidable = getBoolean("mobs.fox.ridable", foxRidable);
         foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater);
         foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips);
         foxBreedingTicks = getInt("mobs.fox.breeding-delay-ticks", foxBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.fox.attributes.max-health", foxMaxHealth);
+            set("mobs.fox.attributes.max-health", null);
+            set("mobs.fox.attributes.max_health", oldValue);
+        }
+        foxMaxHealth = getDouble("mobs.fox.attributes.max_health", foxMaxHealth);
     }
 
     public boolean ghastRidable = false;
     public boolean ghastRidableInWater = false;
     public double ghastMaxY = 256D;
+    public double ghastMaxHealth = 10.0D;
     private void ghastSettings() {
         ghastRidable = getBoolean("mobs.ghast.ridable", ghastRidable);
         ghastRidableInWater = getBoolean("mobs.ghast.ridable-in-water", ghastRidableInWater);
         ghastMaxY = getDouble("mobs.ghast.ridable-max-y", ghastMaxY);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.ghast.attributes.max-health", ghastMaxHealth);
+            set("mobs.ghast.attributes.max-health", null);
+            set("mobs.ghast.attributes.max_health", oldValue);
+        }
+        ghastMaxHealth = getDouble("mobs.ghast.attributes.max_health", ghastMaxHealth);
     }
 
     public boolean giantRidable = false;
@@ -696,31 +854,68 @@ public class PurpurWorldConfig {
         giantHaveHostileAI = getBoolean("mobs.giant.have-hostile-ai", giantHaveHostileAI);
         if (PurpurConfig.version < 8) {
             double oldValue = getDouble("mobs.giant.max-health", giantMaxHealth);
-            set("mobs.giant.attributes.max-health", oldValue);
             set("mobs.giant.max-health", null);
+            set("mobs.giant.attributes.max_health", oldValue);
+        } else if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.giant.attributes.max-health", giantMaxHealth);
+            set("mobs.giant.attributes.max-health", null);
+            set("mobs.giant.attributes.max_health", oldValue);
         }
-        giantMaxHealth = getDouble("mobs.giant.attributes.max-health", giantMaxHealth);
+        giantMaxHealth = getDouble("mobs.giant.attributes.max_health", giantMaxHealth);
     }
 
     public boolean guardianRidable = false;
+    public double guardianMaxHealth = 30.0D;
     private void guardianSettings() {
         guardianRidable = getBoolean("mobs.guardian.ridable", guardianRidable);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.guardian.attributes.max-health", guardianMaxHealth);
+            set("mobs.guardian.attributes.max-health", null);
+            set("mobs.guardian.attributes.max_health", oldValue);
+        }
+        guardianMaxHealth = getDouble("mobs.guardian.attributes.max_health", guardianMaxHealth);
     }
 
     public boolean hoglinRidable = false;
     public boolean hoglinRidableInWater = false;
     public int hoglinBreedingTicks = 6000;
+    public double hoglinMaxHealth = 40.0D;
     private void hoglinSettings() {
         hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable);
         hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater);
         hoglinBreedingTicks = getInt("mobs.hoglin.breeding-delay-ticks", hoglinBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.hoglin.attributes.max-health", hoglinMaxHealth);
+            set("mobs.hoglin.attributes.max-health", null);
+            set("mobs.hoglin.attributes.max_health", oldValue);
+        }
+        hoglinMaxHealth = getDouble("mobs.hoglin.attributes.max_health", hoglinMaxHealth);
     }
 
     public boolean horseRidableInWater = false;
     public int horseBreedingTicks = 6000;
+    public double horseMaxHealthMin = 15.0D;
+    public double horseMaxHealthMax = 30.0D;
+    public double horseJumpStrengthMin = 0.4D;
+    public double horseJumpStrengthMax = 1.0D;
+    public double horseMovementSpeedMin = 0.1125D;
+    public double horseMovementSpeedMax = 0.3375D;
     private void horseSettings() {
         horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater);
         horseBreedingTicks = getInt("mobs.horse.breeding-delay-ticks", horseBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldMin = getDouble("mobs.horse.attributes.max-health.min", horseMaxHealthMin);
+            double oldMax = getDouble("mobs.horse.attributes.max-health.max", horseMaxHealthMax);
+            set("mobs.horse.attributes.max-health", null);
+            set("mobs.horse.attributes.max_health.min", oldMin);
+            set("mobs.horse.attributes.max_health.max", oldMax);
+        }
+        horseMaxHealthMin = getDouble("mobs.horse.attributes.max_health.min", horseMaxHealthMin);
+        horseMaxHealthMax = getDouble("mobs.horse.attributes.max_health.max", horseMaxHealthMax);
+        horseJumpStrengthMin = getDouble("mobs.horse.attributes.jump_strength.min", horseJumpStrengthMin);
+        horseJumpStrengthMax = getDouble("mobs.horse.attributes.jump_strength.max", horseJumpStrengthMax);
+        horseMovementSpeedMin = getDouble("mobs.horse.attributes.movement_speed.min", horseMovementSpeedMin);
+        horseMovementSpeedMax = getDouble("mobs.horse.attributes.movement_speed.max", horseMovementSpeedMax);
     }
 
     public boolean huskRidable = false;
@@ -728,12 +923,21 @@ public class PurpurWorldConfig {
     public boolean huskJockeyOnlyBaby = true;
     public double huskJockeyChance = 0.05D;
     public boolean huskJockeyTryExistingChickens = true;
+    public double huskMaxHealth = 20.0D;
+    public double huskSpawnReinforcements = 0.1D;
     private void huskSettings() {
         huskRidable = getBoolean("mobs.husk.ridable", huskRidable);
         huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater);
         huskJockeyOnlyBaby = getBoolean("mobs.husk.jockey.only-babies", huskJockeyOnlyBaby);
         huskJockeyChance = getDouble("mobs.husk.jockey.chance", huskJockeyChance);
         huskJockeyTryExistingChickens = getBoolean("mobs.husk.jockey.try-existing-chickens", huskJockeyTryExistingChickens);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.husk.attributes.max-health", huskMaxHealth);
+            set("mobs.husk.attributes.max-health", null);
+            set("mobs.husk.attributes.max_health", oldValue);
+        }
+        huskMaxHealth = getDouble("mobs.husk.attributes.max_health", huskMaxHealth);
+        huskSpawnReinforcements = getDouble("mobs.husk.attributes.spawn_reinforcements", huskSpawnReinforcements);
     }
 
     public boolean illusionerRidable = false;
@@ -748,85 +952,188 @@ public class PurpurWorldConfig {
         illusionerFollowRange = getDouble("mobs.illusioner.follow-range", illusionerFollowRange);
         if (PurpurConfig.version < 8) {
             double oldValue = getDouble("mobs.illusioner.max-health", illusionerMaxHealth);
-            set("mobs.illusioner.attributes.max-health", oldValue);
             set("mobs.illusioner.max-health", null);
+            set("mobs.illusioner.attributes.max_health", oldValue);
+        } else if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.illusioner.attributes.max-health", illusionerMaxHealth);
+            set("mobs.illusioner.attributes.max-health", null);
+            set("mobs.illusioner.attributes.max_health", oldValue);
         }
-        illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max-health", illusionerMaxHealth);
+        illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max_health", illusionerMaxHealth);
     }
 
     public boolean ironGolemRidable = false;
     public boolean ironGolemRidableInWater = false;
     public boolean ironGolemCanSwim = false;
+    public double ironGolemMaxHealth = 100.0D;
     private void ironGolemSettings() {
         ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable);
         ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater);
         ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.iron_golem.attributes.max-health", ironGolemMaxHealth);
+            set("mobs.iron_golem.attributes.max-health", null);
+            set("mobs.iron_golem.attributes.max_health", oldValue);
+        }
+        ironGolemMaxHealth = getDouble("mobs.iron_golem.attributes.max_health", ironGolemMaxHealth);
     }
 
     public boolean llamaRidable = false;
     public boolean llamaRidableInWater = false;
     public int llamaBreedingTicks = 6000;
+    public double llamaMaxHealthMin = 15.0D;
+    public double llamaMaxHealthMax = 30.0D;
+    public double llamaJumpStrengthMin = 0.5D;
+    public double llamaJumpStrengthMax = 0.5D;
+    public double llamaMovementSpeedMin = 0.175D;
+    public double llamaMovementSpeedMax = 0.175D;
     private void llamaSettings() {
         llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable);
         llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater);
         llamaBreedingTicks = getInt("mobs.llama.breeding-delay-ticks", llamaBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldMin = getDouble("mobs.llama.attributes.max-health.min", llamaMaxHealthMin);
+            double oldMax = getDouble("mobs.llama.attributes.max-health.max", llamaMaxHealthMax);
+            set("mobs.llama.attributes.max-health", null);
+            set("mobs.llama.attributes.max_health.min", oldMin);
+            set("mobs.llama.attributes.max_health.max", oldMax);
+        }
+        llamaMaxHealthMin = getDouble("mobs.llama.attributes.max_health.min", llamaMaxHealthMin);
+        llamaMaxHealthMax = getDouble("mobs.llama.attributes.max_health.max", llamaMaxHealthMax);
+        llamaJumpStrengthMin = getDouble("mobs.llama.attributes.jump_strength.min", llamaJumpStrengthMin);
+        llamaJumpStrengthMax = getDouble("mobs.llama.attributes.jump_strength.max", llamaJumpStrengthMax);
+        llamaMovementSpeedMin = getDouble("mobs.llama.attributes.movement_speed.min", llamaMovementSpeedMin);
+        llamaMovementSpeedMax = getDouble("mobs.llama.attributes.movement_speed.max", llamaMovementSpeedMax);
     }
 
     public boolean llamaTraderRidable = false;
     public boolean llamaTraderRidableInWater = false;
+    public double llamaTraderMaxHealthMin = 15.0D;
+    public double llamaTraderMaxHealthMax = 30.0D;
+    public double llamaTraderJumpStrengthMin = 0.5D;
+    public double llamaTraderJumpStrengthMax = 0.5D;
+    public double llamaTraderMovementSpeedMin = 0.175D;
+    public double llamaTraderMovementSpeedMax = 0.175D;
     private void llamaTraderSettings() {
         llamaTraderRidable = getBoolean("mobs.trader_llama.ridable", llamaTraderRidable);
         llamaTraderRidableInWater = getBoolean("mobs.trader_llama.ridable-in-water", llamaTraderRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldMin = getDouble("mobs.trader_llama.attributes.max-health.min", llamaTraderMaxHealthMin);
+            double oldMax = getDouble("mobs.trader_llama.attributes.max-health.max", llamaTraderMaxHealthMax);
+            set("mobs.trader_llama.attributes.max-health", null);
+            set("mobs.trader_llama.attributes.max_health.min", oldMin);
+            set("mobs.trader_llama.attributes.max_health.max", oldMax);
+        }
+        llamaTraderMaxHealthMin = getDouble("mobs.trader_llama.attributes.max_health.min", llamaTraderMaxHealthMin);
+        llamaTraderMaxHealthMax = getDouble("mobs.trader_llama.attributes.max_health.max", llamaTraderMaxHealthMax);
+        llamaTraderJumpStrengthMin = getDouble("mobs.trader_llama.attributes.jump_strength.min", llamaTraderJumpStrengthMin);
+        llamaTraderJumpStrengthMax = getDouble("mobs.trader_llama.attributes.jump_strength.max", llamaTraderJumpStrengthMax);
+        llamaTraderMovementSpeedMin = getDouble("mobs.trader_llama.attributes.movement_speed.min", llamaTraderMovementSpeedMin);
+        llamaTraderMovementSpeedMax = getDouble("mobs.trader_llama.attributes.movement_speed.max", llamaTraderMovementSpeedMax);
     }
 
     public boolean magmaCubeRidable = false;
     public boolean magmaCubeRidableInWater = false;
+    public String magmaCubeMaxHealth = "size * size";
     private void magmaCubeSettings() {
         magmaCubeRidable = getBoolean("mobs.magma_cube.ridable", magmaCubeRidable);
         magmaCubeRidableInWater = getBoolean("mobs.magma_cube.ridable-in-water", magmaCubeRidableInWater);
+        if (PurpurConfig.version < 10) {
+            String oldValue = getString("mobs.magma_cube.attributes.max-health", magmaCubeMaxHealth);
+            set("mobs.magma_cube.attributes.max-health", null);
+            set("mobs.magma_cube.attributes.max_health", oldValue);
+        }
+        magmaCubeMaxHealth = getString("mobs.magma_cube.attributes.max_health", magmaCubeMaxHealth);
     }
 
     public boolean mooshroomRidable = false;
     public boolean mooshroomRidableInWater = false;
     public int mooshroomBreedingTicks = 6000;
+    public double mooshroomMaxHealth = 10.0D;
     private void mooshroomSettings() {
         mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable);
         mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater);
         mooshroomBreedingTicks = getInt("mobs.mooshroom.breeding-delay-ticks", mooshroomBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.mooshroom.attributes.max-health", mooshroomMaxHealth);
+            set("mobs.mooshroom.attributes.max-health", null);
+            set("mobs.mooshroom.attributes.max_health", oldValue);
+        }
+        mooshroomMaxHealth = getDouble("mobs.mooshroom.attributes.max_health", mooshroomMaxHealth);
     }
 
     public boolean muleRidableInWater = false;
     public int muleBreedingTicks = 6000;
+    public double muleMaxHealthMin = 15.0D;
+    public double muleMaxHealthMax = 30.0D;
+    public double muleJumpStrengthMin = 0.5D;
+    public double muleJumpStrengthMax = 0.5D;
+    public double muleMovementSpeedMin = 0.175D;
+    public double muleMovementSpeedMax = 0.175D;
     private void muleSettings() {
         muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater);
         muleBreedingTicks = getInt("mobs.mule.breeding-delay-ticks", muleBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldMin = getDouble("mobs.mule.attributes.max-health.min", muleMaxHealthMin);
+            double oldMax = getDouble("mobs.mule.attributes.max-health.max", muleMaxHealthMax);
+            set("mobs.mule.attributes.max-health", null);
+            set("mobs.mule.attributes.max_health.min", oldMin);
+            set("mobs.mule.attributes.max_health.max", oldMax);
+        }
+        muleMaxHealthMin = getDouble("mobs.mule.attributes.max_health.min", muleMaxHealthMin);
+        muleMaxHealthMax = getDouble("mobs.mule.attributes.max_health.max", muleMaxHealthMax);
+        muleJumpStrengthMin = getDouble("mobs.mule.attributes.jump_strength.min", muleJumpStrengthMin);
+        muleJumpStrengthMax = getDouble("mobs.mule.attributes.jump_strength.max", muleJumpStrengthMax);
+        muleMovementSpeedMin = getDouble("mobs.mule.attributes.movement_speed.min", muleMovementSpeedMin);
+        muleMovementSpeedMax = getDouble("mobs.mule.attributes.movement_speed.max", muleMovementSpeedMax);
     }
 
     public boolean ocelotRidable = false;
     public boolean ocelotRidableInWater = false;
     public int ocelotBreedingTicks = 6000;
+    public double ocelotMaxHealth = 10.0D;
     private void ocelotSettings() {
         ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable);
         ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater);
         ocelotBreedingTicks = getInt("mobs.ocelot.breeding-delay-ticks", ocelotBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.ocelot.attributes.max-health", ocelotMaxHealth);
+            set("mobs.ocelot.attributes.max-health", null);
+            set("mobs.ocelot.attributes.max_health", oldValue);
+        }
+        ocelotMaxHealth = getDouble("mobs.ocelot.attributes.max_health", ocelotMaxHealth);
     }
 
     public boolean pandaRidable = false;
     public boolean pandaRidableInWater = false;
     public int pandaBreedingTicks = 6000;
+    public double pandaMaxHealth = 20.0D;
     private void pandaSettings() {
         pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable);
         pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater);
         pandaBreedingTicks = getInt("mobs.panda.breeding-delay-ticks", pandaBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.panda.attributes.max-health", pandaMaxHealth);
+            set("mobs.panda.attributes.max-health", null);
+            set("mobs.panda.attributes.max_health", oldValue);
+        }
+        pandaMaxHealth = getDouble("mobs.panda.attributes.max_health", pandaMaxHealth);
     }
 
     public boolean parrotRidable = false;
     public boolean parrotRidableInWater = false;
     public double parrotMaxY = 256D;
+    public double parrotMaxHealth = 6.0D;
     private void parrotSettings() {
         parrotRidable = getBoolean("mobs.parrot.ridable", parrotRidable);
         parrotRidableInWater = getBoolean("mobs.parrot.ridable-in-water", parrotRidableInWater);
         parrotMaxY = getDouble("mobs.parrot.ridable-max-y", parrotMaxY);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.parrot.attributes.max-health", parrotMaxHealth);
+            set("mobs.parrot.attributes.max-health", null);
+            set("mobs.parrot.attributes.max_health", oldValue);
+        }
+        parrotMaxHealth = getDouble("mobs.parrot.attributes.max_health", parrotMaxHealth);
     }
 
     public boolean phantomRidable = false;
@@ -853,6 +1160,7 @@ public class PurpurWorldConfig {
     public boolean phantomIgnorePlayersWithTorch = false;
     public boolean phantomBurnInDaylight = true;
     public boolean phantomAllowGriefing = false;
+    public double phantomMaxHealth = 20.0D;
     private void phantomSettings() {
         phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable);
         phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater);
@@ -878,38 +1186,72 @@ public class PurpurWorldConfig {
         phantomBurnInDaylight = getBoolean("mobs.phantom.burn-in-daylight", phantomBurnInDaylight);
         phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch);
         phantomAllowGriefing = getBoolean("mobs.phantom.allow-griefing", phantomAllowGriefing);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.phantom.attributes.max-health", phantomMaxHealth);
+            set("mobs.phantom.attributes.max-health", null);
+            set("mobs.phantom.attributes.max_health", oldValue);
+        }
+        phantomMaxHealth = getDouble("mobs.phantom.attributes.max_health", phantomMaxHealth);
     }
 
     public boolean pigRidable = false;
     public boolean pigRidableInWater = false;
     public boolean pigGiveSaddleBack = false;
     public int pigBreedingTicks = 6000;
+    public double pigMaxHealth = 10.0D;
     private void pigSettings() {
         pigRidable = getBoolean("mobs.pig.ridable", pigRidable);
         pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater);
         pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack);
         pigBreedingTicks = getInt("mobs.pig.breeding-delay-ticks", pigBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.pig.attributes.max-health", pigMaxHealth);
+            set("mobs.pig.attributes.max-health", null);
+            set("mobs.pig.attributes.max_health", oldValue);
+        }
+        pigMaxHealth = getDouble("mobs.pig.attributes.max_health", pigMaxHealth);
     }
 
     public boolean piglinRidable = false;
     public boolean piglinRidableInWater = false;
+    public double piglinMaxHealth = 16.0D;
     private void piglinSettings() {
         piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable);
         piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.piglin.attributes.max-health", piglinMaxHealth);
+            set("mobs.piglin.attributes.max-health", null);
+            set("mobs.piglin.attributes.max_health", oldValue);
+        }
+        piglinMaxHealth = getDouble("mobs.piglin.attributes.max_health", piglinMaxHealth);
     }
 
     public boolean piglinBruteRidable = false;
     public boolean piglinBruteRidableInWater = false;
+    public double piglinBruteMaxHealth = 50.0D;
     private void piglinBruteSettings() {
         piglinBruteRidable = getBoolean("mobs.piglin_brute.ridable", piglinBruteRidable);
         piglinBruteRidableInWater = getBoolean("mobs.piglin_brute.ridable-in-water", piglinBruteRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.piglin_brute.attributes.max-health", piglinBruteMaxHealth);
+            set("mobs.piglin_brute.attributes.max-health", null);
+            set("mobs.piglin_brute.attributes.max_health", oldValue);
+        }
+        piglinBruteMaxHealth = getDouble("mobs.piglin_brute.attributes.max_health", piglinBruteMaxHealth);
     }
 
     public boolean pillagerRidable = false;
     public boolean pillagerRidableInWater = false;
+    public double pillagerMaxHealth = 24.0D;
     private void pillagerSettings() {
         pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable);
         pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.pillager.attributes.max-health", pillagerMaxHealth);
+            set("mobs.pillager.attributes.max-health", null);
+            set("mobs.pillager.attributes.max_health", oldValue);
+        }
+        pillagerMaxHealth = getDouble("mobs.pillager.attributes.max_health", pillagerMaxHealth);
     }
 
     public boolean polarBearRidable = false;
@@ -917,6 +1259,7 @@ public class PurpurWorldConfig {
     public String polarBearBreedableItemString = "";
     public Item polarBearBreedableItem = null;
     public int polarBearBreedingTicks = 6000;
+    public double polarBearMaxHealth = 30.0D;
     private void polarBearSettings() {
         polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable);
         polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater);
@@ -924,11 +1267,24 @@ public class PurpurWorldConfig {
         Item item = IRegistry.ITEM.get(new MinecraftKey(polarBearBreedableItemString));
         if (item != Items.AIR) polarBearBreedableItem = item;
         polarBearBreedingTicks = getInt("mobs.polar_bear.breeding-delay-ticks", polarBearBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.polar_bear.attributes.max-health", polarBearMaxHealth);
+            set("mobs.polar_bear.attributes.max-health", null);
+            set("mobs.polar_bear.attributes.max_health", oldValue);
+        }
+        polarBearMaxHealth = getDouble("mobs.polar_bear.attributes.max_health", polarBearMaxHealth);
     }
 
     public boolean pufferfishRidable = false;
+    public double pufferfishMaxHealth = 3.0D;
     private void pufferfishSettings() {
         pufferfishRidable = getBoolean("mobs.pufferfish.ridable", pufferfishRidable);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.pufferfish.attributes.max-health", pufferfishMaxHealth);
+            set("mobs.pufferfish.attributes.max-health", null);
+            set("mobs.pufferfish.attributes.max_health", oldValue);
+        }
+        pufferfishMaxHealth = getDouble("mobs.pufferfish.attributes.max_health", pufferfishMaxHealth);
     }
 
     public boolean rabbitRidable = false;
@@ -936,68 +1292,144 @@ public class PurpurWorldConfig {
     public double rabbitNaturalToast = 0.0D;
     public double rabbitNaturalKiller = 0.0D;
     public int rabbitBreedingTicks = 6000;
+    public double rabbitMaxHealth = 3.0D;
     private void rabbitSettings() {
         rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable);
         rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater);
         rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast);
         rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller);
         rabbitBreedingTicks = getInt("mobs.rabbit.breeding-delay-ticks", rabbitBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.rabbit.attributes.max-health", rabbitMaxHealth);
+            set("mobs.rabbit.attributes.max-health", null);
+            set("mobs.rabbit.attributes.max_health", oldValue);
+        }
+        rabbitMaxHealth = getDouble("mobs.rabbit.attributes.max_health", rabbitMaxHealth);
     }
 
     public boolean ravagerRidable = false;
     public boolean ravagerRidableInWater = false;
+    public double ravagerMaxHealth = 100.0D;
     private void ravagerSettings() {
         ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable);
         ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.ravager.attributes.max-health", ravagerMaxHealth);
+            set("mobs.ravager.attributes.max-health", null);
+            set("mobs.ravager.attributes.max_health", oldValue);
+        }
+        ravagerMaxHealth = getDouble("mobs.ravager.attributes.max_health", ravagerMaxHealth);
     }
 
     public boolean salmonRidable = false;
+    public double salmonMaxHealth = 3.0D;
     private void salmonSettings() {
         salmonRidable = getBoolean("mobs.salmon.ridable", salmonRidable);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.salmon.attributes.max-health", salmonMaxHealth);
+            set("mobs.salmon.attributes.max-health", null);
+            set("mobs.salmon.attributes.max_health", oldValue);
+        }
+        salmonMaxHealth = getDouble("mobs.salmon.attributes.max_health", salmonMaxHealth);
     }
 
     public boolean sheepRidable = false;
     public boolean sheepRidableInWater = false;
     public int sheepBreedingTicks = 6000;
+    public double sheepMaxHealth = 8.0D;
     private void sheepSettings() {
         sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable);
         sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater);
         sheepBreedingTicks = getInt("mobs.sheep.breeding-delay-ticks", sheepBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.sheep.attributes.max-health", sheepMaxHealth);
+            set("mobs.sheep.attributes.max-health", null);
+            set("mobs.sheep.attributes.max_health", oldValue);
+        }
+        sheepMaxHealth = getDouble("mobs.sheep.attributes.max_health", sheepMaxHealth);
     }
 
     public boolean shulkerRidable = false;
     public boolean shulkerRidableInWater = false;
+    public double shulkerMaxHealth = 30.0D;
     private void shulkerSettings() {
         shulkerRidable = getBoolean("mobs.shulker.ridable", shulkerRidable);
         shulkerRidableInWater = getBoolean("mobs.shulker.ridable-in-water", shulkerRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.shulker.attributes.max-health", shulkerMaxHealth);
+            set("mobs.shulker.attributes.max-health", null);
+            set("mobs.shulker.attributes.max_health", oldValue);
+        }
+        shulkerMaxHealth = getDouble("mobs.shulker.attributes.max_health", shulkerMaxHealth);
     }
 
     public boolean silverfishRidable = false;
     public boolean silverfishRidableInWater = false;
+    public double silverfishMaxHealth = 8.0D;
     private void silverfishSettings() {
         silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable);
         silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.silverfish.attributes.max-health", silverfishMaxHealth);
+            set("mobs.silverfish.attributes.max-health", null);
+            set("mobs.silverfish.attributes.max_health", oldValue);
+        }
+        silverfishMaxHealth = getDouble("mobs.silverfish.attributes.max_health", silverfishMaxHealth);
     }
 
     public boolean skeletonRidable = false;
     public boolean skeletonRidableInWater = false;
+    public double skeletonMaxHealth = 20.0D;
     private void skeletonSettings() {
         skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable);
         skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.skeleton.attributes.max-health", skeletonMaxHealth);
+            set("mobs.skeleton.attributes.max-health", null);
+            set("mobs.skeleton.attributes.max_health", oldValue);
+        }
+        skeletonMaxHealth = getDouble("mobs.skeleton.attributes.max_health", skeletonMaxHealth);
     }
 
     public boolean skeletonHorseCanSwim = false;
     public boolean skeletonHorseRidableInWater = true;
+    public double skeletonHorseMaxHealthMin = 15.0D;
+    public double skeletonHorseMaxHealthMax = 15.0D;
+    public double skeletonHorseJumpStrengthMin = 0.4D;
+    public double skeletonHorseJumpStrengthMax = 1.0D;
+    public double skeletonHorseMovementSpeedMin = 0.2D;
+    public double skeletonHorseMovementSpeedMax = 0.2D;
     private void skeletonHorseSettings() {
         skeletonHorseCanSwim = getBoolean("mobs.skeleton_horse.can-swim", skeletonHorseCanSwim);
         skeletonHorseRidableInWater = getBoolean("mobs.skeleton_horse.ridable-in-water", skeletonHorseRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.skeleton_horse.attributes.max-health", skeletonHorseMaxHealthMin);
+            set("mobs.skeleton_horse.attributes.max-health", null);
+            set("mobs.skeleton_horse.attributes.max_health.min", oldValue);
+            set("mobs.skeleton_horse.attributes.max_health.max", oldValue);
+        }
+        skeletonHorseMaxHealthMin = getDouble("mobs.skeleton_horse.attributes.max_health.min", skeletonHorseMaxHealthMin);
+        skeletonHorseMaxHealthMax = getDouble("mobs.skeleton_horse.attributes.max_health.max", skeletonHorseMaxHealthMax);
+        skeletonHorseJumpStrengthMin = getDouble("mobs.skeleton_horse.attributes.jump_strength.min", skeletonHorseJumpStrengthMin);
+        skeletonHorseJumpStrengthMax = getDouble("mobs.skeleton_horse.attributes.jump_strength.max", skeletonHorseJumpStrengthMax);
+        skeletonHorseMovementSpeedMin = getDouble("mobs.skeleton_horse.attributes.movement_speed.min", skeletonHorseMovementSpeedMin);
+        skeletonHorseMovementSpeedMax = getDouble("mobs.skeleton_horse.attributes.movement_speed.max", skeletonHorseMovementSpeedMax);
     }
 
     public boolean slimeRidable = false;
     public boolean slimeRidableInWater = false;
+    public String slimeMaxHealth = "size * size";
+    public Map<Integer, Double> slimeMaxHealthCache = new HashMap<>();
     private void slimeSettings() {
         slimeRidable = getBoolean("mobs.slime.ridable", slimeRidable);
         slimeRidableInWater = getBoolean("mobs.slime.ridable-in-water", slimeRidableInWater);
+        if (PurpurConfig.version < 10) {
+            String oldValue = getString("mobs.slime.attributes.max-health", slimeMaxHealth);
+            set("mobs.slime.attributes.max-health", null);
+            set("mobs.slime.attributes.max_health", oldValue);
+        }
+        slimeMaxHealth = getString("mobs.slime.attributes.max_health", slimeMaxHealth);
+        slimeMaxHealthCache.clear();
     }
 
     public boolean snowGolemRidable = false;
@@ -1009,6 +1441,7 @@ public class PurpurWorldConfig {
     public int snowGolemSnowBallMax = 20;
     public float snowGolemSnowBallModifier = 10.0F;
     public double snowGolemAttackDistance = 1.25D;
+    public double snowGolemMaxHealth = 4.0D;
     private void snowGolemSettings() {
         snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable);
         snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater);
@@ -1019,63 +1452,118 @@ public class PurpurWorldConfig {
         snowGolemSnowBallMax = getInt("mobs.snow_golem.max-shoot-interval-ticks", snowGolemSnowBallMax);
         snowGolemSnowBallModifier = (float) getDouble("mobs.snow_golem.snow-ball-modifier", snowGolemSnowBallModifier);
         snowGolemAttackDistance = getDouble("mobs.snow_golem.attack-distance", snowGolemAttackDistance);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.snow_golem.attributes.max-health", snowGolemMaxHealth);
+            set("mobs.snow_golem.attributes.max-health", null);
+            set("mobs.snow_golem.attributes.max_health", oldValue);
+        }
+        snowGolemMaxHealth = getDouble("mobs.snow_golem.attributes.max_health", snowGolemMaxHealth);
     }
 
     public boolean squidRidable = false;
     public boolean squidImmuneToEAR = true;
     public double squidOffsetWaterCheck = 0.0D;
     public boolean squidsCanFly = false;
+    public double squidMaxHealth = 10.0D;
     private void squidSettings() {
         squidRidable = getBoolean("mobs.squid.ridable", squidRidable);
         squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR);
         squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck);
         squidsCanFly = getBoolean("mobs.squid.can-fly", squidsCanFly);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.squid.attributes.max-health", squidMaxHealth);
+            set("mobs.squid.attributes.max-health", null);
+            set("mobs.squid.attributes.max_health", oldValue);
+        }
+        squidMaxHealth = getDouble("mobs.squid.attributes.max_health", squidMaxHealth);
     }
 
     public boolean spiderRidable = false;
     public boolean spiderRidableInWater = false;
+    public double spiderMaxHealth = 16.0D;
     private void spiderSettings() {
         spiderRidable = getBoolean("mobs.spider.ridable", spiderRidable);
         spiderRidableInWater = getBoolean("mobs.spider.ridable-in-water", spiderRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.spider.attributes.max-health", spiderMaxHealth);
+            set("mobs.spider.attributes.max-health", null);
+            set("mobs.spider.attributes.max_health", oldValue);
+        }
+        spiderMaxHealth = getDouble("mobs.spider.attributes.max_health", spiderMaxHealth);
     }
 
     public boolean strayRidable = false;
     public boolean strayRidableInWater = false;
+    public double strayMaxHealth = 20.0D;
     private void straySettings() {
         strayRidable = getBoolean("mobs.stray.ridable", strayRidable);
         strayRidableInWater = getBoolean("mobs.stray.ridable-in-water", strayRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.stray.attributes.max-health", strayMaxHealth);
+            set("mobs.stray.attributes.max-health", null);
+            set("mobs.stray.attributes.max_health", oldValue);
+        }
+        strayMaxHealth = getDouble("mobs.stray.attributes.max_health", strayMaxHealth);
     }
 
     public boolean striderRidable = false;
     public boolean striderRidableInWater = false;
     public int striderBreedingTicks = 6000;
+    public double striderMaxHealth = 20.0D;
     private void striderSettings() {
         striderRidable = getBoolean("mobs.strider.ridable", striderRidable);
         striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater);
         striderBreedingTicks = getInt("mobs.strider.breeding-delay-ticks", striderBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.strider.attributes.max-health", striderMaxHealth);
+            set("mobs.strider.attributes.max-health", null);
+            set("mobs.strider.attributes.max_health", oldValue);
+        }
+        striderMaxHealth = getDouble("mobs.strider.attributes.max_health", striderMaxHealth);
     }
 
     public boolean tropicalFishRidable = false;
+    public double tropicalFishMaxHealth = 3.0D;
     private void tropicalFishSettings() {
         tropicalFishRidable = getBoolean("mobs.tropical_fish.ridable", tropicalFishRidable);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.tropical_fish.attributes.max-health", tropicalFishMaxHealth);
+            set("mobs.tropical_fish.attributes.max-health", null);
+            set("mobs.tropical_fish.attributes.max_health", oldValue);
+        }
+        tropicalFishMaxHealth = getDouble("mobs.tropical_fish.attributes.max_health", tropicalFishMaxHealth);
     }
 
     public boolean turtleRidable = false;
     public boolean turtleRidableInWater = false;
     public int turtleBreedingTicks = 6000;
+    public double turtleMaxHealth = 30.0D;
     private void turtleSettings() {
         turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable);
         turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater);
         turtleBreedingTicks = getInt("mobs.turtle.breeding-delay-ticks", turtleBreedingTicks);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.turtle.attributes.max-health", turtleMaxHealth);
+            set("mobs.turtle.attributes.max-health", null);
+            set("mobs.turtle.attributes.max_health", oldValue);
+        }
+        turtleMaxHealth = getDouble("mobs.turtle.attributes.max_health", turtleMaxHealth);
     }
 
     public boolean vexRidable = false;
     public boolean vexRidableInWater = false;
     public double vexMaxY = 256D;
+    public double vexMaxHealth = 14.0D;
     private void vexSettings() {
         vexRidable = getBoolean("mobs.vex.ridable", vexRidable);
         vexRidableInWater = getBoolean("mobs.vex.ridable-in-water", vexRidableInWater);
         vexMaxY = getDouble("mobs.vex.ridable-max-y", vexMaxY);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.vex.attributes.max-health", vexMaxHealth);
+            set("mobs.vex.attributes.max-health", null);
+            set("mobs.vex.attributes.max_health", oldValue);
+        }
+        vexMaxHealth = getDouble("mobs.vex.attributes.max_health", vexMaxHealth);
     }
 
     public boolean villagerRidable = false;
@@ -1093,6 +1581,7 @@ public class PurpurWorldConfig {
     public int villagerLobotomizeCheck = 60;
     public boolean villagerClericsFarmWarts = false;
     public boolean villagerClericFarmersThrowWarts = true;
+    public double villagerMaxHealth = 20.0D;
     private void villagerSettings() {
         villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable);
         villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater);
@@ -1114,33 +1603,60 @@ public class PurpurWorldConfig {
         villagerLobotomizeCheck = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheck);
         villagerClericsFarmWarts = getBoolean("mobs.villager.clerics-farm-warts", villagerClericsFarmWarts);
         villagerClericFarmersThrowWarts = getBoolean("mobs.villager.cleric-wart-farmers-throw-warts-at-villagers", villagerClericFarmersThrowWarts);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.villager.attributes.max-health", villagerMaxHealth);
+            set("mobs.villager.attributes.max-health", null);
+            set("mobs.villager.attributes.max_health", oldValue);
+        }
+        villagerMaxHealth = getDouble("mobs.villager.attributes.max_health", villagerMaxHealth);
     }
 
     public boolean villagerTraderRidable = false;
     public boolean villagerTraderRidableInWater = false;
     public boolean villagerTraderCanBeLeashed = false;
     public boolean villagerTraderFollowEmeraldBlock = false;
+    public double villagerTraderMaxHealth = 20.0D;
     private void villagerTraderSettings() {
         villagerTraderRidable = getBoolean("mobs.wandering_trader.ridable", villagerTraderRidable);
         villagerTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", villagerTraderRidableInWater);
         villagerTraderCanBeLeashed = getBoolean("mobs.wandering_trader.can-be-leashed", villagerTraderCanBeLeashed);
         villagerTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", villagerTraderFollowEmeraldBlock);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.wandering_trader.attributes.max-health", villagerTraderMaxHealth);
+            set("mobs.wandering_trader.attributes.max-health", null);
+            set("mobs.wandering_trader.attributes.max_health", oldValue);
+        }
+        villagerTraderMaxHealth = getDouble("mobs.wandering_trader.attributes.max_health", villagerTraderMaxHealth);
     }
 
     public boolean vindicatorRidable = false;
     public boolean vindicatorRidableInWater = false;
     public double vindicatorJohnnySpawnChance = 0D;
+    public double vindicatorMaxHealth = 24.0D;
     private void vindicatorSettings() {
         vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable);
         vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater);
         vindicatorJohnnySpawnChance = getDouble("mobs.vindicator.johnny.spawn-chance", vindicatorJohnnySpawnChance);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.vindicator.attributes.max-health", vindicatorMaxHealth);
+            set("mobs.vindicator.attributes.max-health", null);
+            set("mobs.vindicator.attributes.max_health", oldValue);
+        }
+        vindicatorMaxHealth = getDouble("mobs.vindicator.attributes.max_health", vindicatorMaxHealth);
     }
 
     public boolean witchRidable = false;
     public boolean witchRidableInWater = false;
+    public double witchMaxHealth = 26.0D;
     private void witchSettings() {
         witchRidable = getBoolean("mobs.witch.ridable", witchRidable);
         witchRidableInWater = getBoolean("mobs.witch.ridable-in-water", witchRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.witch.attributes.max-health", witchMaxHealth);
+            set("mobs.witch.attributes.max-health", null);
+            set("mobs.witch.attributes.max_health", oldValue);
+        }
+        witchMaxHealth = getDouble("mobs.witch.attributes.max_health", witchMaxHealth);
     }
 
     public boolean witherRidable = false;
@@ -1157,19 +1673,30 @@ public class PurpurWorldConfig {
         witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay);
         if (PurpurConfig.version < 8) {
             double oldValue = getDouble("mobs.wither.max-health", witherMaxHealth);
+            set("mobs.wither.max_health", null);
             set("mobs.wither.attributes.max-health", oldValue);
-            set("mobs.wither.max-health", null);
+        } else if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.wither.attributes.max-health", witherMaxHealth);
+            set("mobs.wither.attributes.max-health", null);
+            set("mobs.wither.attributes.max_health", oldValue);
         }
-        witherMaxHealth = getDouble("mobs.wither.attributes.max-health", witherMaxHealth);
+        witherMaxHealth = getDouble("mobs.wither.attributes.max_health", witherMaxHealth);
     }
 
     public boolean witherSkeletonRidable = false;
     public boolean witherSkeletonRidableInWater = false;
     public boolean witherSkeletonTakesWitherDamage = false;
+    public double witherSkeletonMaxHealth = 20.0D;
     private void witherSkeletonSettings() {
         witherSkeletonRidable = getBoolean("mobs.wither_skeleton.ridable", witherSkeletonRidable);
         witherSkeletonRidableInWater = getBoolean("mobs.wither_skeleton.ridable-in-water", witherSkeletonRidableInWater);
         witherSkeletonTakesWitherDamage = getBoolean("mobs.wither_skeleton.takes-wither-damage", witherSkeletonTakesWitherDamage);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.wither_skeleton.attributes.max-health", witherSkeletonMaxHealth);
+            set("mobs.wither_skeleton.attributes.max-health", null);
+            set("mobs.wither_skeleton.attributes.max_health", oldValue);
+        }
+        witherSkeletonMaxHealth = getDouble("mobs.wither_skeleton.attributes.max_health", witherSkeletonMaxHealth);
     }
 
     public boolean wolfRidable = false;
@@ -1178,6 +1705,7 @@ public class PurpurWorldConfig {
     public boolean wolfMilkCuresRabies = true;
     public double wolfNaturalRabid = 0.0D;
     public int wolfBreedingTicks = 6000;
+    public double wolfMaxHealth = 8.0D;
     private void wolfSettings() {
         wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable);
         wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater);
@@ -1189,13 +1717,26 @@ public class PurpurWorldConfig {
         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);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.wolf.attributes.max-health", wolfMaxHealth);
+            set("mobs.wolf.attributes.max-health", null);
+            set("mobs.wolf.attributes.max_health", oldValue);
+        }
+        wolfMaxHealth = getDouble("mobs.wolf.attributes.max_health", wolfMaxHealth);
     }
 
     public boolean zoglinRidable = false;
     public boolean zoglinRidableInWater = false;
+    public double zoglinMaxHealth = 40.0D;
     private void zoglinSettings() {
         zoglinRidable = getBoolean("mobs.zoglin.ridable", zoglinRidable);
         zoglinRidableInWater = getBoolean("mobs.zoglin.ridable-in-water", zoglinRidableInWater);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.zoglin.attributes.max-health", zoglinMaxHealth);
+            set("mobs.zoglin.attributes.max-health", null);
+            set("mobs.zoglin.attributes.max_health", oldValue);
+        }
+        zoglinMaxHealth = getDouble("mobs.zoglin.attributes.max_health", zoglinMaxHealth);
     }
 
     public boolean zombieRidable = false;
@@ -1205,6 +1746,8 @@ public class PurpurWorldConfig {
     public boolean zombieJockeyTryExistingChickens = true;
     public boolean zombieAggressiveTowardsVillagerWhenLagging = true;
     public EnumDifficulty zombieBreakDoorMinDifficulty = EnumDifficulty.HARD;
+    public double zombieMaxHealth = 20.0D;
+    public double zombieSpawnReinforcements = 0.1D;
     private void zombieSettings() {
         zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable);
         zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater);
@@ -1217,15 +1760,40 @@ public class PurpurWorldConfig {
         } catch (IllegalArgumentException ignore) {
             zombieBreakDoorMinDifficulty = EnumDifficulty.HARD;
         }
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.zombie.attributes.max-health", zombieMaxHealth);
+            set("mobs.zombie.attributes.max-health", null);
+            set("mobs.zombie.attributes.max_health", oldValue);
+        }
+        zombieMaxHealth = getDouble("mobs.zombie.attributes.max_health", zombieMaxHealth);
+        zombieSpawnReinforcements = getDouble("mobs.zombie.attributes.spawn_reinforcements", zombieSpawnReinforcements);
     }
 
     public boolean zombieHorseCanSwim = false;
     public boolean zombieHorseRidableInWater = false;
     public double zombieHorseSpawnChance = 0.0D;
+    public double zombieHorseMaxHealthMin = 15.0D;
+    public double zombieHorseMaxHealthMax = 15.0D;
+    public double zombieHorseJumpStrengthMin = 0.4D;
+    public double zombieHorseJumpStrengthMax = 1.0D;
+    public double zombieHorseMovementSpeedMin = 0.2D;
+    public double zombieHorseMovementSpeedMax = 0.2D;
     private void zombieHorseSettings() {
         zombieHorseCanSwim = getBoolean("mobs.zombie_horse.can-swim", zombieHorseCanSwim);
         zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater);
         zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.zombie_horse.attributes.max-health", zombieHorseMaxHealthMin);
+            set("mobs.zombie_horse.attributes.max-health", null);
+            set("mobs.zombie_horse.attributes.max_health.min", oldValue);
+            set("mobs.zombie_horse.attributes.max_health.max", oldValue);
+        }
+        zombieHorseMaxHealthMin = getDouble("mobs.zombie_horse.attributes.max_health.min", zombieHorseMaxHealthMin);
+        zombieHorseMaxHealthMax = getDouble("mobs.zombie_horse.attributes.max_health.max", zombieHorseMaxHealthMax);
+        zombieHorseJumpStrengthMin = getDouble("mobs.zombie_horse.attributes.jump_strength.min", zombieHorseJumpStrengthMin);
+        zombieHorseJumpStrengthMax = getDouble("mobs.zombie_horse.attributes.jump_strength.max", zombieHorseJumpStrengthMax);
+        zombieHorseMovementSpeedMin = getDouble("mobs.zombie_horse.attributes.movement_speed.min", zombieHorseMovementSpeedMin);
+        zombieHorseMovementSpeedMax = getDouble("mobs.zombie_horse.attributes.movement_speed.max", zombieHorseMovementSpeedMax);
     }
 
     public boolean zombifiedPiglinRidable = false;
@@ -1234,6 +1802,8 @@ public class PurpurWorldConfig {
     public double zombifiedPiglinJockeyChance = 0.05D;
     public boolean zombifiedPiglinJockeyTryExistingChickens = true;
     public boolean zombifiedPiglinCountAsPlayerKillWhenAngry = true;
+    public double zombifiedPiglinMaxHealth = 20.0D;
+    public double zombifiedPiglinSpawnReinforcements = 0.0D;
     private void zombifiedPiglinSettings() {
         zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable);
         zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater);
@@ -1241,6 +1811,13 @@ public class PurpurWorldConfig {
         zombifiedPiglinJockeyChance = getDouble("mobs.zombified_piglin.jockey.chance", zombifiedPiglinJockeyChance);
         zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens);
         zombifiedPiglinCountAsPlayerKillWhenAngry = getBoolean("mobs.zombified_piglin.count-as-player-kill-when-angry", zombifiedPiglinCountAsPlayerKillWhenAngry);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.zombified_piglin.attributes.max-health", zombifiedPiglinMaxHealth);
+            set("mobs.zombified_piglin.attributes.max-health", null);
+            set("mobs.zombified_piglin.attributes.max_health", oldValue);
+        }
+        zombifiedPiglinMaxHealth = getDouble("mobs.zombified_piglin.attributes.max_health", zombifiedPiglinMaxHealth);
+        zombifiedPiglinSpawnReinforcements = getDouble("mobs.zombified_piglin.attributes.spawn_reinforcements", zombifiedPiglinSpawnReinforcements);
     }
 
     public boolean zombieVillagerRidable = false;
@@ -1248,11 +1825,20 @@ public class PurpurWorldConfig {
     public boolean zombieVillagerJockeyOnlyBaby = true;
     public double zombieVillagerJockeyChance = 0.05D;
     public boolean zombieVillagerJockeyTryExistingChickens = true;
+    public double zombieVillagerMaxHealth = 20.0D;
+    public double zombieVillagerSpawnReinforcements = 0.1D;
     private void zombieVillagerSettings() {
         zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable);
         zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater);
         zombieVillagerJockeyOnlyBaby = getBoolean("mobs.zombie_villager.jockey.only-babies", zombieVillagerJockeyOnlyBaby);
         zombieVillagerJockeyChance = getDouble("mobs.zombie_villager.jockey.chance", zombieVillagerJockeyChance);
         zombieVillagerJockeyTryExistingChickens = getBoolean("mobs.zombie_villager.jockey.try-existing-chickens", zombieVillagerJockeyTryExistingChickens);
+        if (PurpurConfig.version < 10) {
+            double oldValue = getDouble("mobs.zombie_villager.attributes.max-health", zombieVillagerMaxHealth);
+            set("mobs.zombie_villager.attributes.max-health", null);
+            set("mobs.zombie_villager.attributes.max_health", oldValue);
+        }
+        zombieVillagerMaxHealth = getDouble("mobs.zombie_villager.attributes.max_health", zombieVillagerMaxHealth);
+        zombieVillagerSpawnReinforcements = getDouble("mobs.zombie_villager.attributes.spawn_reinforcements", zombieVillagerSpawnReinforcements);
     }
 }
