update drog effect

This commit is contained in:
2026-01-21 09:34:51 +01:00
parent 5be20ee06a
commit a5150e34fe
9 changed files with 320 additions and 25 deletions

View File

@@ -6,7 +6,7 @@ minecraft_version=1.20.1
yarn_mappings=1.20.1+build.10 yarn_mappings=1.20.1+build.10
loader_version=0.18.3 loader_version=0.18.3
# Mod Properties # Mod Properties
mod_version=1.0.4 mod_version=1.0.5
maven_group=dev.tggamesyt maven_group=dev.tggamesyt
archives_base_name=szar archives_base_name=szar
# Dependencies # Dependencies

View File

@@ -0,0 +1,12 @@
package dev.tggamesyt.szar.client;
import dev.tggamesyt.szar.client.SzarClient.MouseScrambleMode;
public class MouseScrambleState {
public static MouseScrambleMode active = MouseScrambleMode.NONE;
public static boolean wasMoving = false;
public static void reset() {
active = MouseScrambleMode.NONE;
wasMoving = false;
}
}

View File

@@ -1,6 +1,6 @@
package dev.tggamesyt.szar.client; package dev.tggamesyt.szar.client;
import dev.tggamesyt.szar.items.Joint; import dev.tggamesyt.szar.Joint;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;

View File

@@ -1,34 +1,32 @@
package dev.tggamesyt.szar.client; package dev.tggamesyt.szar.client;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import dev.tggamesyt.szar.NiggerEntity;
import dev.tggamesyt.szar.Szar; import dev.tggamesyt.szar.Szar;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry; import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.gui.hud.InGameHud; import net.minecraft.client.util.InputUtil;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.render.*; import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.model.EntityModelLayers;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.random.Random;
import java.util.HashMap;
import java.util.Map;
public class SzarClient implements ClientModInitializer { public class SzarClient implements ClientModInitializer {
private static final Map<KeyBinding, KeyBinding> activeScramble = new HashMap<>();
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
ClientPlayNetworking.registerGlobalReceiver( ClientPlayNetworking.registerGlobalReceiver(
Szar.NWORDPACKET, Szar.TOTEMPACKET,
(client, handler, buf, responseSender) -> { (client, handler, buf, responseSender) -> {
ItemStack stack = buf.readItemStack(); ItemStack stack = buf.readItemStack();
@@ -60,6 +58,7 @@ public class SzarClient implements ClientModInitializer {
var effect = client.player.getStatusEffect(Szar.DROG_EFFECT); var effect = client.player.getStatusEffect(Szar.DROG_EFFECT);
int amplifier = effect.getAmplifier(); // 0 = level I int amplifier = effect.getAmplifier(); // 0 = level I
if (amplifier > 2) {amplifier = 2;}
float level = amplifier + 1f; float level = amplifier + 1f;
float time = client.player.age + tickDelta; float time = client.player.age + tickDelta;
@@ -104,6 +103,18 @@ public class SzarClient implements ClientModInitializer {
RenderSystem.disableBlend(); RenderSystem.disableBlend();
}); });
ClientTickEvents.END_CLIENT_TICK.register(client -> {
if (client.player == null) return;
if (!client.player.hasStatusEffect(Szar.DROG_EFFECT)) return;
var effect = client.player.getStatusEffect(Szar.DROG_EFFECT);
int amplifier = effect.getAmplifier();
float level = amplifier + 1f;
float chance = 0;
if (level > 6) {chance = 0.20f * (level-6);}
scrambleMovement(client, chance);
});
HudRenderCallback.EVENT.register((drawContext, tickDelta) -> { HudRenderCallback.EVENT.register((drawContext, tickDelta) -> {
MinecraftClient client = MinecraftClient.getInstance(); MinecraftClient client = MinecraftClient.getInstance();
@@ -123,4 +134,63 @@ public class SzarClient implements ClientModInitializer {
}); });
} }
private static void scrambleMovement(MinecraftClient client, float chance) {
var options = client.options;
long window = client.getWindow().getHandle();
Random random = client.player.getRandom();
KeyBinding[] movementKeys = {
options.forwardKey,
options.backKey,
options.leftKey,
options.rightKey
};
/* ───── Clear logical movement every tick ───── */
for (KeyBinding key : movementKeys) {
KeyBinding.setKeyPressed(key.getDefaultKey(), false);
}
/* ───── Handle each movement key ───── */
for (KeyBinding key : movementKeys) {
InputUtil.Key bound = key.getDefaultKey();
if (bound.getCategory() != InputUtil.Type.KEYSYM) continue;
boolean physicallyDown =
InputUtil.isKeyPressed(window, bound.getCode());
if (physicallyDown) {
/* ───── Key is held ───── */
// If first tick of press → decide direction
if (!activeScramble.containsKey(key)) {
KeyBinding chosen = key;
if (random.nextFloat() < chance) {
do {
chosen = movementKeys[random.nextInt(movementKeys.length)];
} while (chosen == key);
}
activeScramble.put(key, chosen);
}
// Apply stored direction
KeyBinding result = activeScramble.get(key);
KeyBinding.setKeyPressed(result.getDefaultKey(), true);
} else {
/* ───── Key released ───── */
activeScramble.remove(key);
}
}
}
public enum MouseScrambleMode {
NONE,
INVERT_X,
INVERT_Y,
INVERT_BOTH
}
} }

View File

@@ -0,0 +1,85 @@
package dev.tggamesyt.szar.client.mixin;
import dev.tggamesyt.szar.Szar;
import dev.tggamesyt.szar.client.MouseScrambleState;
import dev.tggamesyt.szar.client.SzarClient;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.Mouse;
import net.minecraft.util.math.random.Random;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArgs;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.invoke.arg.Args;
import static dev.tggamesyt.szar.client.SzarClient.MouseScrambleMode.*;
@Mixin(Mouse.class)
public abstract class MouseMixin {
@Shadow private MinecraftClient client;
@ModifyArgs(
method = "updateMouse",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/network/ClientPlayerEntity;changeLookDirection(DD)V"
)
)
private void szar$scrambleMouse(Args args) {
if (client.player == null) return;
if (!client.player.hasStatusEffect(Szar.DROG_EFFECT)) {
MouseScrambleState.reset();
return;
}
double dx = args.get(0);
double dy = args.get(1);
boolean isMoving = dx != 0 || dy != 0;
var effect = client.player.getStatusEffect(Szar.DROG_EFFECT);
assert effect != null;
int amplifier = effect.getAmplifier();
float level = amplifier + 1f;
float chance = 0;
if (level > 8) {chance = 0.25f * (level-8);}
Random random = client.player.getRandom();
/* ───── Mouse movement started ───── */
if (isMoving && !MouseScrambleState.wasMoving) {
MouseScrambleState.active = SzarClient.MouseScrambleMode.NONE;
if (random.nextFloat() < chance) {
SzarClient.MouseScrambleMode[] modes = {
INVERT_X,
INVERT_Y,
INVERT_BOTH
};
MouseScrambleState.active =
modes[random.nextInt(modes.length)];
}
}
/* ───── Apply scramble ───── */
switch (MouseScrambleState.active) {
case INVERT_X -> dx = -dx;
case INVERT_Y -> dy = -dy;
case INVERT_BOTH -> {
dx = -dx;
dy = -dy;
}
}
MouseScrambleState.wasMoving = isMoving;
args.set(0, dx);
args.set(1, dy);
}
}

View File

@@ -1,9 +1,10 @@
{ {
"required": true, "required": true,
"minVersion": "0.8", "minVersion": "0.8",
"package": "dev.tggamesyt.szar.mixin.client", "package": "dev.tggamesyt.szar.client.mixin",
"compatibilityLevel": "JAVA_17", "compatibilityLevel": "JAVA_17",
"client": [ "client": [
"MouseMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1

View File

@@ -1,10 +1,16 @@
package dev.tggamesyt.szar.items; package dev.tggamesyt.szar;
import dev.tggamesyt.szar.Szar; import dev.tggamesyt.szar.Szar;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.SpyglassItem; import net.minecraft.item.SpyglassItem;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundEvents; import net.minecraft.sound.SoundEvents;
import net.minecraft.stat.Stats; import net.minecraft.stat.Stats;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
@@ -15,9 +21,9 @@ import net.minecraft.world.World;
public class Joint extends SpyglassItem { public class Joint extends SpyglassItem {
public Joint(Settings settings) { public Joint(Settings settings) {
super(settings.maxDamage(64)); // max durability super(settings.maxDamage(20)); // max durability
} }
private static final int COOLDOWN_TICKS = 20 * 5;
@Override @Override
public UseAction getUseAction(ItemStack stack) { public UseAction getUseAction(ItemStack stack) {
return UseAction.SPYGLASS; // keeps spyglass hold animation return UseAction.SPYGLASS; // keeps spyglass hold animation
@@ -40,28 +46,90 @@ public class Joint extends SpyglassItem {
@Override @Override
public void onStoppedUsing(ItemStack stack, World world, LivingEntity user, int remainingUseTicks) { public void onStoppedUsing(ItemStack stack, World world, LivingEntity user, int remainingUseTicks) {
// Only do server/client side durability and effect // Only do server/client side durability and effect
if (!world.isClient) return; //if (!world.isClient) return;
// Consume 1 durability // Consume 1 durability
stack.damage(1, user, p -> p.sendToolBreakStatus(user.getActiveHand())); stack.damage(1, user, p -> p.sendToolBreakStatus(user.getActiveHand()));
if (user instanceof PlayerEntity player && !world.isClient) {
player.getItemCooldownManager().set(this, COOLDOWN_TICKS);
}
// Increase drug effect // Increase drug effect
int amplifier = 0; int amplifier = 0;
if (user.hasStatusEffect(Szar.DROG_EFFECT)) { if (user.hasStatusEffect(Szar.DROG_EFFECT)) {
amplifier = Math.min(user.getStatusEffect(Szar.DROG_EFFECT).getAmplifier() + 1, 9); // max 10 levels amplifier = Math.min(user.getStatusEffect(Szar.DROG_EFFECT).getAmplifier() + 1, 9); // max 10 levels
user.addStatusEffect(new StatusEffectInstance(
StatusEffects.LUCK,
1200,
amplifier,
false, // ambient
true, // show particles
true // show icon
));
user.addStatusEffect(new StatusEffectInstance(
StatusEffects.MINING_FATIGUE,
1200,
amplifier,
false, // ambient
true, // show particles
true // show icon
));
user.addStatusEffect(new StatusEffectInstance(
StatusEffects.STRENGTH,
1200,
amplifier,
false, // ambient
true, // show particles
true // show icon
));
user.addStatusEffect(new StatusEffectInstance(
StatusEffects.HEALTH_BOOST,
1200,
amplifier,
false, // ambient
true, // show particles
true // show icon
));
user.addStatusEffect(new StatusEffectInstance(
StatusEffects.REGENERATION,
1200,
amplifier,
false, // ambient
true, // show particles
true // show icon
));
user.addStatusEffect(new StatusEffectInstance(
StatusEffects.SATURATION,
1200,
amplifier,
false, // ambient
true, // show particles
true // show icon
));
}
if (amplifier > 3) {
int nausealevel = amplifier - 3;
user.addStatusEffect(new StatusEffectInstance(
StatusEffects.NAUSEA,
1200,
nausealevel,
false, // ambient
true, // show particles
true // show icon
));
} }
// Apply the effect (10 seconds, invisible particles) // Apply the effect (10 seconds, invisible particles)
user.addStatusEffect(new net.minecraft.entity.effect.StatusEffectInstance( user.addStatusEffect(new StatusEffectInstance(
Szar.DROG_EFFECT, Szar.DROG_EFFECT,
6000, 1200,
amplifier, amplifier,
false, // ambient false, // ambient
false, // show particles true, // show particles
true // show icon true // show icon
)); ));
// Optional: play inhale / stop sound // Optional: play inhale / stop sound
user.playSound(SoundEvents.ITEM_HONEY_BOTTLE_DRINK, 1.0F, 1.0F); user.playSound(SoundEvents.ITEM_HONEY_BOTTLE_DRINK, 1.0F, 1.0F);
} }
} }

View File

@@ -31,7 +31,7 @@ public class NwordPassItem extends Item {
PacketByteBuf buf = PacketByteBufs.create(); PacketByteBuf buf = PacketByteBufs.create();
buf.writeItemStack(stack); buf.writeItemStack(stack);
ServerPlayNetworking.send(serverPlayer, Szar.NWORDPACKET, buf); ServerPlayNetworking.send(serverPlayer, Szar.TOTEMPACKET, buf);
} }
//world.sendEntityStatus(user, (byte) 35); //world.sendEntityStatus(user, (byte) 35);

View File

@@ -1,10 +1,12 @@
package dev.tggamesyt.szar; package dev.tggamesyt.szar;
import dev.tggamesyt.szar.items.Joint;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
import net.fabricmc.fabric.api.message.v1.ServerMessageDecoratorEvent; import net.fabricmc.fabric.api.message.v1.ServerMessageDecoratorEvent;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
@@ -17,13 +19,19 @@ import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup; import net.minecraft.entity.SpawnGroup;
import net.minecraft.entity.effect.StatusEffect; import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*; import net.minecraft.item.*;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.world.World;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -39,7 +47,7 @@ public class Szar implements ModInitializer {
new Block(AbstractBlock.Settings.copy(Blocks.NETHERITE_BLOCK)); new Block(AbstractBlock.Settings.copy(Blocks.NETHERITE_BLOCK));
public static final Block FASZ_BLOCK = public static final Block FASZ_BLOCK =
new FaszBlock(); new FaszBlock();
public static final Identifier NWORDPACKET = public static final Identifier TOTEMPACKET =
new Identifier(MOD_ID, "nwordpacket"); new Identifier(MOD_ID, "nwordpacket");
public static final ItemGroup SZAR_GROUP = Registry.register( public static final ItemGroup SZAR_GROUP = Registry.register(
Registries.ITEM_GROUP, Registries.ITEM_GROUP,
@@ -104,6 +112,13 @@ public class Szar implements ModInitializer {
GYPSY_ENTITY_TYPE, GYPSY_ENTITY_TYPE,
GypsyEntity.createAttributes() GypsyEntity.createAttributes()
); );
ServerTickEvents.END_WORLD_TICK.register(world -> {
for (var entity : world.getPlayers()) {
if (entity.getHealth() <= 0f) {
tryDrugTotem(entity);
}
}
});
} }
public static final StatusEffect DROG_EFFECT = Registry.register( public static final StatusEffect DROG_EFFECT = Registry.register(
Registries.STATUS_EFFECT, Registries.STATUS_EFFECT,
@@ -344,6 +359,50 @@ public class Szar implements ModInitializer {
.getProgress(advancement) .getProgress(advancement)
.isDone(); .isDone();
} }
public static boolean tryDrugTotem(PlayerEntity player) {
StatusEffectInstance effect = player.getStatusEffect(Szar.DROG_EFFECT);
if (effect == null || effect.getAmplifier() < 5) return false;
// Only trigger if holding Joint
ItemStack stack = player.getMainHandStack();
if (!(stack.getItem() instanceof Joint)) return false;
World world = player.getWorld();
// Prevent death
player.setHealth(1f);
// Clear negative effects
player.clearStatusEffects();
// Vanilla totem effects
player.addStatusEffect(new StatusEffectInstance(StatusEffects.REGENERATION, 900, 1));
player.addStatusEffect(new StatusEffectInstance(StatusEffects.ABSORPTION, 100, 1));
player.addStatusEffect(new StatusEffectInstance(StatusEffects.FIRE_RESISTANCE, 800, 0));
// Sound
player.playSound(SoundEvents.ITEM_TOTEM_USE, 1f, 1f);
// Animation via packet
if (!world.isClient() && player instanceof ServerPlayerEntity serverPlayer) {
PacketByteBuf buf = PacketByteBufs.create();
buf.writeItemStack(stack);
ServerPlayNetworking.send(serverPlayer, Szar.TOTEMPACKET, buf);
}
// Reduce drug level safely
int duration = effect.getDuration();
int amplifier = effect.getAmplifier();
player.addStatusEffect(new StatusEffectInstance(
Szar.DROG_EFFECT,
duration,
Math.max(0, amplifier - 2),
false,
true,
true
));
return true;
}
} }