From 82bdce6c51788ca93ca17811e4087604064d603b Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 17 May 2023 19:49:38 +0100 Subject: [PATCH] Added consumption and heartbound enchantments --- .../com/minelittlepony/unicopia/Unicopia.java | 2 + .../advancement/CustomEventCriterion.java | 6 +- .../unicopia/advancement/UCriteria.java | 2 + .../unicopia/entity/player/Pony.java | 15 +++++ .../enchantment/ConsumptionEnchantment.java | 55 +++++++++++++++ .../item/enchantment/EnchantmentUtil.java | 61 +++++++++++++++++ .../enchantment/PoisonedJokeEnchantment.java | 3 +- .../enchantment/StressfulEnchantment.java | 4 +- .../enchantment/UEnchantmentValidSlots.java | 9 +++ .../item/enchantment/UEnchantments.java | 17 ++++- .../enchantment/WantItNeedItEnchantment.java | 3 +- .../unicopia/mixin/MixinBlock.java | 31 +++++++++ .../unicopia/mixin/MixinPlayerInventory.java | 67 +++++++++++++++++++ .../unicopia/trinkets/TrinketsDelegate.java | 4 ++ .../trinkets/TrinketsDelegateImpl.java | 14 ++++ .../resources/assets/unicopia/lang/en_us.json | 10 +++ .../unicopia/enchanting/experimental.json | 36 ++++++++++ .../hearts_stronger_than_horses.json | 36 ++++++++++ .../unicopia/enchanting/soulmate.json | 32 +++++++++ .../unicopia/enchanting/xp_mine.json | 32 +++++++++ src/main/resources/unicopia.mixin.json | 2 + 21 files changed, 428 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/item/enchantment/ConsumptionEnchantment.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/enchantment/EnchantmentUtil.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/enchantment/UEnchantmentValidSlots.java create mode 100644 src/main/java/com/minelittlepony/unicopia/mixin/MixinBlock.java create mode 100644 src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerInventory.java create mode 100644 src/main/resources/data/unicopia/advancements/unicopia/enchanting/experimental.json create mode 100644 src/main/resources/data/unicopia/advancements/unicopia/enchanting/hearts_stronger_than_horses.json create mode 100644 src/main/resources/data/unicopia/advancements/unicopia/enchanting/soulmate.json create mode 100644 src/main/resources/data/unicopia/advancements/unicopia/enchanting/xp_mine.json diff --git a/src/main/java/com/minelittlepony/unicopia/Unicopia.java b/src/main/java/com/minelittlepony/unicopia/Unicopia.java index cd2a438f..a23d2ae0 100644 --- a/src/main/java/com/minelittlepony/unicopia/Unicopia.java +++ b/src/main/java/com/minelittlepony/unicopia/Unicopia.java @@ -34,6 +34,7 @@ import com.minelittlepony.unicopia.server.world.NocturnalSleepManager; import com.minelittlepony.unicopia.server.world.UGameRules; import com.minelittlepony.unicopia.server.world.WeatherConditions; import com.minelittlepony.unicopia.server.world.ZapAppleStageStore; +import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; public class Unicopia implements ModInitializer { public static final String DEFAULT_NAMESPACE = "unicopia"; @@ -62,6 +63,7 @@ public class Unicopia implements ModInitializer { UCriteria.bootstrap(); UEntities.bootstrap(); Commands.bootstrap(); + TrinketsDelegate.getInstance().bootstrap(); ServerTickEvents.END_WORLD_TICK.register(w -> { ((BlockDestructionManager.Source)w).getDestructionManager().tick(); diff --git a/src/main/java/com/minelittlepony/unicopia/advancement/CustomEventCriterion.java b/src/main/java/com/minelittlepony/unicopia/advancement/CustomEventCriterion.java index 3ae2437c..3ba1ba75 100644 --- a/src/main/java/com/minelittlepony/unicopia/advancement/CustomEventCriterion.java +++ b/src/main/java/com/minelittlepony/unicopia/advancement/CustomEventCriterion.java @@ -13,7 +13,7 @@ import com.minelittlepony.unicopia.entity.player.Pony; import net.minecraft.advancement.criterion.AbstractCriterion; import net.minecraft.advancement.criterion.AbstractCriterionConditions; -import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.Entity; import net.minecraft.predicate.entity.AdvancementEntityPredicateDeserializer; import net.minecraft.predicate.entity.AdvancementEntityPredicateSerializer; import net.minecraft.predicate.entity.EntityPredicate.Extended; @@ -53,7 +53,7 @@ public class CustomEventCriterion extends AbstractCriterion { if (player instanceof ServerPlayerEntity p) { - int counter = Pony.of(player).getAdvancementProgress().compute(name, (key, i) -> i == null ? 1 : i + 1); + int counter = Pony.of(p).getAdvancementProgress().compute(name, (key, i) -> i == null ? 1 : i + 1); trigger(p, c -> c.test(name, counter, p)); } @@ -61,7 +61,7 @@ public class CustomEventCriterion extends AbstractCriterion implements Copyable, UpdateCallback { private static final TrackedData RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING); @@ -697,6 +701,17 @@ public class Pony extends Living implements Copyable, Update } else { oldPlayer.getSpellSlot().stream(true).filter(SpellPredicate.IS_PLACED).forEach(getSpellSlot()::put); } + + // putting it here instead of adding another injection point into ServerPlayerEntity.copyFrom() + if (!asWorld().getGameRules().getBoolean(GameRules.KEEP_INVENTORY)) { + PlayerInventory inventory = oldPlayer.asEntity().getInventory(); + for (int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStack(i); + if (EnchantmentHelper.getLevel(UEnchantments.HEART_BOUND, stack) > 0) { + asEntity().getInventory().setStack(i, stack); + } + } + } } oldPlayer.getSpellSlot().put(null); diff --git a/src/main/java/com/minelittlepony/unicopia/item/enchantment/ConsumptionEnchantment.java b/src/main/java/com/minelittlepony/unicopia/item/enchantment/ConsumptionEnchantment.java new file mode 100644 index 00000000..3924cf4b --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/enchantment/ConsumptionEnchantment.java @@ -0,0 +1,55 @@ +package com.minelittlepony.unicopia.item.enchantment; + +import java.util.function.DoubleSupplier; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.advancement.UCriteria; +import com.minelittlepony.unicopia.util.VecHelper; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.enchantment.EnchantmentTarget; +import net.minecraft.entity.Entity; +import net.minecraft.entity.ExperienceOrbEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class ConsumptionEnchantment extends SimpleEnchantment { + protected ConsumptionEnchantment() { + super(Rarity.VERY_RARE, EnchantmentTarget.DIGGER, false, 1, UEnchantmentValidSlots.HANDS); + } + + public static boolean applyConsumption(World w, BlockState state, BlockPos pos, @Nullable BlockEntity blockEntity, Entity entity, ItemStack tool) { + + if (!(w instanceof ServerWorld world)) { + return false; + } + + if (tool.isEmpty() && entity instanceof LivingEntity l) { + tool = l.getMainHandStack(); + } + if (EnchantmentHelper.getLevel(UEnchantments.CONSUMPTION, tool) <= 0) { + return false; + } + + DoubleSupplier vecComponentFactory = () -> world.random.nextTriangular(0, 0.3); + + Block.getDroppedStacks(state, world, pos, blockEntity, entity, tool).forEach(s -> { + world.playSound(null, pos, SoundEvents.ENTITY_PLAYER_BURP, SoundCategory.BLOCKS, 0.05F, (float)world.random.nextTriangular(0.6F, 0.2F)); + ExperienceOrbEntity.spawn(world, Vec3d.ofCenter(pos).add(VecHelper.supply(vecComponentFactory)), s.getCount()); + UCriteria.USE_CONSUMPTION.trigger(entity); + }); + state.onStacksDropped(world, pos, tool, true); + + return true; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/enchantment/EnchantmentUtil.java b/src/main/java/com/minelittlepony/unicopia/item/enchantment/EnchantmentUtil.java new file mode 100644 index 00000000..6d223e8d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/enchantment/EnchantmentUtil.java @@ -0,0 +1,61 @@ +package com.minelittlepony.unicopia.item.enchantment; + +import java.util.Map; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.entity.Living; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.random.Random; + +public interface EnchantmentUtil { + + static boolean consumeEnchantment(Enchantment enchantment, int levels, ItemStack stack) { + return consumeEnchantment(enchantment, levels, stack, null, 0); + } + + static boolean consumeEnchantment(Enchantment enchantment, int levels, ItemStack stack, @Nullable Random random, int chance) { + Map enchantments = EnchantmentHelper.get(stack); + int level = enchantments.getOrDefault(enchantment, 0); + if (level <= 0) { + return false; + } + + if (random == null || chance <= 1 || random.nextInt(chance) == 0) { + level = Math.max(0, level - levels); + if (level == 0) { + enchantments.remove(enchantment); + } else { + enchantments.put(enchantment, level - 1); + } + EnchantmentHelper.set(enchantments, stack); + } + return true; + } + + static int getLuck(int baseline, LivingEntity entity) { + boolean naturallyLucky = Living.getOrEmpty(entity).filter(c -> c.getSpecies().canUseEarth()).isPresent(); + if (naturallyLucky) { + baseline += 15; + } + float luckAmplifier = getEffectAmplifier(entity, StatusEffects.LUCK) * (naturallyLucky ? 2 : 1); + float dolphinsGraceAmplifier = getEffectAmplifier(entity, StatusEffects.DOLPHINS_GRACE) * 0.5F; + float unluckAmplifier = getEffectAmplifier(entity, StatusEffects.UNLUCK) * (naturallyLucky ? 0.5F : 1); + float badOmenAmplifier = getEffectAmplifier(entity, StatusEffects.BAD_OMEN) * (naturallyLucky ? 1 : 2); + return (int)MathHelper.clamp(baseline + luckAmplifier + dolphinsGraceAmplifier - unluckAmplifier - badOmenAmplifier, -10, 10); + } + + static int getEffectAmplifier(LivingEntity entity, StatusEffect effect) { + if (!entity.hasStatusEffect(effect)) { + return 0; + } + return entity.getStatusEffect(effect).getAmplifier(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/enchantment/PoisonedJokeEnchantment.java b/src/main/java/com/minelittlepony/unicopia/item/enchantment/PoisonedJokeEnchantment.java index 0d0e5cfe..03ce128c 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/enchantment/PoisonedJokeEnchantment.java +++ b/src/main/java/com/minelittlepony/unicopia/item/enchantment/PoisonedJokeEnchantment.java @@ -15,7 +15,6 @@ import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.util.Resources; import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; -import net.minecraft.entity.EquipmentSlot; import net.minecraft.resource.ResourceManager; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; @@ -31,7 +30,7 @@ public class PoisonedJokeEnchantment extends SimpleEnchantment implements Identi private List sounds = new ArrayList<>(); protected PoisonedJokeEnchantment() { - super(Rarity.VERY_RARE, true, 1, EquipmentSlot.values()); + super(Rarity.VERY_RARE, true, 1, UEnchantmentValidSlots.ANY); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/item/enchantment/StressfulEnchantment.java b/src/main/java/com/minelittlepony/unicopia/item/enchantment/StressfulEnchantment.java index a7031e81..70dee276 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/enchantment/StressfulEnchantment.java +++ b/src/main/java/com/minelittlepony/unicopia/item/enchantment/StressfulEnchantment.java @@ -4,12 +4,10 @@ import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.player.MagicReserves.Bar; import com.minelittlepony.unicopia.entity.player.Pony; -import net.minecraft.entity.EquipmentSlot; - public class StressfulEnchantment extends SimpleEnchantment { protected StressfulEnchantment() { - super(Rarity.RARE, true, 3, EquipmentSlot.values()); + super(Rarity.RARE, true, 3, UEnchantmentValidSlots.ANY); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/item/enchantment/UEnchantmentValidSlots.java b/src/main/java/com/minelittlepony/unicopia/item/enchantment/UEnchantmentValidSlots.java new file mode 100644 index 00000000..b4c1c122 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/enchantment/UEnchantmentValidSlots.java @@ -0,0 +1,9 @@ +package com.minelittlepony.unicopia.item.enchantment; + +import net.minecraft.entity.EquipmentSlot; + +public interface UEnchantmentValidSlots { + EquipmentSlot[] ANY = EquipmentSlot.values(); + EquipmentSlot[] ARMOR = { EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET }; + EquipmentSlot[] HANDS = { EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND }; +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/enchantment/UEnchantments.java b/src/main/java/com/minelittlepony/unicopia/item/enchantment/UEnchantments.java index d46f04d4..449ec7bc 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/enchantment/UEnchantments.java +++ b/src/main/java/com/minelittlepony/unicopia/item/enchantment/UEnchantments.java @@ -29,12 +29,12 @@ public interface UEnchantments { /** * Protects against wall collisions and earth pony attacks! */ - Enchantment PADDED = register("padded", new SimpleEnchantment(Rarity.COMMON, EnchantmentTarget.ARMOR, false, 3, EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET)); + Enchantment PADDED = register("padded", new SimpleEnchantment(Rarity.COMMON, EnchantmentTarget.ARMOR, false, 3, UEnchantmentValidSlots.ARMOR)); /** * Heavy players move more slowly but are less likely to be flung around wildly. */ - Enchantment HEAVY = register("heavy", new AttributedEnchantment(Rarity.COMMON, EnchantmentTarget.ARMOR, false, 4, EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET)) + Enchantment HEAVY = register("heavy", new AttributedEnchantment(Rarity.COMMON, EnchantmentTarget.ARMOR, false, 4, UEnchantmentValidSlots.ARMOR)) .addModifier(EntityAttributes.GENERIC_MOVEMENT_SPEED, (user, level) -> { return new EntityAttributeModifier(UUID.fromString("a3d5a94f-4c40-48f6-a343-558502a13e10"), "Heavyness", (1 - level/(float)10) - 1, Operation.MULTIPLY_TOTAL); }); @@ -76,7 +76,18 @@ public interface UEnchantments { /** * This item just wants to be held. */ - Enchantment CLINGY = register("clingy", new SimpleEnchantment(Rarity.VERY_RARE, true, 6, EquipmentSlot.values())); + Enchantment CLINGY = register("clingy", new SimpleEnchantment(Rarity.VERY_RARE, true, 6, UEnchantmentValidSlots.ANY)); + + /** + * Items with loyalty are kept after death. + * Only works if they don't also have curse of binding. + */ + Enchantment HEART_BOUND = register("heart_bound", new SimpleEnchantment(Rarity.COMMON, EnchantmentTarget.VANISHABLE, false, 5, UEnchantmentValidSlots.ANY)); + + /** + * Consumes drops whilst mining and produces experience instead + */ + Enchantment CONSUMPTION = register("consumption", new ConsumptionEnchantment()); static void bootstrap() { } diff --git a/src/main/java/com/minelittlepony/unicopia/item/enchantment/WantItNeedItEnchantment.java b/src/main/java/com/minelittlepony/unicopia/item/enchantment/WantItNeedItEnchantment.java index 5624d39f..ded97190 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/enchantment/WantItNeedItEnchantment.java +++ b/src/main/java/com/minelittlepony/unicopia/item/enchantment/WantItNeedItEnchantment.java @@ -7,13 +7,12 @@ import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.UParticles; import net.minecraft.enchantment.EnchantmentHelper; -import net.minecraft.entity.EquipmentSlot; import net.minecraft.item.ItemStack; public class WantItNeedItEnchantment extends SimpleEnchantment { protected WantItNeedItEnchantment() { - super(Rarity.VERY_RARE, true, 1, EquipmentSlot.values()); + super(Rarity.VERY_RARE, true, 1, UEnchantmentValidSlots.ANY); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinBlock.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinBlock.java new file mode 100644 index 00000000..3cbfe530 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinBlock.java @@ -0,0 +1,31 @@ +package com.minelittlepony.unicopia.mixin; + +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.minelittlepony.unicopia.item.enchantment.ConsumptionEnchantment; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +@Mixin(Block.class) +abstract class MixinBlock { + @Inject( + method = "dropStacks(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/entity/BlockEntity;Lnet/minecraft/entity/Entity;Lnet/minecraft/item/ItemStack;)V", + at = @At("HEAD"), + cancellable = true + ) + private static void dropStacks(BlockState state, World world, BlockPos pos, @Nullable BlockEntity blockEntity, Entity entity, ItemStack stack, CallbackInfo info) { + if (ConsumptionEnchantment.applyConsumption(world, state, pos, blockEntity, entity, stack)) { + info.cancel(); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerInventory.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerInventory.java new file mode 100644 index 00000000..5661455b --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerInventory.java @@ -0,0 +1,67 @@ +package com.minelittlepony.unicopia.mixin; + +import java.util.List; + +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +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.callback.CallbackInfo; + +import com.minelittlepony.unicopia.advancement.UCriteria; +import com.minelittlepony.unicopia.item.enchantment.EnchantmentUtil; +import com.minelittlepony.unicopia.item.enchantment.UEnchantments; + +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.enchantment.Enchantments; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Nameable; +import net.minecraft.util.collection.DefaultedList; + +@Mixin(PlayerInventory.class) +abstract class MixinPlayerInventory implements Inventory, Nameable { + @Shadow + public @Final PlayerEntity player; + @Shadow + private @Final List> combinedInventory; + + @Nullable + private List> storedCombinedInventory; + + @Inject(method = "dropAll()V", at = @At("HEAD")) + public void beforeDropAll(CallbackInfo info) { + storedCombinedInventory = combinedInventory.stream().map(l -> DefaultedList.ofSize(l.size(), ItemStack.EMPTY)).toList(); + for (int group = 0; group < combinedInventory.size(); group++) { + var original = combinedInventory.get(group); + for (int i = 0; i < original.size(); i++) { + ItemStack stack = original.get(i); + if (EnchantmentHelper.getLevel(Enchantments.BINDING_CURSE, stack) == 0 + && EnchantmentUtil.consumeEnchantment(UEnchantments.HEART_BOUND, 1, stack, player.world.random, EnchantmentUtil.getLuck(3, player))) { + original.set(i, ItemStack.EMPTY); + UCriteria.USE_CONSUMPTION.trigger(player); + storedCombinedInventory.get(group).set(i, stack); + } + } + } + } + + @Inject(method = "dropAll()V", at = @At("TAIL")) + public void afterDropAll(CallbackInfo info) { + if (storedCombinedInventory != null) { + for (int group = 0; group < combinedInventory.size(); group++) { + var original = combinedInventory.get(group); + for (int i = 0; i < original.size(); i++) { + ItemStack stored = storedCombinedInventory.get(group).get(i); + if (!stored.isEmpty()) { + original.set(i, stored); + } + } + } + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java index feb3c1d0..719a517f 100644 --- a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java +++ b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java @@ -37,6 +37,10 @@ public interface TrinketsDelegate { return FabricLoader.getInstance().isModLoaded("trinkets"); } + default void bootstrap() { + + } + default boolean equipStack(LivingEntity entity, Identifier slot, ItemStack stack) { EquipmentSlot eq = MobEntity.getPreferredEquipmentSlot(stack); if (!entity.getEquippedStack(eq).isEmpty()) { diff --git a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegateImpl.java b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegateImpl.java index 960da04e..fa28f896 100644 --- a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegateImpl.java +++ b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegateImpl.java @@ -4,10 +4,14 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; +import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.util.InventoryUtil; import dev.emi.trinkets.TrinketSlot; import dev.emi.trinkets.api.*; +import dev.emi.trinkets.api.TrinketEnums.DropRule; +import dev.emi.trinkets.api.event.TrinketDropCallback; +import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; @@ -21,6 +25,16 @@ public class TrinketsDelegateImpl implements TrinketsDelegate { public static final TrinketsDelegateImpl INSTANCE = new TrinketsDelegateImpl(); // who tf designed this api? + @Override + public void bootstrap() { + TrinketDropCallback.EVENT.register((rule, stack, ref, entity) -> { + if (EnchantmentHelper.getLevel(UEnchantments.HEART_BOUND, stack) > 0) { + return DropRule.KEEP; + } + return rule; + }); + } + @Override public boolean equipStack(LivingEntity entity, Identifier slot, ItemStack stack) { return getInventory(entity, slot).map(inventory -> { diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index e12edb49..4c0c1c45 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -426,6 +426,8 @@ "enchantment.unicopia.want_it_need_it": "Want It Need It", "enchantment.unicopia.poisoned_joke": "Poisoned Joke", "enchantment.unicopia.stressed": "Stressed", + "enchantment.unicopia.heart_bound": "Heart Bound", + "enchantment.unicopia.consumption": "Consumption", "commands.race.success.self": "Set own race to %1$s", "commands.race.success": "%1$s changed race to %2$s", @@ -617,6 +619,14 @@ "advancements.unicopia.eat_pinecone.description": "Eat a pinecone", "advancements.unicopia.imported_oats.title": "As Delicious As They Are Expensive", "advancements.unicopia.imported_oats.description": "Send of receive fancy imported oats", + "advancements.unicopia.experimental.title": "You Can't Take It With You", + "advancements.unicopia.experimental.description": "Enchant a tool with Consumption", + "advancements.unicopia.xp_mine.title": "XP Miner", + "advancements.unicopia.xp_mine.description": "Use consumption to dig up some experience", + "advancements.unicopia.hearts_stronger_than_horses.title": "You Can Keep it With You", + "advancements.unicopia.hearts_stronger_than_horses.description": "Enchant a tool with Heart Bound", + "advancements.unicopia.soulmate.title": "Hearts Stronger Than Horses", + "advancements.unicopia.soulmate.description": "Die whilst holding a heart-bound item", "advancements.unicopia.burn_juice.title": "That doesn't seem right", "advancements.unicopia.burn_juice.description": "Burn the juice", diff --git a/src/main/resources/data/unicopia/advancements/unicopia/enchanting/experimental.json b/src/main/resources/data/unicopia/advancements/unicopia/enchanting/experimental.json new file mode 100644 index 00000000..5f6b8dcd --- /dev/null +++ b/src/main/resources/data/unicopia/advancements/unicopia/enchanting/experimental.json @@ -0,0 +1,36 @@ +{ + "parent": "minecraft:story/enchant_item", + "display": { + "icon": { + "item": "minecraft:netherite_pickaxe" + }, + "title": { + "translate": "advancements.unicopia.experimental.title" + }, + "description": { + "translate": "advancements.unicopia.experimental.description" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "rewards": { + "experience": 120 + }, + "criteria": { + "enchant_with_consumption": { + "trigger": "minecraft:enchanted_item", + "conditions": { + "item": { + "enchantments": [ + { "enchantment": "unicopia:consumption" } + ] + } + } + } + }, + "requirements": [ + [ "enchant_with_consumption" ] + ] +} diff --git a/src/main/resources/data/unicopia/advancements/unicopia/enchanting/hearts_stronger_than_horses.json b/src/main/resources/data/unicopia/advancements/unicopia/enchanting/hearts_stronger_than_horses.json new file mode 100644 index 00000000..ceaf66b9 --- /dev/null +++ b/src/main/resources/data/unicopia/advancements/unicopia/enchanting/hearts_stronger_than_horses.json @@ -0,0 +1,36 @@ +{ + "parent": "minecraft:story/enchant_item", + "display": { + "icon": { + "item": "minecraft:golden_pickaxe" + }, + "title": { + "translate": "advancements.unicopia.hearts_stronger_than_horses.title" + }, + "description": { + "translate": "advancements.unicopia.hearts_stronger_than_horses.description" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "rewards": { + "experience": 120 + }, + "criteria": { + "enchant_with_heart_bound": { + "trigger": "minecraft:enchanted_item", + "conditions": { + "item": { + "enchantments": [ + { "enchantment": "unicopia:heart_bound" } + ] + } + } + } + }, + "requirements": [ + [ "enchant_with_heart_bound" ] + ] +} diff --git a/src/main/resources/data/unicopia/advancements/unicopia/enchanting/soulmate.json b/src/main/resources/data/unicopia/advancements/unicopia/enchanting/soulmate.json new file mode 100644 index 00000000..18ef64c7 --- /dev/null +++ b/src/main/resources/data/unicopia/advancements/unicopia/enchanting/soulmate.json @@ -0,0 +1,32 @@ +{ + "parent": "unicopia:unicopia/enchanting/hearts_stronger_than_horses", + "display": { + "icon": { + "item": "minecraft:golden_apple" + }, + "title": { + "translate": "advancements.unicopia.soulmate.title" + }, + "description": { + "translate": "advancements.unicopia.soulmate.description" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": true + }, + "rewards": { + "experience": 1200 + }, + "criteria": { + "use_soulmate": { + "trigger": "unicopia:custom", + "conditions": { + "event": "use_soulmate" + } + } + }, + "requirements": [ + [ "use_soulmate" ] + ] +} diff --git a/src/main/resources/data/unicopia/advancements/unicopia/enchanting/xp_mine.json b/src/main/resources/data/unicopia/advancements/unicopia/enchanting/xp_mine.json new file mode 100644 index 00000000..0721fe43 --- /dev/null +++ b/src/main/resources/data/unicopia/advancements/unicopia/enchanting/xp_mine.json @@ -0,0 +1,32 @@ +{ + "parent": "unicopia:unicopia/enchanting/experimental", + "display": { + "icon": { + "item": "minecraft:netherite_pickaxe" + }, + "title": { + "translate": "advancements.unicopia.xp_mine.title" + }, + "description": { + "translate": "advancements.unicopia.xp_mine.description" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": true + }, + "rewards": { + "experience": 1200 + }, + "criteria": { + "mine_xp": { + "trigger": "unicopia:custom", + "conditions": { + "event": "use_consumption" + } + } + }, + "requirements": [ + [ "mine_xp" ] + ] +} diff --git a/src/main/resources/unicopia.mixin.json b/src/main/resources/unicopia.mixin.json index 5a5a9ef9..5a9c0794 100644 --- a/src/main/resources/unicopia.mixin.json +++ b/src/main/resources/unicopia.mixin.json @@ -7,6 +7,7 @@ "mixins": [ "MixinAbstractDecorationEntity", "MixinBlazeEntity", + "MixinBlock", "MixinBlockEntity", "MixinBlockItem", "MixinBoatEntity", @@ -24,6 +25,7 @@ "MixinMobEntity", "MixinPersistentProjectileEntity", "MixinPlayerEntity", + "MixinPlayerInventory", "MixinPowderSnowBlock", "MixinProjectileEntity", "MixinServerPlayerEntity",