diff --git a/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java b/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java index f5f17927..fe24d63f 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java +++ b/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java @@ -94,7 +94,7 @@ public class ClientInteractionManager extends InteractionManager { soundManager.play(new MotionBasedSoundInstance(USounds.ENTITY_PLAYER_PEGASUS_FLYING, (PlayerEntity)source, Random.create(seed))); } else if (type == SOUND_MAGIC_BEAM) { soundManager.play(new LoopedEntityTrackingSoundInstance(USounds.SPELL_CAST_SHOOT, 0.3F, 1F, source, seed)); - } else if (type == 6) { + } else if (type == SOUND_HEART_BEAT) { soundManager.play(new NonLoopingFadeOutSoundInstance(USounds.ENTITY_PLAYER_HEARTBEAT, SoundCategory.PLAYERS, 0.3F, Random.create(seed), 80L)); } }); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java b/src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java index c5feebea..9dd3695d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java @@ -5,6 +5,7 @@ import java.util.function.Predicate; import java.util.stream.Stream; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; import com.minelittlepony.unicopia.util.*; import net.minecraft.entity.LivingEntity; @@ -14,7 +15,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.util.Identifier; import net.minecraft.registry.Registries; -public class ItemTracker implements NbtSerialisable, Copyable, Tickable { +public class ItemTracker implements NbtSerialisable, Copyable, Tickable, TrinketsDelegate.Inventory { public static final long TICKS = 1; public static final long SECONDS = 20 * TICKS; public static final long HOURS = 1000 * TICKS; @@ -59,12 +60,17 @@ public class ItemTracker implements NbtSerialisable, Copyable, Tick this.living = living; } + @Override + public LivingEntity asEntity() { + return living.asEntity(); + } + @Override public void tick() { update(living, living.getArmourStacks()); } - public void update(Living living, Stream stacks) { + private void update(Living living, Stream stacks) { final Set found = new HashSet<>(); final Set foundStacks = new HashSet<>(); stacks.forEach(stack -> { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/ButterfingersStatusEffect.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/ButterfingersStatusEffect.java new file mode 100644 index 00000000..3c415da4 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/ButterfingersStatusEffect.java @@ -0,0 +1,60 @@ +package com.minelittlepony.unicopia.entity.effect; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffectCategory; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.Hand; +import net.minecraft.util.math.MathHelper; + +public class ButterfingersStatusEffect extends StatusEffect { + + ButterfingersStatusEffect(int color) { + super(StatusEffectCategory.HARMFUL, color); + } + + @Override + public void applyUpdateEffect(LivingEntity entity, int amplifier) { + amplifier = MathHelper.clamp(amplifier, 0, 5); + final int scale = 500 + (int)(((5 - amplifier) / 5F) * 900); + + if (entity.world.random.nextInt(scale / 4) == 0) { + applyInstantEffect(null, null, entity, amplifier, entity.world.random.nextInt(scale)); + } + } + + @Override + public void applyInstantEffect(@Nullable Entity source, @Nullable Entity attacker, LivingEntity target, int amplifier, double proximity) { + + if (target.world.isClient) { + return; + } + + if (target instanceof ServerPlayerEntity player) { + if (player.dropSelectedItem(proximity < 1)) { + player.world.playSound(null, player.getBlockPos(), SoundEvents.BLOCK_HONEY_BLOCK_SLIDE, player.getSoundCategory()); + PlayerInventory inventory = player.getInventory(); + player.networkHandler.sendPacket(new ScreenHandlerSlotUpdateS2CPacket(-2, 0, inventory.selectedSlot, inventory.getStack(inventory.selectedSlot))); + } + } else { + ItemStack stack = target.getMainHandStack(); + if (!stack.isEmpty()) { + target.setStackInHand(Hand.MAIN_HAND, ItemStack.EMPTY); + target.dropStack(stack); + target.world.playSound(null, target.getBlockPos(), SoundEvents.BLOCK_HONEY_BLOCK_SLIDE, target.getSoundCategory()); + } + } + } + + @Override + public boolean canApplyUpdateEffect(int duration, int amplifier) { + return duration > 0; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java index a01fbb5f..c7675ecf 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/UEffects.java @@ -12,6 +12,7 @@ public interface UEffects { StatusEffect SUN_BLINDNESS = register("sun_blindness", new SunBlindnessStatusEffect(0x886F0F)); StatusEffect CORRUPT_INFLUENCE = register("corrupt_influence", new CorruptInfluenceStatusEffect(0x00FF00)); StatusEffect PARALYSIS = register("paralysis", new StatusEffect(StatusEffectCategory.HARMFUL, 0) {}); + StatusEffect BUTTER_FINGERS = register("butter_fingers", new ButterfingersStatusEffect(0x888800)); private static StatusEffect register(String name, StatusEffect effect) { return Registry.register(Registries.STATUS_EFFECT, Unicopia.id(name), effect); diff --git a/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java b/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java index 93bc1f36..0226fda4 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java @@ -8,7 +8,9 @@ import com.google.common.collect.ImmutableMultimap; import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.entity.*; +import com.minelittlepony.unicopia.entity.effect.UEffects; import com.minelittlepony.unicopia.entity.player.*; +import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; import com.minelittlepony.unicopia.util.MagicalDamageSource; import net.fabricmc.api.EnvType; @@ -16,6 +18,8 @@ import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.minecraft.client.MinecraftClient; import net.minecraft.client.item.TooltipContext; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.enchantment.Enchantments; import net.minecraft.entity.*; import net.minecraft.entity.Entity.RemovalReason; import net.minecraft.entity.attribute.*; @@ -166,19 +170,19 @@ public class AlicornAmuletItem extends AmuletItem implements ItemTracker.Trackab return; } - Living living = Living.living(entity); + final Living living = Living.living(entity); if (living == null || !living.getArmour().contains(this)) { return; } - long attachedTicks = living.getArmour().getTicks(this); - boolean poweringUp = attachedTicks < (ItemTracker.DAYS * 4); - boolean fullSecond = attachedTicks % ItemTracker.SECONDS == 0; + final long attachedTicks = living.getArmour().getTicks(this); + final long daysAttached = attachedTicks / ItemTracker.DAYS; + final boolean fullSecond = attachedTicks % ItemTracker.SECONDS == 0; if (entity instanceof PlayerEntity player) { // healing effect - if (poweringUp) { + if (daysAttached <= 4) { if (player.getHealth() < player.getMaxHealth()) { player.heal(0.5F); } else if (player.canConsume(false)) { @@ -188,6 +192,28 @@ public class AlicornAmuletItem extends AmuletItem implements ItemTracker.Trackab Pony pony = (Pony)living; + // butterfingers effects + if (daysAttached >= 2) { + if (pony.asWorld().random.nextInt(200) == 0 && !pony.asEntity().hasStatusEffect(UEffects.BUTTER_FINGERS)) { + pony.asEntity().addStatusEffect(new StatusEffectInstance(UEffects.CORRUPT_INFLUENCE, 2100, 1)); + } + + pony.findAllEntitiesInRange(10, e -> e instanceof LivingEntity && !((LivingEntity)e).hasStatusEffect(UEffects.CORRUPT_INFLUENCE)).forEach(e -> { + ((LivingEntity)e).addStatusEffect(new StatusEffectInstance(UEffects.CORRUPT_INFLUENCE, 100, 1)); + }); + } + + // bind to the player after 3 days + if (daysAttached >= 3 && !pony.asEntity().isCreative()) { + stack = living.getArmour().getEquippedStack(TrinketsDelegate.NECKLACE); + if (stack.getItem() == this && !EnchantmentHelper.hasBindingCurse(stack)) { + pony.playSound(USounds.ITEM_ALICORN_AMULET_HALLUCINATION, 3, 1); + stack = stack.copy(); + stack.addEnchantment(Enchantments.BINDING_CURSE, 1); + pony.getArmour().equipStack(TrinketsDelegate.NECKLACE, stack); + } + } + MagicReserves reserves = pony.getMagicalReserves(); // constantly increase exertion @@ -195,13 +221,15 @@ public class AlicornAmuletItem extends AmuletItem implements ItemTracker.Trackab reserves.getExertion().add(2); } + // gradual corruption accumulation if (fullSecond && world.random.nextInt(12) == 0 && !pony.asEntity().isCreative()) { reserves.getEnergy().add(reserves.getEnergy().getMax() / 10F); pony.getCorruption().add((int)MathHelper.clamp(attachedTicks / ItemTracker.HOURS, 1, pony.getCorruption().getMax())); } + // ambient effects if (attachedTicks % ItemTracker.HOURS < 90 && world.random.nextInt(900) == 0) { - player.world.playSound(null, player.getBlockPos(), USounds.ITEM_ALICORN_AMULET_HALLUCINATION, SoundCategory.AMBIENT, 3, 1); + pony.playSound(USounds.ITEM_ALICORN_AMULET_HALLUCINATION, 3, 1); } else if (attachedTicks < 2 || (attachedTicks % (10 * ItemTracker.SECONDS) < 9 && world.random.nextInt(90) == 0)) { if (attachedTicks % 5 == 0) { InteractionManager.INSTANCE.playLoopingSound(player, InteractionManager.SOUND_HEART_BEAT, 0); @@ -213,7 +241,8 @@ public class AlicornAmuletItem extends AmuletItem implements ItemTracker.Trackab living.asEntity().removeStatusEffect(StatusEffects.NAUSEA); } - if (!poweringUp) { + // damage effect after 4 days + if (daysAttached >= 4) { if (attachedTicks % 100 == 0) { player.getHungerManager().addExhaustion(90F); float healthDrop = MathHelper.clamp(player.getMaxHealth() - player.getHealth(), 2, 5); diff --git a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java index 079aa0e4..feb3c1d0 100644 --- a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java +++ b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java @@ -4,6 +4,8 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; +import com.minelittlepony.unicopia.EntityConvertable; + import net.fabricmc.loader.api.FabricLoader; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; @@ -86,4 +88,19 @@ public interface TrinketsDelegate { default boolean isTrinketSlot(Slot slot) { return false; } + + interface Inventory extends EntityConvertable { + + default Stream getEquippedStacks(Identifier slot) { + return TrinketsDelegate.getInstance().getEquipped(asEntity(), slot); + } + + default ItemStack getEquippedStack(Identifier slot) { + return getEquippedStacks(slot).findFirst().orElse(ItemStack.EMPTY); + } + + default void equipStack(Identifier slot, ItemStack stack) { + TrinketsDelegate.getInstance().setEquippedStack(asEntity(), slot, stack); + } + } } diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 8a69a6bc..3725d5b8 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -141,20 +141,20 @@ "entity.unicopia.cast_spell.by": "a spell cast by %s", "entity.unicopia.spellbook": "Spellbook", + "player.reachDistance": "Reach Distance", + "player.miningSpeed": "Mining Speed", + "player.gravityModifier": "Gravity", + "unicopia.effect.tribe.stage.initial": "It appears to have no effect.", "unicopia.effect.tribe.stage.crawling": "You feel the skin crawling on your back.", "unicopia.effect.tribe.stage.determination": "As your bones realign you are filled by determination.", "unicopia.effect.tribe.stage.resurection": "Knowing you will return to this world as a %s", "effect.unicopia.food_poisoning": "Food Poisoning", - "effect.unicopia.corrupt_influence": "Corrupt Influence", - - "player.reachDistance": "Reach Distance", - "player.miningSpeed": "Mining Speed", - "player.gravityModifier": "Gravity", - "effect.unicopia.sun_blindness": "Sun Blindness", + "effect.unicopia.corrupt_influence": "Corrupt Influence", "effect.unicopia.paralysis": "Paralysis", + "effect.unicopia.butter_fingers": "Butterfingers", "effect.unicopia.change_race_earth": "Earth Pony Metamorphosis", "item.minecraft.potion.effect.unicopia.tribe_swap_earth": "Potion of Earth Pony Metamorphosis", diff --git a/src/main/resources/assets/unicopia/textures/mob_effect/butter_fingers.png b/src/main/resources/assets/unicopia/textures/mob_effect/butter_fingers.png new file mode 100644 index 00000000..233bc85c Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/mob_effect/butter_fingers.png differ