--- a/net/minecraft/world/entity/animal/Turtle.java
+++ b/net/minecraft/world/entity/animal/Turtle.java
@@ -71,10 +_,10 @@
     private static final boolean DEFAULT_HAS_EGG = false;
     int layEggCounter;
     public static final TargetingConditions.Selector BABY_ON_LAND_SELECTOR = (entity, level) -> entity.isBaby() && !entity.isInWater();
-    BlockPos homePos = BlockPos.ZERO;
+    public BlockPos homePos = BlockPos.ZERO;
     @Nullable
     BlockPos travelPos;
-    boolean goingHome;
+    public boolean goingHome;
 
     public Turtle(EntityType<? extends Turtle> entityType, Level level) {
         super(entityType, level);
@@ -93,7 +_,7 @@
         return this.entityData.get(HAS_EGG);
     }
 
-    void setHasEgg(boolean hasEgg) {
+    public void setHasEgg(boolean hasEgg) {
         this.entityData.set(HAS_EGG, hasEgg);
     }
 
@@ -171,7 +_,7 @@
 
     @Nullable
     @Override
-    protected SoundEvent getAmbientSound() {
+    public SoundEvent getAmbientSound() {
         return !this.isInWater() && this.onGround() && !this.isBaby() ? SoundEvents.TURTLE_AMBIENT_LAND : super.getAmbientSound();
     }
 
@@ -181,19 +_,19 @@
     }
 
     @Override
-    protected SoundEvent getSwimSound() {
+    public SoundEvent getSwimSound() {
         return SoundEvents.TURTLE_SWIM;
     }
 
     @Nullable
     @Override
-    protected SoundEvent getHurtSound(DamageSource damageSource) {
+    public SoundEvent getHurtSound(DamageSource damageSource) {
         return this.isBaby() ? SoundEvents.TURTLE_HURT_BABY : SoundEvents.TURTLE_HURT;
     }
 
     @Nullable
     @Override
-    protected SoundEvent getDeathSound() {
+    public SoundEvent getDeathSound() {
         return this.isBaby() ? SoundEvents.TURTLE_DEATH_BABY : SoundEvents.TURTLE_DEATH;
     }
 
@@ -259,7 +_,9 @@
     protected void ageBoundaryReached() {
         super.ageBoundaryReached();
         if (!this.isBaby() && this.level() instanceof ServerLevel serverLevel && serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
+            this.forceDrops = true; // CraftBukkit
             this.spawnAtLocation(serverLevel, Items.TURTLE_SCUTE, 1);
+            this.forceDrops = false; // CraftBukkit
         }
     }
 
@@ -284,7 +_,7 @@
 
     @Override
     public void thunderHit(ServerLevel level, LightningBolt lightning) {
-        this.hurtServer(level, this.damageSources().lightningBolt(), Float.MAX_VALUE);
+        this.hurtServer(level, this.damageSources().lightningBolt().eventEntityDamager(lightning), Float.MAX_VALUE); // CraftBukkit // Paper - fix DamageSource API
     }
 
     @Override
@@ -311,6 +_,10 @@
             if (loveCause == null && this.partner.getLoveCause() != null) {
                 loveCause = this.partner.getLoveCause();
             }
+            // Paper start - Add EntityFertilizeEggEvent event
+            io.papermc.paper.event.entity.EntityFertilizeEggEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this.animal, this.partner);
+            if (event.isCancelled()) return;
+            // Paper end - Add EntityFertilizeEggEvent event
 
             if (loveCause != null) {
                 loveCause.awardStat(Stats.ANIMALS_BRED);
@@ -324,7 +_,7 @@
             this.partner.resetLove();
             RandomSource random = this.animal.getRandom();
             if (getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
-                this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), random.nextInt(7) + 1));
+                if (event.getExperience() > 0) this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), event.getExperience(), org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, loveCause)); // Paper - Add EntityFertilizeEggEvent event
             }
         }
     }
@@ -347,7 +_,7 @@
                 && (
                     this.turtle.hasEgg()
                         || this.turtle.getRandom().nextInt(reducedTickDelay(700)) == 0 && !this.turtle.homePos.closerToCenterThan(this.turtle.position(), 64.0)
-                );
+                ) && new com.destroystokyo.paper.event.entity.TurtleGoHomeEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity()).callEvent(); // Paper - Turtle API
         }
 
         @Override
@@ -455,14 +_,20 @@
             BlockPos blockPos = this.turtle.blockPosition();
             if (!this.turtle.isInWater() && this.isReachedTarget()) {
                 if (this.turtle.layEggCounter < 1) {
-                    this.turtle.setLayingEgg(true);
+                    this.turtle.setLayingEgg(new com.destroystokyo.paper.event.entity.TurtleStartDiggingEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.blockPos, this.turtle.level())).callEvent()); // Paper - Turtle API
                 } else if (this.turtle.layEggCounter > this.adjustedTickDelay(200)) {
+                    // Paper start - Turtle API
+                    int eggCount = this.turtle.random.nextInt(4) + 1;
+                    com.destroystokyo.paper.event.entity.TurtleLayEggEvent layEggEvent = new com.destroystokyo.paper.event.entity.TurtleLayEggEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.blockPos.above(), this.turtle.level()), eggCount);
+                    if (layEggEvent.callEvent() && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount()))) {
+                    // Paper end - Turtle API
                     Level level = this.turtle.level();
                     level.playSound(null, blockPos, SoundEvents.TURTLE_LAY_EGG, SoundSource.BLOCKS, 0.3F, 0.9F + level.random.nextFloat() * 0.2F);
                     BlockPos blockPos1 = this.blockPos.above();
-                    BlockState blockState = Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1);
+                    BlockState blockState = Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount()); // Paper
                     level.setBlock(blockPos1, blockState, 3);
                     level.gameEvent(GameEvent.BLOCK_PLACE, blockPos1, GameEvent.Context.of(this.turtle, blockState));
+                    } // CraftBukkit
                     this.turtle.setHasEgg(false);
                     this.turtle.setLayingEgg(false);
                     this.turtle.setInLoveTime(600);
