From 6691effce6d70f6a16c6a3ab9cdaf838199abf56 Mon Sep 17 00:00:00 2001 From: marston Date: Thu, 29 Jan 2026 12:39:28 -0500 Subject: [PATCH] Add Lucky modifier - chance to deal double damage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lucky gives a chance to deal double damage on hit. - 10% base chance, scaling to 25% at max level - Can level up 3 times (10% → 15% → 20% → 25%) - Works on swords and axes - Shows enchanted hit particles on lucky strike - Recipe: Rabbit's Foot (classic luck item) Co-Authored-By: Claude Opus 4.5 --- .../loot/modifiers/ModifierRegistry.java | 3 +- .../loot/modifiers/hurter/Lucky.java | 127 ++++++++++++++++++ .../data/randomloot/recipe/trait_lucky.json | 8 ++ 3 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/main/java/dev/marston/randomloot/loot/modifiers/hurter/Lucky.java create mode 100644 src/main/resources/data/randomloot/recipe/trait_lucky.json diff --git a/src/main/java/dev/marston/randomloot/loot/modifiers/ModifierRegistry.java b/src/main/java/dev/marston/randomloot/loot/modifiers/ModifierRegistry.java index b4627d2..c9453cd 100644 --- a/src/main/java/dev/marston/randomloot/loot/modifiers/ModifierRegistry.java +++ b/src/main/java/dev/marston/randomloot/loot/modifiers/ModifierRegistry.java @@ -67,6 +67,7 @@ public static Modifier getModifier(String name) { public static Modifier PUMMELING = register(new Pummeling()); public static Modifier HAILEYS_WRATH = register(new HaileysWrath()); public static Modifier EARLY_BIRD = register(new EarlyBird()); + public static Modifier LUCKY = register(new Lucky()); // Biome-restricted modifiers public static Modifier AQUATIC = register(new Aquatic()); @@ -103,7 +104,7 @@ public static Modifier getModifier(String name) { public static final Set BREAKERS = Set.of(EXPLODE, LEARNING, ATTRACTING, VEINY, MELTING, EXCAVATOR, PROSPECTOR, MUNCHIES, FRAGILE, LUMBERING); public static final Set USERS = Set.of(TORCH_PLACE, DIRT_PLACE, FIRE_PLACE, FIRE_BALL, VOID_TOUCHED); public static final Set HURTERS = Set.of(CRITICAL, CHARGING, FLAMING, COMBO, DRAINING, POISONOUS, - WITHERING, BLINDING, BEZERK, NEMESIS, SOULBOUND, SCORCHED, FROZEN, OVERGROWN, FIERCE, FEASTING, EXECUTIONER, CROWD_PLEASER, PUMMELING, HAILEYS_WRATH, MUNCHIES, CHAOTIC, FRAGILE, CLUNKY, EARLY_BIRD); + WITHERING, BLINDING, BEZERK, NEMESIS, SOULBOUND, SCORCHED, FROZEN, OVERGROWN, FIERCE, FEASTING, EXECUTIONER, CROWD_PLEASER, PUMMELING, HAILEYS_WRATH, MUNCHIES, CHAOTIC, FRAGILE, CLUNKY, EARLY_BIRD, LUCKY); public static final Set HOLDERS = Set.of(HASTY, ABSORBTION, FILLING, RAINY, ORE_FINDER, SPAWNER_FINDER, LIVING, REGENERATING, RESISTANT, FIRE_RESISTANT, AQUATIC, HUNTER, FEASTING, NATURALIST, CLUNKY); diff --git a/src/main/java/dev/marston/randomloot/loot/modifiers/hurter/Lucky.java b/src/main/java/dev/marston/randomloot/loot/modifiers/hurter/Lucky.java new file mode 100644 index 0000000..b96348e --- /dev/null +++ b/src/main/java/dev/marston/randomloot/loot/modifiers/hurter/Lucky.java @@ -0,0 +1,127 @@ +package dev.marston.randomloot.loot.modifiers.hurter; + +import dev.marston.randomloot.loot.LootItem; +import dev.marston.randomloot.loot.LootItem.ToolType; +import dev.marston.randomloot.loot.LootUtils; +import dev.marston.randomloot.loot.modifiers.EntityHurtModifier; +import dev.marston.randomloot.loot.modifiers.Modifier; +import net.minecraft.ChatFormatting; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; + +import java.util.List; +import java.util.Random; + +public class Lucky implements EntityHurtModifier { + + private String name; + private final static String LEVEL = "trait_level"; + private int level = 0; + private static final Random random = new Random(); + + public Lucky(String name, int level) { + this.name = name; + this.level = level; + } + + public Lucky() { + this.name = "Lucky"; + this.level = 0; + } + + public Modifier clone() { + return new Lucky(); + } + + @Override + public CompoundTag toNBT() { + CompoundTag tag = new CompoundTag(); + tag.putString(NAME, name); + tag.putInt(LEVEL, level); + return tag; + } + + @Override + public Modifier fromNBT(CompoundTag tag) { + return new Lucky(tag.getStringOr(NAME, "Lucky"), tag.getIntOr(LEVEL, 0)); + } + + @Override + public String name() { + if (this.level == 0) { + return this.name; + } + return this.name + " " + LootUtils.roman(this.level + 1); + } + + @Override + public String tagName() { + return "lucky"; + } + + @Override + public String color() { + return ChatFormatting.GREEN.getName(); + } + + @Override + public String description() { + int chance = getChance(); + return chance + "% chance to deal double damage."; + } + + private int getChance() { + // 10%, 15%, 20%, 25% based on level + return 10 + (level * 5); + } + + @Override + public void writeToLore(List list, boolean shift) { + MutableComponent comp = Modifier.makeComp(this.name(), this.color()); + list.add(comp); + } + + @Override + public boolean forTool(ToolType type) { + return type.equals(ToolType.SWORD) || type.equals(ToolType.AXE); + } + + @Override + public boolean hurtEnemy(ItemStack itemstack, LivingEntity hurtee, LivingEntity hurter) { + if (hurtee.level().isClientSide()) { + return false; + } + + // Check if we get lucky + if (random.nextInt(100) >= getChance()) { + return false; + } + + // Lucky hit! Deal additional damage equal to base damage + float dmg = LootItem.getAttackDamage(itemstack, LootUtils.getToolType(itemstack)); + + // Visual feedback - enchanted hit particles + Modifier.TrackEntityParticle(hurtee.level(), hurtee, ParticleTypes.ENCHANTED_HIT); + + if (hurter instanceof Player p) { + hurtee.hurt(hurter.damageSources().playerAttack(p), dmg); + } else { + hurtee.hurt(hurter.damageSources().mobAttack(hurter), dmg); + } + + return false; + } + + public boolean canLevel() { + return level < 3; + } + + public void levelUp() { + this.level++; + } +} diff --git a/src/main/resources/data/randomloot/recipe/trait_lucky.json b/src/main/resources/data/randomloot/recipe/trait_lucky.json new file mode 100644 index 0000000..e5deccb --- /dev/null +++ b/src/main/resources/data/randomloot/recipe/trait_lucky.json @@ -0,0 +1,8 @@ +{ + "type": "randomloot:trait_change", + "item": { + "count": 1, + "id": "minecraft:rabbit_foot" + }, + "trait": "lucky" +}