diff --git a/src/main/java/net/fretux/mindmotion/AscendMindMotion.java b/src/main/java/net/fretux/mindmotion/AscendMindMotion.java index 11523b3..7760152 100644 --- a/src/main/java/net/fretux/mindmotion/AscendMindMotion.java +++ b/src/main/java/net/fretux/mindmotion/AscendMindMotion.java @@ -2,8 +2,7 @@ package net.fretux.mindmotion; import com.mojang.logging.LogUtils; import net.fretux.mindmotion.command.SanityCommand; -import net.fretux.mindmotion.event.CombatEvents; -import net.fretux.mindmotion.event.PlayerTickHandler; +import net.fretux.mindmotion.event.CommonEvents; import net.fretux.mindmotion.network.ModMessages; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.api.distmarker.Dist; @@ -28,8 +27,7 @@ public class AscendMindMotion { net.fretux.mindmotion.client.ClientBootstrap.init(modEventBus) ); MinecraftForge.EVENT_BUS.register(this); - MinecraftForge.EVENT_BUS.register(PlayerTickHandler.class); - MinecraftForge.EVENT_BUS.register(CombatEvents.class); + MinecraftForge.EVENT_BUS.register(new CommonEvents()); MinecraftForge.EVENT_BUS.register(SanityCommand.class); LOGGER.info("Ascend: Mind and Motion initialized!"); ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ConfigMM.CLIENT_SPEC); diff --git a/src/main/java/net/fretux/mindmotion/ConfigMM.java b/src/main/java/net/fretux/mindmotion/ConfigMM.java index 18e3212..83adaec 100644 --- a/src/main/java/net/fretux/mindmotion/ConfigMM.java +++ b/src/main/java/net/fretux/mindmotion/ConfigMM.java @@ -83,6 +83,7 @@ public final class ConfigMM { public final ForgeConfigSpec.DoubleValue BASE_SANITY_REGEN_LIGHT; public final ForgeConfigSpec.DoubleValue BASE_SANITY_DECAY_DARK; public final ForgeConfigSpec.BooleanValue ENABLE_LOW_SANITY_SOUNDS; + public final ForgeConfigSpec.BooleanValue ENABLE_SANITY_GAMEPLAY_EFFECTS; public final ForgeConfigSpec.DoubleValue SCRATCHING_CHANCE; public final ForgeConfigSpec.DoubleValue PANIC_CHANCE; public final ForgeConfigSpec.IntValue TEMPO_DECAY_DELAY; @@ -104,6 +105,10 @@ public final class ConfigMM { .comment("Enable creepy noises when sanity is low.") .define("enableLowSanitySounds", true); + ENABLE_SANITY_GAMEPLAY_EFFECTS = b + .comment("Enable gameplay penalties from low sanity and high insanity, beyond shaders and sounds.") + .define("enableSanityGameplayEffects", true); + b.pop().push("insanity"); SCRATCHING_CHANCE = b diff --git a/src/main/java/net/fretux/mindmotion/event/CommonEvents.java b/src/main/java/net/fretux/mindmotion/event/CommonEvents.java index 2441911..57cbc16 100644 --- a/src/main/java/net/fretux/mindmotion/event/CommonEvents.java +++ b/src/main/java/net/fretux/mindmotion/event/CommonEvents.java @@ -10,9 +10,9 @@ public class CommonEvents { @SubscribeEvent public void onPlayerHurt(LivingHurtEvent event) { if (!(event.getEntity() instanceof net.minecraft.world.entity.player.Player player)) return; + if (player.level().isClientSide) return; player.getCapability(PlayerCapabilityProvider.SANITY).ifPresent(sanity -> sanity.reduceSanity(1)); - player.getCapability(PlayerCapabilityProvider.TEMPO).ifPresent(tempo -> tempo.addTempo(4)); } @SubscribeEvent @@ -20,7 +20,17 @@ public class CommonEvents { event.getOriginal().reviveCaps(); event.getEntity().getCapability(PlayerCapabilityProvider.SANITY).ifPresent(newCap -> event.getOriginal().getCapability(PlayerCapabilityProvider.SANITY) - .ifPresent(oldCap -> newCap.setSanity(oldCap.getSanity())) + .ifPresent(oldCap -> { + newCap.setSanity(oldCap.getSanity()); + newCap.setInsanity(oldCap.getInsanity()); + }) + ); + event.getEntity().getCapability(PlayerCapabilityProvider.TEMPO).ifPresent(newCap -> + event.getOriginal().getCapability(PlayerCapabilityProvider.TEMPO) + .ifPresent(oldCap -> { + newCap.setTempo(oldCap.getTempo()); + newCap.setVentCooldown(oldCap.getVentCooldown()); + }) ); event.getOriginal().invalidateCaps(); } diff --git a/src/main/java/net/fretux/mindmotion/event/PlayerTickHandler.java b/src/main/java/net/fretux/mindmotion/event/PlayerTickHandler.java index efc067b..8ce880f 100644 --- a/src/main/java/net/fretux/mindmotion/event/PlayerTickHandler.java +++ b/src/main/java/net/fretux/mindmotion/event/PlayerTickHandler.java @@ -9,6 +9,7 @@ import net.minecraft.tags.BiomeTags; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.level.block.Blocks; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -189,7 +190,11 @@ public class PlayerTickHandler { insanity = sanity.getInsanity(); } } - float percent = (value / sanity.getMaxSanity()) * 100f; + float percent = (sanity.getSanity() / sanity.getMaxSanity()) * 100f; + float insanityPercent = (insanity / sanity.getMaxSanity()) * 100f; + if (ConfigMM.COMMON.ENABLE_SANITY_GAMEPLAY_EFFECTS.get()) { + applySanityGameplayPressure(player, percent, insanityPercent); + } if (percent <= 70 && Math.random() < 0.03) { applyShiver(player); } @@ -208,7 +213,6 @@ public class PlayerTickHandler { if (percent <= 50 && Math.random() < ConfigMM.COMMON.PANIC_CHANCE.get()) { applyPanic(player); } - float insanityPercent = (insanity / sanity.getMaxSanity()) * 100f; if (insanityPercent > 0) { if (insanityPercent > 60 && Math.random() < ConfigMM.COMMON.PANIC_CHANCE.get()) { applyPanic(player); @@ -240,6 +244,68 @@ public class PlayerTickHandler { }); } + private static void applySanityGameplayPressure(Player player, float sanityPercent, float insanityPercent) { + float lowSanity = clamp01((55f - sanityPercent) / 55f); + float highInsanity = clamp01((insanityPercent - 35f) / 65f); + float pressure = Math.max(lowSanity, highInsanity); + if (pressure <= 0f) return; + + if (!player.getAbilities().instabuild) { + player.causeFoodExhaustion(0.08f + pressure * 0.18f); + } + + if (sanityPercent <= 35f) { + int amplifier = sanityPercent <= 15f ? 1 : 0; + player.addEffect(new MobEffectInstance(MobEffects.DIG_SLOWDOWN, 60, amplifier, true, true)); + } + + if (player.isUsingItem() && (sanityPercent <= 25f || insanityPercent >= 70f)) { + float interruptChance = 0.06f + pressure * 0.12f; + if (player.getRandom().nextFloat() < interruptChance) { + player.stopUsingItem(); + } + } + + if ((sanityPercent <= 15f || insanityPercent >= 80f) && player.getRandom().nextFloat() < 0.08f + pressure * 0.10f) { + applyStumble(player, pressure); + } + + if (insanityPercent >= 45f) { + int tempoLoss = Math.max(1, Math.round(highInsanity * 4f)); + player.getCapability(PlayerCapabilityProvider.TEMPO).ifPresent(tempo -> tempo.reduceTempo(tempoLoss)); + } + + if (insanityPercent >= 60f && player.getRandom().nextFloat() < 0.18f + highInsanity * 0.20f) { + alertNearbyMonsters(player, 10.0 + highInsanity * 10.0); + } + } + + private static void applyStumble(Player player, float pressure) { + double strength = 0.08 + pressure * 0.16; + double x = (player.getRandom().nextDouble() - 0.5) * strength; + double z = (player.getRandom().nextDouble() - 0.5) * strength; + player.setDeltaMovement(player.getDeltaMovement().add(x, 0.0, z)); + player.hurtMarked = true; + if (player.isSprinting() && player.getRandom().nextFloat() < 0.5f) { + player.setSprinting(false); + } + } + + private static void alertNearbyMonsters(Player player, double radius) { + player.level().getEntitiesOfClass(Monster.class, player.getBoundingBox().inflate(radius), + monster -> monster.isAlive() && monster.hasLineOfSight(player) + ).forEach(monster -> { + if (monster.getTarget() == null || monster.getRandom().nextFloat() < 0.35f) { + monster.setTarget(player); + } + monster.getNavigation().moveTo(player, 1.1); + }); + } + + private static float clamp01(float value) { + return Math.max(0f, Math.min(1f, value)); + } + private static void handleTempoTick(Player player, int currentTick) { player.getCapability(PlayerCapabilityProvider.TEMPO).ifPresent(tempo -> { int cd = tempo.getVentCooldown();