Repository: DragonSurvivalTeam/DragonSurvival
Pull request #838: Modify dragon-growth command to allow modifying growth in addition to setting growth
Author: login: Oblivire
Created: 2025-05-23T03:01:15Z | Merged: 2025-05-27T21:52:23Z

This changes the dragon-growth command to have an 'add' and a 'sub' option with an amount definable after the option that determines how much it should add/sub by.

Please give suggestions on this, I'm not really sure how to maintain backwards compatibility for anything using this command other than:
- Replacing the DragonGrowthArgument with a DoubleArgumentType
- Removing the min/max limits on the DragonGrowthArgument
- Or just making a totally separate command.

If backwards compatibility isn't required, I'd probably move the add/sub options to immediately after dragon-growth, so then the syntax would be /dragon-growth <set/add/sub> \<players\> \<amount\>


Diff:
diff --git a/src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/AbilityEntityEffect.java b/src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/AbilityEntityEffect.java
index fcdb458ea..a51d0fd47 100644
--- a/src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/AbilityEntityEffect.java
+++ b/src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/AbilityEntityEffect.java
@@ -78,6 +78,7 @@ static void registerEntries(final RegisterEvent event) {
             event.register(REGISTRY_KEY, DragonSurvival.res("hunger"), () -> HungerEffect.CODEC);
             event.register(REGISTRY_KEY, DragonSurvival.res("effect_removal"), () -> MobEffectRemovalEffect.CODEC);
             event.register(REGISTRY_KEY, DragonSurvival.res("use_item"), () -> UseItemOnLivingEntityEffect.CODEC);
+            event.register(REGISTRY_KEY, DragonSurvival.res("dragon_growth"), () -> DragonGrowthEffect.CODEC);
         }
     }
 }
diff --git a/src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java b/src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
new file mode 100644
index 000000000..0e0fdcda5
--- /dev/null
+++ b/src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
@@ -0,0 +1,104 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.MiscCodecs;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.stage.DragonStage;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.core.Holder;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, DragonGrowthEffect.ActionType action_type, LevelBasedValue amount, LevelBasedValue probability) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            ActionType.CODEC.fieldOf("action_type").forGetter(DragonGrowthEffect::action_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
+                return;
+            }
+
+            // If FLAT, difference = amount
+            // If PERCENT, difference = percentage mapped to current stage
+            // If ADD, base = current growth
+            // If SET and FLAT, base = 0
+            // If SET and PERCENT, base = min size of current stage
+            double amount = amount().calculate(ability.level());
+            double base = 0;
+            double difference = amount;
+            if (growth_type == GrowthType.ADD) {
+                base = handler.getGrowth();
+            }
+            if (action_type == ActionType.PERCENT) {
+                Holder<DragonStage> dragonStage = handler.stage();
+                MiscCodecs.Bounds growthRange = dragonStage.value().growthRange();
+                double maxSize = growthRange.max();
+                double minSize = growthRange.min();
+                // Maybe get maximum overall size instead of the current stage?
+                difference = amount * (maxSize - minSize);
+                if (growth_type == GrowthType.SET) {
+                    base = minSize;
+                }
+            }
+
+
+            handler.setDesiredGrowth(targetPlayer, (base + difference));
+        }
+    }
+
+    public enum GrowthType implements StringRepresentable {
+        SET("set"), ADD("add");
+
+        public static final Codec<DragonGrowthEffect.GrowthType> CODEC = StringRepresentable.fromEnum(DragonGrowthEffect.GrowthType::values);
+        private final String name;
+
+        GrowthType(final String name) {
+            this.name = name;
+        }
+
+        @Override
+        public @NotNull String getSerializedName() {
+            return name;
+        }
+    }
+
+    public enum ActionType implements StringRepresentable {
+        PERCENT("percent"), FLAT("flat");
+
+        public static final Codec<DragonGrowthEffect.ActionType> CODEC = StringRepresentable.fromEnum(DragonGrowthEffect.ActionType::values);
+        private final String name;
+
+        ActionType(final String name) {
+            this.name = name;
+        }
+
+        @Override
+        public @NotNull String getSerializedName() {
+            return name;
+        }
+    }
+
+    @Override
+    public MapCodec<? extends AbilityEntityEffect> entityCodec() {
+        return CODEC;
+    }
+}


Reviews:
user: login: SiverDX
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-23T17:51:24Z
user: login: Oblivire
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-23T18:59:03Z
user: login: Psither
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-23T21:54:41Z
user: login: Psither
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-23T21:57:24Z
user: login: Oblivire
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-24T01:35:57Z
user: login: Oblivire
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-24T01:37:44Z
user: login: Oblivire
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-24T01:40:22Z
user: login: Psither
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-24T18:10:03Z
user: login: Oblivire
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-24T18:52:53Z
user: login: Psither
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-24T18:54:29Z
user: login: Oblivire
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-24T19:01:50Z
user: login: Oblivire
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-24T20:58:02Z
user: login: Psither
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-24T22:31:28Z
user: login: Psither
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-26T17:39:47Z
user: login: SiverDX
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-27T16:15:42Z
user: login: Oblivire
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-27T21:44:41Z

Review comments:
diff_hunk: @@ -0,0 +1,91 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.BlockVision;
+import by.dragonsurvivalteam.dragonsurvival.registry.DSAttributes;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.Translation;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.lang.LangKey;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.util.DSColors;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.advancements.critereon.EntityPredicate;
+import net.minecraft.core.Holder;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.damagesource.DamageType;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Optional;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, LevelBasedValue amount, LevelBasedValue probability, Optional<EntityPredicate> validEntities) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability),
+            EntityPredicate.CODEC.optionalFieldOf("valid_entities").forGetter(DragonGrowthEffect::validEntities)
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: SiverDX
body: i don't think this is needed since the targeting of the ability already determines which entities are affected by the ability effects
created_at: 2025-05-23T17:51:24Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,91 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.BlockVision;
+import by.dragonsurvivalteam.dragonsurvival.registry.DSAttributes;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.Translation;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.lang.LangKey;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.util.DSColors;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.advancements.critereon.EntityPredicate;
+import net.minecraft.core.Holder;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.damagesource.DamageType;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Optional;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, LevelBasedValue amount, LevelBasedValue probability, Optional<EntityPredicate> validEntities) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability),
+            EntityPredicate.CODEC.optionalFieldOf("valid_entities").forGetter(DragonGrowthEffect::validEntities)
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Oblivire
body: That's true.
I didn't realize that the targeting had a full predicate, I thought it was just allies/enemies/neutral.

Will remove when I'm next able, thank you!
created_at: 2025-05-23T18:59:03Z
author_association: NONE
diff_hunk: @@ -0,0 +1,91 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.BlockVision;
+import by.dragonsurvivalteam.dragonsurvival.registry.DSAttributes;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.Translation;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.lang.LangKey;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.util.DSColors;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.advancements.critereon.EntityPredicate;
+import net.minecraft.core.Holder;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.damagesource.DamageType;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Optional;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, LevelBasedValue amount, LevelBasedValue probability, Optional<EntityPredicate> validEntities) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability),
+            EntityPredicate.CODEC.optionalFieldOf("valid_entities").forGetter(DragonGrowthEffect::validEntities)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Psither
body: Twice?
created_at: 2025-05-23T21:54:41Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,91 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.BlockVision;
+import by.dragonsurvivalteam.dragonsurvival.registry.DSAttributes;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.Translation;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.lang.LangKey;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.util.DSColors;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.advancements.critereon.EntityPredicate;
+import net.minecraft.core.Holder;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.damagesource.DamageType;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Optional;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, LevelBasedValue amount, LevelBasedValue probability, Optional<EntityPredicate> validEntities) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability),
+            EntityPredicate.CODEC.optionalFieldOf("valid_entities").forGetter(DragonGrowthEffect::validEntities)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
+                return;
+            }
+
+            if (probability.calculate(ability.level()) < dragon.getRandom().nextDouble()) {
+                return;
+            }
+
+            double amount = amount().calculate(ability.level());
+            double targetGrowth = switch (growth_type) {
+                case GrowthType.ADD -> handler.getGrowth() + amount;
+                case GrowthType.SUBTRACT -> handler.getGrowth() - amount;
+                default -> amount;
+            };
+
+            ServerLevel level = dragon.serverLevel();
+            if (validEntities.isEmpty() || validEntities.get().matches(level, dragon.position(), target)) {
+                handler.setDesiredGrowth(targetPlayer, targetGrowth);
+            }
+        }
+    }
+
+    public enum GrowthType implements StringRepresentable {
+        SET("set"), ADD("add"), SUBTRACT("subtract");
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Psither
body: You could just supply a negative value to subtract growth.  Why not use the GrowthType to instead specify the kind of math you're doing (%-based or flat)
created_at: 2025-05-23T21:57:24Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,91 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.BlockVision;
+import by.dragonsurvivalteam.dragonsurvival.registry.DSAttributes;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.Translation;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.lang.LangKey;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.util.DSColors;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.advancements.critereon.EntityPredicate;
+import net.minecraft.core.Holder;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.damagesource.DamageType;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Optional;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, LevelBasedValue amount, LevelBasedValue probability, Optional<EntityPredicate> validEntities) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability),
+            EntityPredicate.CODEC.optionalFieldOf("valid_entities").forGetter(DragonGrowthEffect::validEntities)
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Oblivire
body: Removed
created_at: 2025-05-24T01:35:57Z
author_association: NONE
diff_hunk: @@ -0,0 +1,91 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.BlockVision;
+import by.dragonsurvivalteam.dragonsurvival.registry.DSAttributes;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.Translation;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.lang.LangKey;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.util.DSColors;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.advancements.critereon.EntityPredicate;
+import net.minecraft.core.Holder;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.damagesource.DamageType;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Optional;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, LevelBasedValue amount, LevelBasedValue probability, Optional<EntityPredicate> validEntities) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability),
+            EntityPredicate.CODEC.optionalFieldOf("valid_entities").forGetter(DragonGrowthEffect::validEntities)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Oblivire
body: Fixed, I had copied that section from UseItemOnLivingEntityEffect and forgot that twice doesn't make sense in this instance
created_at: 2025-05-24T01:37:44Z
author_association: NONE
diff_hunk: @@ -0,0 +1,91 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.BlockVision;
+import by.dragonsurvivalteam.dragonsurvival.registry.DSAttributes;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.Translation;
+import by.dragonsurvivalteam.dragonsurvival.registry.datagen.lang.LangKey;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.util.DSColors;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.advancements.critereon.EntityPredicate;
+import net.minecraft.core.Holder;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.damagesource.DamageType;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Optional;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, LevelBasedValue amount, LevelBasedValue probability, Optional<EntityPredicate> validEntities) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability),
+            EntityPredicate.CODEC.optionalFieldOf("valid_entities").forGetter(DragonGrowthEffect::validEntities)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
+                return;
+            }
+
+            if (probability.calculate(ability.level()) < dragon.getRandom().nextDouble()) {
+                return;
+            }
+
+            double amount = amount().calculate(ability.level());
+            double targetGrowth = switch (growth_type) {
+                case GrowthType.ADD -> handler.getGrowth() + amount;
+                case GrowthType.SUBTRACT -> handler.getGrowth() - amount;
+                default -> amount;
+            };
+
+            ServerLevel level = dragon.serverLevel();
+            if (validEntities.isEmpty() || validEntities.get().matches(level, dragon.position(), target)) {
+                handler.setDesiredGrowth(targetPlayer, targetGrowth);
+            }
+        }
+    }
+
+    public enum GrowthType implements StringRepresentable {
+        SET("set"), ADD("add"), SUBTRACT("subtract");
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Oblivire
body: Added, thank you!
Though I was thinking you might want to use percentage with setting/adding and the same for flat, so I instead split it into two enums
Unsure if it would be better to make a different codec instead of two separate enums, or have like, add_percent, add_flat, set_percent, set_flat

~Also currently the percentage is of the current growth stage, which I think might cause problems with adding?~
Fixed the issue with adding by using the difference instead of mapping the value to the stage's range.  But I realize that I'm checking growth_type twice.  I'm certain that there's a better way of doing this, but I'm having difficulty thinking of it right now
created_at: 2025-05-24T01:40:22Z
author_association: NONE
diff_hunk: @@ -0,0 +1,99 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.MiscCodecs;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.stage.DragonStage;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.core.Holder;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, DragonGrowthEffect.ActionType action_type, LevelBasedValue amount, LevelBasedValue probability) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            ActionType.CODEC.fieldOf("action_type").forGetter(DragonGrowthEffect::action_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
+                return;
+            }
+
+            double amount = amount().calculate(ability.level());
+            if (action_type == ActionType.PERCENT) {
+                Holder<DragonStage> dragonStage = handler.stage();
+                MiscCodecs.Bounds growthRange = dragonStage.value().growthRange();
+                double maxSize = growthRange.max();
+                double minSize = growthRange.min();
+                // Maybe get maximum overall size instead of the current stage?
+                if (growth_type == GrowthType.ADD) {
+                    amount = amount * 0.01 * (maxSize - minSize);
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Psither
body: You could just make it a float value, and not perform additional math on it after the fact, for consistency with the rest of our ability effect definitions.
created_at: 2025-05-24T18:10:03Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,99 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.MiscCodecs;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.stage.DragonStage;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.core.Holder;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, DragonGrowthEffect.ActionType action_type, LevelBasedValue amount, LevelBasedValue probability) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            ActionType.CODEC.fieldOf("action_type").forGetter(DragonGrowthEffect::action_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
+                return;
+            }
+
+            double amount = amount().calculate(ability.level());
+            if (action_type == ActionType.PERCENT) {
+                Holder<DragonStage> dragonStage = handler.stage();
+                MiscCodecs.Bounds growthRange = dragonStage.value().growthRange();
+                double maxSize = growthRange.max();
+                double minSize = growthRange.min();
+                // Maybe get maximum overall size instead of the current stage?
+                if (growth_type == GrowthType.ADD) {
+                    amount = amount * 0.01 * (maxSize - minSize);
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Oblivire
body: Apologies, made changes before I realized you had left a message.

I'm also a bit confused by what you mean?  I don't think there's a function that sets the growth with a percentage parameter already, so I need to map it to the current stage, right?
Or do you mean having the percentage & amount as separate inputs?
created_at: 2025-05-24T18:52:53Z
author_association: NONE
diff_hunk: @@ -0,0 +1,99 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.MiscCodecs;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.stage.DragonStage;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.core.Holder;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, DragonGrowthEffect.ActionType action_type, LevelBasedValue amount, LevelBasedValue probability) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            ActionType.CODEC.fieldOf("action_type").forGetter(DragonGrowthEffect::action_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
+                return;
+            }
+
+            double amount = amount().calculate(ability.level());
+            if (action_type == ActionType.PERCENT) {
+                Holder<DragonStage> dragonStage = handler.stage();
+                MiscCodecs.Bounds growthRange = dragonStage.value().growthRange();
+                double maxSize = growthRange.max();
+                double minSize = growthRange.min();
+                // Maybe get maximum overall size instead of the current stage?
+                if (growth_type == GrowthType.ADD) {
+                    amount = amount * 0.01 * (maxSize - minSize);
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Psither
body: 0.05f = 5%
instead of 0.05f = 0.0005%
created_at: 2025-05-24T18:54:28Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,99 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.MiscCodecs;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.stage.DragonStage;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.core.Holder;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, DragonGrowthEffect.ActionType action_type, LevelBasedValue amount, LevelBasedValue probability) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            ActionType.CODEC.fieldOf("action_type").forGetter(DragonGrowthEffect::action_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
+                return;
+            }
+
+            double amount = amount().calculate(ability.level());
+            if (action_type == ActionType.PERCENT) {
+                Holder<DragonStage> dragonStage = handler.stage();
+                MiscCodecs.Bounds growthRange = dragonStage.value().growthRange();
+                double maxSize = growthRange.max();
+                double minSize = growthRange.min();
+                // Maybe get maximum overall size instead of the current stage?
+                if (growth_type == GrowthType.ADD) {
+                    amount = amount * 0.01 * (maxSize - minSize);
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Oblivire
body: Ohhhhhh, thank you
Will remove the 0.01 mult, I was assuming 0-100
created_at: 2025-05-24T19:01:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,99 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.MiscCodecs;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.stage.DragonStage;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.core.Holder;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, DragonGrowthEffect.ActionType action_type, LevelBasedValue amount, LevelBasedValue probability) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            ActionType.CODEC.fieldOf("action_type").forGetter(DragonGrowthEffect::action_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
+                return;
+            }
+
+            double amount = amount().calculate(ability.level());
+            if (action_type == ActionType.PERCENT) {
+                Holder<DragonStage> dragonStage = handler.stage();
+                MiscCodecs.Bounds growthRange = dragonStage.value().growthRange();
+                double maxSize = growthRange.max();
+                double minSize = growthRange.min();
+                // Maybe get maximum overall size instead of the current stage?
+                if (growth_type == GrowthType.ADD) {
+                    amount = amount * 0.01 * (maxSize - minSize);
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Oblivire
body: Forgot to mention, but removed
created_at: 2025-05-24T20:58:02Z
author_association: NONE
diff_hunk: @@ -0,0 +1,104 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.MiscCodecs;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.stage.DragonStage;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.core.Holder;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, DragonGrowthEffect.ActionType action_type, LevelBasedValue amount, LevelBasedValue probability) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            ActionType.CODEC.fieldOf("action_type").forGetter(DragonGrowthEffect::action_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
+                return;
+            }
+
+            // If FLAT, difference = amount
+            // If PERCENT, difference = percentage mapped to current stage
+            // If ADD, base = current growth
+            // If SET and FLAT, base = 0
+            // If SET and PERCENT, base = min size of current stage
+            double amount = amount().calculate(ability.level());
+            double base = 0;
+            double difference = amount;
+            if (growth_type == GrowthType.ADD) {
+                base = handler.getGrowth();
+            }
+            if (action_type == ActionType.PERCENT) {
+                Holder<DragonStage> dragonStage = handler.stage();
+                MiscCodecs.Bounds growthRange = dragonStage.value().growthRange();
+                double maxSize = growthRange.max();
+                double minSize = growthRange.min();
+                // Maybe get maximum overall size instead of the current stage?
+                difference = amount * (maxSize - minSize);
+                if (growth_type == GrowthType.SET) {
+                    base = minSize;
+                }
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: SiverDX
body: why does `set` only work with `percentage`
shouldn't be an issue to have it work for `add` as well
created_at: 2025-05-27T16:15:41Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,104 @@
+package by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.entity_effects;
+
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateHandler;
+import by.dragonsurvivalteam.dragonsurvival.common.capability.DragonStateProvider;
+import by.dragonsurvivalteam.dragonsurvival.common.codecs.MiscCodecs;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.ability.DragonAbilityInstance;
+import by.dragonsurvivalteam.dragonsurvival.registry.dragon.stage.DragonStage;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.core.Holder;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.enchantment.LevelBasedValue;
+import org.jetbrains.annotations.NotNull;
+
+public record DragonGrowthEffect(DragonGrowthEffect.GrowthType growth_type, DragonGrowthEffect.ActionType action_type, LevelBasedValue amount, LevelBasedValue probability) implements AbilityEntityEffect {
+    public static final MapCodec<DragonGrowthEffect> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+            GrowthType.CODEC.fieldOf("growth_type").forGetter(DragonGrowthEffect::growth_type),
+            ActionType.CODEC.fieldOf("action_type").forGetter(DragonGrowthEffect::action_type),
+            LevelBasedValue.CODEC.fieldOf("amount").forGetter(DragonGrowthEffect::amount),
+            LevelBasedValue.CODEC.fieldOf("probability").forGetter(DragonGrowthEffect::probability)
+    ).apply(instance, DragonGrowthEffect::new));
+
+    @Override
+    public void apply(final ServerPlayer dragon, final DragonAbilityInstance ability, final Entity target) {
+        if (target instanceof Player targetPlayer) {
+            DragonStateHandler handler = DragonStateProvider.getData(targetPlayer);
+
+            if (!handler.isDragon()) {
+                return;
+            }
+
+            if (dragon.getRandom().nextDouble() > probability().calculate(ability.level())) {
+                return;
+            }
+
+            // If FLAT, difference = amount
+            // If PERCENT, difference = percentage mapped to current stage
+            // If ADD, base = current growth
+            // If SET and FLAT, base = 0
+            // If SET and PERCENT, base = min size of current stage
+            double amount = amount().calculate(ability.level());
+            double base = 0;
+            double difference = amount;
+            if (growth_type == GrowthType.ADD) {
+                base = handler.getGrowth();
+            }
+            if (action_type == ActionType.PERCENT) {
+                Holder<DragonStage> dragonStage = handler.stage();
+                MiscCodecs.Bounds growthRange = dragonStage.value().growthRange();
+                double maxSize = growthRange.max();
+                double minSize = growthRange.min();
+                // Maybe get maximum overall size instead of the current stage?
+                difference = amount * (maxSize - minSize);
+                if (growth_type == GrowthType.SET) {
+                    base = minSize;
+                }
path: src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/DragonGrowthEffect.java
user: login: Oblivire
body: It does work for flat, it just sets it as amount directly instead of offsetting it from the bottom of the current growth stage
I have the FLAT and SET combo as the default, the variables are overwritten for the other 3 options to reduce the number of condition checks

Edit: typoed, sorry
created_at: 2025-05-27T21:44:41Z
author_association: NONE

PR comments:
user: login: Psither
created_at: 2025-05-23T03:14:31Z
body: Why not make an [AbilityEntityEffect](https://github.com/DragonSurvivalTeam/DragonSurvival/blob/ad6d32c6ecf79523adfbc03d36b513a68ebdeabc/src/main/java/by/dragonsurvivalteam/dragonsurvival/registry/dragon/ability/entity_effects/AbilityEntityEffect.java#L52) that does this instead?

author_association: COLLABORATOR
user: login: Oblivire
created_at: 2025-05-23T17:15:45Z
body: I agree, that would be better.
Implemented, though I haven't tested it yet, thank you for the suggestion!
author_association: NONE
user: login: Oblivire
created_at: 2025-05-25T00:52:38Z
body: Sorry for toggling the draft status, I wanted to check if it worked, and yes, it does.
Though low values added don't display, like 1%, which is why I have 5% here.
Checked with this ability, just swapping growth_type, action_type, and amount to all of the options (except negative, I didn't try that):
```
{
  "activation": {
    "activation_type": "dragonsurvival:passive",
    "trigger": {
      "trigger_type": "dragonsurvival:on_target_killed"
    }
  },
  "actions": [
    {
      "target_selection": {
        "target_type": "dragonsurvival:self",
        "applied_effects": {
          "entity_effect": [
            {
              "effect_type": "dragonsurvival:dragon_growth",
			  "growth_type": "add",
			  "action_type": "percent",
			  "amount": 0.05,
			  "probability": 1
            }
          ],
          "targeting_mode": "all"
        }
      },
      "trigger_rate": 0
    }
  ],
  "can_be_manually_disabled": true,
  "icon": {
    "texture_entries": [
      {
      "from_level": 0,
      "texture_resource": "dragonsurvival:abilities/echo_sculk/sculk_bloom"
    }
  ]
  }
}
author_association: NONE
user: login: Psither
created_at: 2025-05-25T14:01:28Z
body: Have you thoroughly tested this?  Are we ready to merge?
author_association: COLLABORATOR
user: login: Oblivire
created_at: 2025-05-25T16:27:37Z
body: Yes I think so.  I tested with negatives and because of the clamp on setDesiredGrowth it doesn't cause any issues
The only thing I would change is maybe making the option of having the percentage based on the total possible growth instead of just the current stage, but I think it's fine as is - most people would want it based on the current stage anyways
author_association: NONE
user: login: Oblivire
created_at: 2025-05-25T16:30:34Z
body: Actually hold on, I didn't test in multiplayer.  Will update once I have
author_association: NONE
user: login: Oblivire
created_at: 2025-05-25T19:17:24Z
body: Tested in multiplayer, I think it's good now
author_association: NONE
user: login: Oblivire
created_at: 2025-05-27T21:53:00Z
body: Thank you!
author_association: NONE