Enhance intelligence, willpower, and charisma bonuses

This commit is contained in:
2026-01-13 19:51:42 +01:00
parent d22629d1d1
commit c097f997b6
8 changed files with 266 additions and 16 deletions
@@ -14,6 +14,8 @@ import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.entity.animal.TamableAnimal;
import net.minecraft.world.entity.animal.horse.AbstractHorse;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
@@ -24,8 +26,13 @@ import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.event.level.BlockEvent;
import net.minecraftforge.event.entity.living.LivingDamageEvent;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.animal.IronGolem;
import net.minecraft.world.entity.animal.SnowGolem;
import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraft.world.phys.AABB;
import java.util.Objects;
import java.util.UUID;
@Mod.EventBusSubscriber(modid = AscendMod.MODID)
public class ActivityEvents {
@@ -33,6 +40,7 @@ public class ActivityEvents {
private static int agilityTickCounter = 0;
private static int fortitudeTickCounter = 0;
private static int willpowerTickCounter = 0;
private static int charismaTickCounter = 0;
@SubscribeEvent
public static void onMobKilled(LivingDeathEvent event) {
@@ -41,7 +49,7 @@ public class ActivityEvents {
stats.addAscendXP((int) (AscendConfig.COMMON.xpPerMobKill.get() * AscendConfig.COMMON.xpMultiplier.get()));
LivingEntity mob = event.getEntity();
if (mob.getMaxHealth() > 100f || mob.getType().toString().toLowerCase().contains("boss")) {
stats.addKnowledge(2);
stats.addKnowledgeScaled(2);
}
PlayerStatsProvider.sync(player);
});
@@ -134,8 +142,15 @@ public class ActivityEvents {
Player player = event.player;
if (player.level().isClientSide || event.phase != TickEvent.Phase.END) return;
willpowerTickCounter++;
if (willpowerTickCounter % 200 != 0) return;
player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> {
int willpower = stats.getAttributeLevel("willpower");
if (willpower > 0 && willpowerTickCounter % 80 == 0) {
float regen = StatEffects.getWillpowerHealthRegen(willpower);
if (regen > 0.0f && player.getHealth() < player.getMaxHealth()) {
player.heal(regen);
}
}
if (willpowerTickCounter % 200 != 0) return;
boolean hasNegativeEffect = player.getActiveEffects().stream()
.anyMatch(e -> e.getEffect().getCategory() == MobEffectCategory.HARMFUL);
boolean lowHealth = player.getHealth() <= player.getMaxHealth() * 0.25f;
@@ -151,6 +166,35 @@ public class ActivityEvents {
});
}
@SubscribeEvent
public static void onPlayerTickCharisma(TickEvent.PlayerTickEvent event) {
Player player = event.player;
if (player.level().isClientSide || event.phase != TickEvent.Phase.END) return;
charismaTickCounter++;
if (charismaTickCounter % 40 != 0) return;
player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> {
int charisma = stats.getAttributeLevel("charisma");
if (charisma <= 0) return;
double radius = 16.0d;
AABB range = player.getBoundingBox().inflate(radius);
for (LivingEntity entity : player.level().getEntitiesOfClass(LivingEntity.class, range,
candidate -> isCharismaAlly(player, candidate))) {
StatEffects.applyCharismaAllyBuff(entity, charisma);
}
});
}
@SubscribeEvent
public static void onCharismaAllyTick(LivingEvent.LivingTickEvent event) {
LivingEntity entity = event.getEntity();
if (entity.level().isClientSide) return;
if (!isCharismaAllyCandidate(entity)) return;
if (entity.tickCount % 40 != 0) return;
double radius = 16.0d;
if (hasNearbyCharismaSource(entity, radius)) return;
StatEffects.clearCharismaAllyBuff(entity);
}
@SubscribeEvent
public static void onVillagerTrade(PlayerInteractEvent.EntityInteract event) {
if (!(event.getTarget() instanceof Villager)) return;
@@ -271,4 +315,64 @@ public class ActivityEvents {
}
});
}
}
private static boolean isCharismaAlly(Player player, LivingEntity entity) {
if (entity instanceof TamableAnimal tame) {
return tame.isTame() && tame.isOwnedBy(player);
}
if (entity instanceof AbstractHorse horse) {
return horse.isTamed() && player.getUUID().equals(horse.getOwnerUUID());
}
if (entity instanceof IronGolem ironGolem) {
return ironGolem.isPlayerCreated();
}
if (entity instanceof SnowGolem snowGolem) {
return snowGolem.isPlayerCreated();
}
return false;
}
private static boolean isCharismaAllyCandidate(LivingEntity entity) {
if (entity instanceof TamableAnimal tame) {
return tame.isTame();
}
if (entity instanceof AbstractHorse horse) {
return horse.isTamed();
}
if (entity instanceof IronGolem ironGolem) {
return ironGolem.isPlayerCreated();
}
if (entity instanceof SnowGolem snowGolem) {
return snowGolem.isPlayerCreated();
}
return false;
}
private static boolean hasNearbyCharismaSource(LivingEntity entity, double radius) {
if (entity instanceof TamableAnimal tame) {
Player owner = tame.getOwner() instanceof Player player ? player : null;
return owner != null && owner.distanceToSqr(entity) <= radius * radius && hasCharisma(owner);
}
if (entity instanceof AbstractHorse horse) {
UUID ownerId = horse.getOwnerUUID();
if (ownerId == null) return false;
Player owner = entity.level().getPlayerByUUID(ownerId);
return owner != null && owner.distanceToSqr(entity) <= radius * radius && hasCharisma(owner);
}
if (entity instanceof IronGolem || entity instanceof SnowGolem) {
AABB range = entity.getBoundingBox().inflate(radius);
for (Player player : entity.level().getEntitiesOfClass(Player.class, range)) {
if (hasCharisma(player)) {
return true;
}
}
}
return false;
}
private static boolean hasCharisma(Player player) {
return player.getCapability(PlayerStatsProvider.PLAYER_STATS)
.map(stats -> stats.getAttributeLevel("charisma") > 0)
.orElse(false);
}
}
@@ -7,6 +7,8 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.MerchantMenu;
import net.minecraft.world.item.trading.MerchantOffer;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.npc.GossipType;
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@@ -26,6 +28,13 @@ public class CharismaTradeEvents {
int cha = stats.getAttributeLevel("charisma");
if (cha <= 0) return;
if (merchantMenu.getTrader() instanceof Villager villager) {
int reputationBonus = StatEffects.getCharismaVillagerReputationBonus(cha);
if (reputationBonus > 0) {
villager.getGossips().add(player.getUUID(), GossipType.MINOR_POSITIVE, reputationBonus);
}
}
double discountFraction = StatEffects.getCharismaTradeDiscount(cha);
if (discountFraction <= 0.0d) return;
@@ -57,4 +66,4 @@ public class CharismaTradeEvents {
}
});
}
}
}
@@ -0,0 +1,31 @@
package net.fretux.ascend.event;
import net.fretux.ascend.AscendMod;
import net.fretux.ascend.player.PlayerStatsProvider;
import net.fretux.ascend.player.StatEffects;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.event.AnvilUpdateEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(modid = AscendMod.MODID)
public class IntelligenceAnvilEvents {
@SubscribeEvent
public static void onAnvilUpdate(AnvilUpdateEvent event) {
Player player = event.getPlayer();
if (player == null || player.level().isClientSide) return;
int baseCost = event.getCost();
if (baseCost <= 0) return;
player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> {
int intelligence = stats.getAttributeLevel("intelligence");
if (intelligence <= 0) return;
double reduction = StatEffects.getIntelligenceAnvilCostReduction(intelligence);
if (reduction <= 0.0d) return;
int newCost = (int) Math.max(1, Math.floor(baseCost * (1.0d - reduction)));
if (newCost < baseCost) {
event.setCost(newCost);
}
});
}
}
@@ -26,12 +26,12 @@ public class MoonseyeTome extends Item {
} else {
gained = 50;
}
stats.addKnowledge(gained);
player.sendSystemMessage(net.minecraft.network.chat.Component.translatable("item.ascend.moonseye_tome.used", gained));
int totalGained = stats.addKnowledgeScaled(gained);
player.sendSystemMessage(net.minecraft.network.chat.Component.translatable("item.ascend.moonseye_tome.used", totalGained));
player.playSound(SoundEvents.ENCHANTMENT_TABLE_USE, 1.0f, 1.2f);
stack.shrink(1);
PlayerStatsProvider.sync(player);
});
return InteractionResultHolder.consume(stack);
}
}
}
@@ -55,7 +55,7 @@ public class ServerboundShrineChoicePacket {
player.getCapability(PlayerCapabilityProvider.SANITY).ifPresent(sanity -> {
float sanityPercent = sanity.getSanity() / sanity.getMaxSanity();
if (sanityPercent >= 0.90f) {
stats.addKnowledge(5);
stats.addKnowledgeScaled(5);
sanity.setSanity(0);
sanity.setInsanity(0);
player.sendSystemMessage(Component.literal("YOUR MIND EXPANDS AS IT BREAKS."));
@@ -86,4 +86,4 @@ public class ServerboundShrineChoicePacket {
});
ctx.get().setPacketHandled(true);
}
}
}
@@ -32,7 +32,7 @@ public class PlayerStats {
ascendXP -= xpNeeded;
ascendLevel++;
unspentPoints += POINTS_PER_LEVEL;
knowledge += 1;
addKnowledgeScaled(1);
}
if (ascendLevel >= MAX_ASCEND_LEVEL) {
int xpNeeded = getXPToNextAscendLevel();
@@ -111,6 +111,17 @@ public class PlayerStats {
knowledge = Math.max(0, knowledge + amount);
}
public int addKnowledgeScaled(int amount) {
if (amount <= 0) {
addKnowledge(amount);
return amount;
}
int intelligence = getAttributeLevel("intelligence");
int scaled = StatEffects.getIntelligenceKnowledgeGain(intelligence, amount);
addKnowledge(scaled);
return scaled;
}
public void refundAllPoints() {
int totalSpent = 0;
for (String key : attributes.keySet()) {
@@ -167,4 +178,4 @@ public class PlayerStats {
hasUsedMoonseye = tag.getBoolean("HasUsedMoonseye");
}
}
}
}
@@ -3,6 +3,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.LivingEntity;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes;
@@ -23,6 +24,10 @@ public final class StatEffects {
UUID.fromString("d3a4b5c6-7d8e-4f90-8a1b-223344556677");
private static final UUID FORTITUDE_KB_RESIST_UUID =
UUID.fromString("e4b5c6d7-8e9f-4012-9abc-334455667788");
private static final UUID CHARISMA_ALLY_HEALTH_UUID =
UUID.fromString("f5c6d7e8-9012-4bcd-9ef0-445566778899");
private static final UUID CHARISMA_ALLY_DAMAGE_UUID =
UUID.fromString("0a1b2c3d-4e5f-4012-8a9b-556677889900");
private StatEffects() {
}
@@ -145,6 +150,12 @@ public final class StatEffects {
return (float) (1.0d + bonus);
}
public static float getWillpowerHealthRegen(int willpowerLevel) {
if (willpowerLevel <= 0) return 0.0f;
double bonus = Math.min(willpowerLevel * 0.01d * getScaling(), 2.0d);
return (float) bonus;
}
public static float getPlayerSanityMultiplier(Player player) {
return player.getCapability(PlayerStatsProvider.PLAYER_STATS)
.map(stats -> getWillpowerSanityMultiplier(stats.getAttributeLevel("willpower")))
@@ -161,12 +172,97 @@ public final class StatEffects {
return Math.max(0, intelligenceLevel);
}
public static double getIntelligenceAnvilCostReduction(int intelligenceLevel) {
if (intelligenceLevel <= 0) return 0.0d;
double perPoint = 0.005d;
double max = 0.40d;
return Math.min(intelligenceLevel * perPoint * getScaling(), max);
}
public static int getIntelligenceKnowledgeGain(int intelligenceLevel, int baseGain) {
if (baseGain <= 0) return baseGain;
if (intelligenceLevel <= 0) return baseGain;
double perPoint = 0.005d;
double max = 0.50d;
double bonus = Math.min(intelligenceLevel * perPoint * getScaling(), max);
int extra = (int) Math.floor(baseGain * bonus);
return baseGain + Math.max(0, extra);
}
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 * getScaling(), max);
}
public static int getCharismaVillagerReputationBonus(int charismaLevel) {
if (charismaLevel <= 0) return 0;
double perPoint = 0.1d;
double max = 10.0d;
return (int) Math.floor(Math.min(charismaLevel * perPoint * getScaling(), max));
}
public static double getCharismaAllyHealthBonus(int charismaLevel) {
if (charismaLevel <= 0) return 0.0d;
double perPoint = 0.0025d;
double max = 0.25d;
return Math.min(charismaLevel * perPoint * getScaling(), max);
}
public static double getCharismaAllyDamageBonus(int charismaLevel) {
if (charismaLevel <= 0) return 0.0d;
double perPoint = 0.0020d;
double max = 0.20d;
return Math.min(charismaLevel * perPoint * getScaling(), max);
}
public static void applyCharismaAllyBuff(LivingEntity entity, int charismaLevel) {
if (charismaLevel <= 0) {
clearCharismaAllyBuff(entity);
return;
}
double healthBonus = getCharismaAllyHealthBonus(charismaLevel);
AttributeInstance health = entity.getAttribute(Attributes.MAX_HEALTH);
if (health != null) {
health.removeModifier(CHARISMA_ALLY_HEALTH_UUID);
if (healthBonus > 0.0d) {
health.addTransientModifier(new AttributeModifier(
CHARISMA_ALLY_HEALTH_UUID,
"Ascend Charisma ally max health",
healthBonus,
AttributeModifier.Operation.MULTIPLY_BASE
));
}
}
double damageBonus = getCharismaAllyDamageBonus(charismaLevel);
AttributeInstance damage = entity.getAttribute(Attributes.ATTACK_DAMAGE);
if (damage != null) {
damage.removeModifier(CHARISMA_ALLY_DAMAGE_UUID);
if (damageBonus > 0.0d) {
damage.addTransientModifier(new AttributeModifier(
CHARISMA_ALLY_DAMAGE_UUID,
"Ascend Charisma ally damage",
damageBonus,
AttributeModifier.Operation.MULTIPLY_BASE
));
}
}
}
public static void clearCharismaAllyBuff(LivingEntity entity) {
AttributeInstance health = entity.getAttribute(Attributes.MAX_HEALTH);
if (health != null) {
health.removeModifier(CHARISMA_ALLY_HEALTH_UUID);
}
AttributeInstance damage = entity.getAttribute(Attributes.ATTACK_DAMAGE);
if (damage != null) {
damage.removeModifier(CHARISMA_ALLY_DAMAGE_UUID);
}
if (entity.getHealth() > entity.getMaxHealth()) {
entity.setHealth(entity.getMaxHealth());
}
}
public static double getWeaponScalingMultiplier(int scalingLevel) {
if (scalingLevel <= 0) return 1.0d;
@@ -192,4 +288,4 @@ public final class StatEffects {
double maxBonus = 0.75d;
return 1.0d + Math.min(scalingLevel * perPoint, maxBonus);
}
}
}