diff --git a/src/main/java/net/fretux/ascend/AscendMod.java b/src/main/java/net/fretux/ascend/AscendMod.java index 506547f..13118f8 100644 --- a/src/main/java/net/fretux/ascend/AscendMod.java +++ b/src/main/java/net/fretux/ascend/AscendMod.java @@ -1,8 +1,10 @@ package net.fretux.ascend; +import net.fretux.ascend.config.AscendConfig; import net.fretux.ascend.network.PacketHandler; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @@ -17,6 +19,7 @@ public class AscendMod { modBus.addListener(this::onCommonSetup); MinecraftForge.EVENT_BUS.register(this); System.out.println("[Ascend] Mod loaded! Side=" + FMLEnvironment.dist); + net.minecraftforge.fml.ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, AscendConfig.COMMON_SPEC); } private void onCommonSetup(final FMLCommonSetupEvent event) { diff --git a/src/main/java/net/fretux/ascend/Config.java b/src/main/java/net/fretux/ascend/Config.java deleted file mode 100644 index 7a8fc68..0000000 --- a/src/main/java/net/fretux/ascend/Config.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.fretux.ascend; - -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; -import net.minecraftforge.common.ForgeConfigSpec; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.config.ModConfigEvent; -import net.minecraftforge.registries.ForgeRegistries; - -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -@Mod.EventBusSubscriber(modid = AscendMod.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) -public class Config { - private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); - - private static final ForgeConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER - .comment("Whether to log the dirt block on common setup") - .define("logDirtBlock", true); - - private static final ForgeConfigSpec.IntValue MAGIC_NUMBER = BUILDER - .comment("A magic number") - .defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE); - - public static final ForgeConfigSpec.ConfigValue MAGIC_NUMBER_INTRODUCTION = BUILDER - .comment("What you want the introduction message to be for the magic number") - .define("magicNumberIntroduction", "The magic number is... "); - - private static final ForgeConfigSpec.ConfigValue> ITEM_STRINGS = BUILDER - .comment("A list of items to log on common setup.") - .defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName); - - static final ForgeConfigSpec SPEC = BUILDER.build(); - - public static boolean logDirtBlock; - public static int magicNumber; - public static String magicNumberIntroduction; - public static Set items; - - private static boolean validateItemName(final Object obj) { - return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(new ResourceLocation(itemName)); - } - - @SubscribeEvent - static void onLoad(final ModConfigEvent event) { - logDirtBlock = LOG_DIRT_BLOCK.get(); - magicNumber = MAGIC_NUMBER.get(); - magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get(); - items = ITEM_STRINGS.get().stream() - .map(itemName -> ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemName))) - .collect(Collectors.toSet()); - } -} diff --git a/src/main/java/net/fretux/ascend/config/AscendConfig.java b/src/main/java/net/fretux/ascend/config/AscendConfig.java new file mode 100644 index 0000000..f66dc4f --- /dev/null +++ b/src/main/java/net/fretux/ascend/config/AscendConfig.java @@ -0,0 +1,68 @@ +package net.fretux.ascend.config; + +import net.minecraftforge.common.ForgeConfigSpec; +import org.apache.commons.lang3.tuple.Pair; + +public class AscendConfig { + + public static class Common { + public final ForgeConfigSpec.IntValue xpPerMobKill; + public final ForgeConfigSpec.IntValue xpPerBlockBreak; + public final ForgeConfigSpec.IntValue xpPerCraft; + public final ForgeConfigSpec.IntValue xpPerSmelt; + public final ForgeConfigSpec.IntValue xpPerTrade; + public final ForgeConfigSpec.IntValue xpPerDamageTaken; + public final ForgeConfigSpec.IntValue xpPerMovement; + public final ForgeConfigSpec.IntValue xpPerPotion; + public final ForgeConfigSpec.IntValue pointsPerLevel; + public final ForgeConfigSpec.IntValue maxAscendLevel; + public final ForgeConfigSpec.IntValue maxAttributePoints; + + public final ForgeConfigSpec.DoubleValue xpMultiplier; + public final ForgeConfigSpec.DoubleValue attributeScalingMultiplier; + + Common(ForgeConfigSpec.Builder builder) { + builder.push("Ascend Progression"); + + xpPerMobKill = builder.comment("Ascend XP gained for killing a mob.") + .defineInRange("xpPerMobKill", 5, 0, 1000); + xpPerBlockBreak = builder.comment("Ascend XP gained for breaking a block (ore/stone/log).") + .defineInRange("xpPerBlockBreak", 2, 0, 1000); + xpPerCraft = builder.comment("Ascend XP gained for crafting items.") + .defineInRange("xpPerCraft", 3, 0, 1000); + xpPerSmelt = builder.comment("Ascend XP gained for smelting items.") + .defineInRange("xpPerSmelt", 2, 0, 1000); + xpPerTrade = builder.comment("Ascend XP gained for trading with villagers.") + .defineInRange("xpPerTrade", 5, 0, 1000); + xpPerDamageTaken = builder.comment("Ascend XP gained for taking damage.") + .defineInRange("xpPerDamageTaken", 2, 0, 1000); + xpPerMovement = builder.comment("Ascend XP gained for movement actions.") + .defineInRange("xpPerMovement", 1, 0, 1000); + xpPerPotion = builder.comment("Ascend XP gained for using a potion.") + .defineInRange("xpPerPotion", 3, 0, 1000); + + pointsPerLevel = builder.comment("Unspent points gained per Ascend level.") + .defineInRange("pointsPerLevel", 15, 1, 1000); + maxAscendLevel = builder.comment("Maximum Ascend level.") + .defineInRange("maxAscendLevel", 20, 1, 100); + maxAttributePoints = builder.comment("Maximum points in a single attribute.") + .defineInRange("maxAttributePoints", 100, 1, 1000); + + xpMultiplier = builder.comment("Global multiplier for all Ascend XP gain.") + .defineInRange("xpMultiplier", 1.0D, 0.0D, 100.0D); + attributeScalingMultiplier = builder.comment("Global multiplier for all attribute-based stat bonuses (damage, mana, speed, etc.).") + .defineInRange("attributeScalingMultiplier", 1.0D, 0.1D, 10.0D); + + builder.pop(); + } + } + + public static final ForgeConfigSpec COMMON_SPEC; + public static final Common COMMON; + + static { + final Pair specPair = new ForgeConfigSpec.Builder().configure(Common::new); + COMMON_SPEC = specPair.getRight(); + COMMON = specPair.getLeft(); + } +} diff --git a/src/main/java/net/fretux/ascend/event/ActivityEvents.java b/src/main/java/net/fretux/ascend/event/ActivityEvents.java index ebc22ec..99985b0 100644 --- a/src/main/java/net/fretux/ascend/event/ActivityEvents.java +++ b/src/main/java/net/fretux/ascend/event/ActivityEvents.java @@ -1,6 +1,7 @@ package net.fretux.ascend.event; import net.fretux.ascend.AscendMod; +import net.fretux.ascend.config.AscendConfig; import net.fretux.ascend.player.PlayerStatsProvider; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; @@ -33,7 +34,7 @@ public class ActivityEvents { public static void onMobKilled(LivingDeathEvent event) { if (event.getSource().getEntity() instanceof Player player && !player.level().isClientSide) { player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { - stats.addAscendXP(5); + stats.addAscendXP((int) (AscendConfig.COMMON.xpPerMobKill.get() * AscendConfig.COMMON.xpMultiplier.get())); PlayerStatsProvider.sync(player); }); } @@ -43,13 +44,11 @@ public class ActivityEvents { public static void onBlockBreak(BlockEvent.BreakEvent event) { Player player = event.getPlayer(); if (player == null || player.level().isClientSide) return; - Block block = event.getState().getBlock(); String name = block.getName().getString().toLowerCase(); - player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { if (name.contains("log") || name.contains("ore") || name.contains("stone")) { - stats.addAscendXP(2); + stats.addAscendXP((int) (AscendConfig.COMMON.xpPerBlockBreak.get() * AscendConfig.COMMON.xpMultiplier.get())); PlayerStatsProvider.sync(player); } }); @@ -77,7 +76,7 @@ public class ActivityEvents { boolean hasNegativeEffect = player.getActiveEffects().stream() .anyMatch(e -> e.getEffect().getCategory() == MobEffectCategory.HARMFUL); if (player.getFoodData().getFoodLevel() <= 6 || hasNegativeEffect) { - stats.addAscendXP(2); + stats.addAscendXP((int) (AscendConfig.COMMON.xpPerDamageTaken.get() * AscendConfig.COMMON.xpMultiplier.get())); PlayerStatsProvider.sync(player); } }); @@ -97,7 +96,7 @@ public class ActivityEvents { || Math.abs(player.getDeltaMovement().y) > 0.25 || player.onClimbable(); if (didAgileThing) { - stats.addAscendXP(1); + stats.addAscendXP((int) (AscendConfig.COMMON.xpPerMovement.get() * AscendConfig.COMMON.xpMultiplier.get())); PlayerStatsProvider.sync(player); } }); @@ -108,7 +107,7 @@ public class ActivityEvents { Player player = event.getEntity(); if (player.level().isClientSide) return; player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { - stats.addAscendXP(3); + stats.addAscendXP((int) (AscendConfig.COMMON.xpPerCraft.get() * AscendConfig.COMMON.xpMultiplier.get())); PlayerStatsProvider.sync(player); }); } @@ -118,7 +117,7 @@ public class ActivityEvents { Player player = event.getEntity(); if (player.level().isClientSide) return; player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { - stats.addAscendXP(2); + stats.addAscendXP((int) (AscendConfig.COMMON.xpPerSmelt.get() * AscendConfig.COMMON.xpMultiplier.get())); PlayerStatsProvider.sync(player); }); } @@ -151,7 +150,7 @@ public class ActivityEvents { Player player = event.getEntity(); if (player.level().isClientSide) return; player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { - stats.addAscendXP(5); + stats.addAscendXP((int) (AscendConfig.COMMON.xpPerTrade.get() * AscendConfig.COMMON.xpMultiplier.get())); PlayerStatsProvider.sync(player); }); } @@ -178,7 +177,7 @@ public class ActivityEvents { if (player.level().isClientSide) return; if (event.getItemStack().getItem().getDescriptionId().contains("potion")) { player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { - stats.addAscendXP(3); + stats.addAscendXP((int) (AscendConfig.COMMON.xpPerPotion.get() * AscendConfig.COMMON.xpMultiplier.get())); PlayerStatsProvider.sync(player); }); } diff --git a/src/main/java/net/fretux/ascend/event/PlayerEvents.java b/src/main/java/net/fretux/ascend/event/PlayerEvents.java index e53f895..c851e33 100644 --- a/src/main/java/net/fretux/ascend/event/PlayerEvents.java +++ b/src/main/java/net/fretux/ascend/event/PlayerEvents.java @@ -26,17 +26,16 @@ public class PlayerEvents { @SubscribeEvent public static void onPlayerClone(PlayerEvent.Clone event) { - if (!event.isWasDeath()) return; event.getOriginal().reviveCaps(); event.getOriginal().getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(oldStats -> event.getEntity().getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(newStats -> { newStats.deserializeNBT(oldStats.serializeNBT()); - StatEffects.applyAll(event.getEntity()); - if (!event.getEntity().level().isClientSide) { - PlayerStatsProvider.sync(event.getEntity()); - } }) ); + if (!event.getEntity().level().isClientSide) { + StatEffects.applyAll(event.getEntity()); + PlayerStatsProvider.sync(event.getEntity()); + } } @SubscribeEvent @@ -46,5 +45,4 @@ public class PlayerEvents { StatEffects.applyAll(event.getEntity()); } } - -} +} \ No newline at end of file diff --git a/src/main/java/net/fretux/ascend/event/WeaponMagicScalingEvents.java b/src/main/java/net/fretux/ascend/event/WeaponMagicScalingEvents.java index 9207ba4..bd957db 100644 --- a/src/main/java/net/fretux/ascend/event/WeaponMagicScalingEvents.java +++ b/src/main/java/net/fretux/ascend/event/WeaponMagicScalingEvents.java @@ -1,6 +1,7 @@ package net.fretux.ascend.event; import net.fretux.ascend.AscendMod; +import net.fretux.ascend.config.AscendConfig; import net.fretux.ascend.player.PlayerStatsProvider; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.player.Player; @@ -11,6 +12,7 @@ import net.minecraftforge.fml.common.Mod; @Mod.EventBusSubscriber(modid = AscendMod.MODID) public class WeaponMagicScalingEvents { + static double scale = AscendConfig.COMMON.attributeScalingMultiplier.get(); @SubscribeEvent public static void onLivingHurt(LivingHurtEvent event) { @@ -25,7 +27,7 @@ public class WeaponMagicScalingEvents { if (magicScaling > 0) { double perPoint = 0.005d; double maxBonus = 0.40d; - double bonusMult = 1.0d + Math.min(magicScaling * perPoint, maxBonus); + double bonusMult = 1.0d + Math.min(magicScaling * perPoint * scale, maxBonus); modified = (float) (modified * bonusMult); } } else { @@ -33,12 +35,10 @@ public class WeaponMagicScalingEvents { if (player.getAttribute(Attributes.ATTACK_SPEED) != null) { attackSpeed = player.getAttribute(Attributes.ATTACK_SPEED).getValue(); } - String key = (attackSpeed >= 1.8d) ? "light_scaling" : (attackSpeed >= 1.2d) ? "medium_scaling" : "heavy_scaling"; - int level = stats.getAttributeLevel(key); if (level > 0) { double perPoint = @@ -46,7 +46,7 @@ public class WeaponMagicScalingEvents { key.equals("medium_scaling") ? 0.004d : 0.005d; double maxBonus = 0.40d; - double bonusMult = 1.0d + Math.min(level * perPoint, maxBonus); + double bonusMult = 1.0d + Math.min(level * perPoint * scale, maxBonus); modified = (float) (modified * bonusMult); } } diff --git a/src/main/java/net/fretux/ascend/network/ClientboundSyncStatsPacket.java b/src/main/java/net/fretux/ascend/network/ClientboundSyncStatsPacket.java index 1d3cd2c..02b7b17 100644 --- a/src/main/java/net/fretux/ascend/network/ClientboundSyncStatsPacket.java +++ b/src/main/java/net/fretux/ascend/network/ClientboundSyncStatsPacket.java @@ -2,6 +2,7 @@ package net.fretux.ascend.network; import net.fretux.ascend.player.PlayerStats; import net.fretux.ascend.player.PlayerStatsProvider; +import net.fretux.ascend.player.StatEffects; import net.minecraft.client.Minecraft; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; @@ -12,9 +13,17 @@ import java.util.function.Supplier; public class ClientboundSyncStatsPacket { private final CompoundTag data; - public ClientboundSyncStatsPacket(CompoundTag data) { this.data = data; } - public ClientboundSyncStatsPacket(FriendlyByteBuf buf) { this.data = buf.readNbt(); } - public void toBytes(FriendlyByteBuf buf) { buf.writeNbt(data); } + public ClientboundSyncStatsPacket(CompoundTag data) { + this.data = data; + } + + public ClientboundSyncStatsPacket(FriendlyByteBuf buf) { + this.data = buf.readNbt(); + } + + public void toBytes(FriendlyByteBuf buf) { + buf.writeNbt(data); + } public void handle(Supplier ctx) { System.out.println("[SERVER] Spend packet handle() called"); @@ -22,7 +31,9 @@ public class ClientboundSyncStatsPacket { Minecraft mc = Minecraft.getInstance(); var player = mc.player; if (player != null) { - player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { + mc.player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { + stats.deserializeNBT(data); + StatEffects.applyAll(mc.player); stats.deserializeNBT(data); System.out.println("[CLIENT] Before sync: points=" + player.getCapability(PlayerStatsProvider.PLAYER_STATS) @@ -31,10 +42,9 @@ public class ClientboundSyncStatsPacket { System.out.println("[CLIENT] After sync: points=" + player.getCapability(PlayerStatsProvider.PLAYER_STATS) .map(PlayerStats::getUnspentPoints).orElse(-1)); - }); } + ctx.get().setPacketHandled(true); }); - ctx.get().setPacketHandled(true); } } diff --git a/src/main/java/net/fretux/ascend/network/ServerboundSpendPointPacket.java b/src/main/java/net/fretux/ascend/network/ServerboundSpendPointPacket.java index 55b1e6c..8b3765d 100644 --- a/src/main/java/net/fretux/ascend/network/ServerboundSpendPointPacket.java +++ b/src/main/java/net/fretux/ascend/network/ServerboundSpendPointPacket.java @@ -1,11 +1,11 @@ package net.fretux.ascend.network; +import net.fretux.ascend.player.PlayerStatsProvider; import net.fretux.ascend.player.StatEffects; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraftforge.network.NetworkEvent; -import net.fretux.ascend.player.PlayerStatsProvider; import net.minecraftforge.network.PacketDistributor; import net.minecraft.nbt.CompoundTag; @@ -31,9 +31,6 @@ public class ServerboundSpendPointPacket { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); if (player == null) return; - - System.out.println("[Ascend] Received spend packet '" + attribute + "' from " + player.getGameProfile().getName()); - player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { boolean success = stats.spendPoints(attribute); if (success) { diff --git a/src/main/java/net/fretux/ascend/player/PlayerStats.java b/src/main/java/net/fretux/ascend/player/PlayerStats.java index d6bb3ba..6a7bbd9 100644 --- a/src/main/java/net/fretux/ascend/player/PlayerStats.java +++ b/src/main/java/net/fretux/ascend/player/PlayerStats.java @@ -1,18 +1,19 @@ package net.fretux.ascend.player; +import net.fretux.ascend.config.AscendConfig; import net.minecraft.nbt.CompoundTag; import java.util.HashMap; import java.util.Map; public class PlayerStats { - public static final int MAX_ASCEND_LEVEL = 20; - public static final int POINTS_PER_LEVEL = 15; + public static final int POINTS_PER_LEVEL = AscendConfig.COMMON.pointsPerLevel.get(); + public static final int MAX_ASCEND_LEVEL = AscendConfig.COMMON.maxAscendLevel.get(); + public static final int MAX_ATTRIBUTE_POINTS = AscendConfig.COMMON.maxAttributePoints.get(); private final Map attributes = new HashMap<>(); private int ascendLevel = 1; private int ascendXP = 0; private int unspentPoints = POINTS_PER_LEVEL; - public static final int MAX_ATTRIBUTE_POINTS = 100; public PlayerStats() { for (String attr : new String[]{ "strength", "agility", "fortitude", "intelligence", diff --git a/src/main/java/net/fretux/ascend/player/StatEffects.java b/src/main/java/net/fretux/ascend/player/StatEffects.java index 6cd3527..0a2ba62 100644 --- a/src/main/java/net/fretux/ascend/player/StatEffects.java +++ b/src/main/java/net/fretux/ascend/player/StatEffects.java @@ -1,6 +1,7 @@ package net.fretux.ascend.player; import net.fretux.ascend.compat.IronsSpellbooksCompat; +import net.fretux.ascend.config.AscendConfig; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.AttributeModifier; @@ -8,9 +9,6 @@ import net.minecraft.world.entity.ai.attributes.Attributes; import java.util.UUID; -import static net.fretux.ascend.compat.IronsSpellbooksCompat.applyCharisma; -import static net.fretux.ascend.compat.IronsSpellbooksCompat.applyIntelligence; - public final class StatEffects { private static final UUID STRENGTH_DAMAGE_UUID = @@ -27,6 +25,8 @@ public final class StatEffects { UUID.fromString("e4b5c6d7-8e9f-4012-9abc-334455667788"); private StatEffects() {} + + static double scale = AscendConfig.COMMON.attributeScalingMultiplier.get(); public static void applyAll(Player player) { player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { @@ -39,20 +39,14 @@ public final class StatEffects { } }); } - - /** - * Strength: - * - +0.1 attack damage per point (0.05 hearts) - * - +0.03 knockback per point - * - Armor bypass handled in your combat event using strength level. - */ + public static void applyStrength(Player player, int strengthLevel) { // Damage AttributeInstance atk = player.getAttribute(Attributes.ATTACK_DAMAGE); if (atk != null) { atk.removeModifier(STRENGTH_DAMAGE_UUID); if (strengthLevel > 0) { - double dmgBonus = strengthLevel * 0.1d; + double dmgBonus = strengthLevel * 0.1d * scale; atk.addTransientModifier(new AttributeModifier( STRENGTH_DAMAGE_UUID, "Ascend Strength damage bonus", @@ -67,7 +61,7 @@ public final class StatEffects { if (kb != null) { kb.removeModifier(STRENGTH_KNOCKBACK_UUID); if (strengthLevel > 0) { - double kbBonus = strengthLevel * 0.03d; + double kbBonus = strengthLevel * 0.03d * scale; kb.addTransientModifier(new AttributeModifier( STRENGTH_KNOCKBACK_UUID, "Ascend Strength knockback bonus", @@ -77,19 +71,13 @@ public final class StatEffects { } } } - - /** - * Agility: - * - Small movement speed bonus per point. - * - Stealth handled externally (e.g. other mods can read agility). - */ + public static void applyAgility(Player player, int agilityLevel) { AttributeInstance move = player.getAttribute(Attributes.MOVEMENT_SPEED); if (move != null) { move.removeModifier(AGILITY_SPEED_UUID); if (agilityLevel > 0) { - // Example: +0.002 per point = +0.2 at 100 (about +20% on base 0.1) - double bonus = agilityLevel * 0.002d; + double bonus = agilityLevel * 0.002d * scale; move.addTransientModifier(new AttributeModifier( AGILITY_SPEED_UUID, "Ascend Agility speed bonus", @@ -99,21 +87,13 @@ public final class StatEffects { } } } - - /** - * Fortitude: - * - Max HP up per point. - * - Knockback taken reduced via attribute. - * (Poison/hunger/debuff tuning handled via your other event hooks.) - */ + public static void applyFortitude(Player player, int fortitudeLevel) { - // Max health AttributeInstance hp = player.getAttribute(Attributes.MAX_HEALTH); if (hp != null) { hp.removeModifier(FORTITUDE_HEALTH_UUID); if (fortitudeLevel > 0) { - // Example: 0.25 HP (1/8 heart) per point = +12.5 hearts at 100 - double healthBonus = fortitudeLevel * 0.25d; + double healthBonus = fortitudeLevel * 0.25d * scale; hp.addTransientModifier(new AttributeModifier( FORTITUDE_HEALTH_UUID, "Ascend Fortitude health bonus", @@ -122,14 +102,11 @@ public final class StatEffects { )); } } - - // Knockback resistance AttributeInstance kbRes = player.getAttribute(Attributes.KNOCKBACK_RESISTANCE); if (kbRes != null) { kbRes.removeModifier(FORTITUDE_KB_RESIST_UUID); if (fortitudeLevel > 0) { - // Tiny scaling; cap at 60% here - double res = Math.min(0.006d * fortitudeLevel, 0.60d); + double res = Math.min(0.006d * fortitudeLevel * scale, 0.60d); kbRes.addTransientModifier(new AttributeModifier( FORTITUDE_KB_RESIST_UUID, "Ascend Fortitude knockback resist", @@ -139,75 +116,40 @@ public final class StatEffects { } } } - - /** - * Intelligence: - * - Used for mana & potion/enchant effects via other hooks. - * - Here we only expose a mana bonus helper. - */ - - // ===== Willpower external API ===== - - /** - * Sanity drain multiplier from Willpower. - * Other mods can call this directly. - * - * - Starts at 1.0 - * - Reduces up to 50% at high Willpower. - */ + public static float getWillpowerSanityMultiplier(int willpowerLevel) { if (willpowerLevel <= 0) return 1.0f; - double reduction = Math.min(willpowerLevel * 0.005d, 0.5d); // up to -50% + double reduction = Math.min(willpowerLevel * 0.005d * scale, 0.5d); return (float) (1.0d - reduction); } - - /** - * Tempo gain/multiplier from Willpower. - * Other mods can plug this into stamina/tempo/sprint systems. - * - * - Starts at 1.0 - * - Increases up to +40%. - */ + public static float getWillpowerTempoMultiplier(int willpowerLevel) { if (willpowerLevel <= 0) return 1.0f; - double bonus = Math.min(willpowerLevel * 0.004d, 0.4d); // up to +40% + double bonus = Math.min(willpowerLevel * 0.004d * scale, 0.4d); // up to +40% return (float) (1.0d + bonus); } - /** Convenience: from player capability → sanity multiplier. */ - public static float getPlayerSanityMultiplier(Player player) { + public static float getPlayerSanityMultiplier(Player player) { return player.getCapability(PlayerStatsProvider.PLAYER_STATS) .map(stats -> getWillpowerSanityMultiplier(stats.getAttributeLevel("willpower"))) .orElse(1.0f); } - - /** Convenience: from player capability → tempo multiplier. */ + public static float getPlayerTempoMultiplier(Player player) { return player.getCapability(PlayerStatsProvider.PLAYER_STATS) .map(stats -> getWillpowerTempoMultiplier(stats.getAttributeLevel("willpower"))) .orElse(1.0f); } - - // ===== Intelligence external helper (for your mana system) ===== - - /** - * Example mana bonus: 1 mana per INT, capped by caller if needed. - */ + public static int getIntelligenceManaBonus(int intelligenceLevel) { return Math.max(0, intelligenceLevel); } - // ===== Charisma helper (used in trade discount handler) ===== - - /** - * Charisma → trade discount fraction. - * Returns value in [0, max], e.g. 0.0 = no discount, 0.25 = 25% cheaper. - */ public static double getCharismaTradeDiscount(int charismaLevel) { if (charismaLevel <= 0) return 0.0d; double perPoint = 0.01d; double max = 0.30d; - return Math.min(charismaLevel * perPoint, max); + return Math.min(charismaLevel * perPoint * scale, max); } public static double getWeaponScalingMultiplier(int scalingLevel) {