From 8959c67d53911de46eb76a97145b205daffa69e0 Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 28 Feb 2023 16:44:14 +0000 Subject: [PATCH] Added magic staffs: 3 sticks on a diagonal = meadowbrooks_staff 3 sticks + gem (optionally with spell) on a diagnoal = magic_staff --- .../ability/UnicornCastingAbility.java | 5 +- .../ability/magic/spell/ThrowableSpell.java | 3 +- .../spell/crafting/IngredientWithSpell.java | 6 +- .../spell/crafting/SpellCraftingRecipe.java | 4 +- .../crafting/SpellDuplicatingRecipe.java | 8 +- .../spell/crafting/SpellEnhancingRecipe.java | 2 +- .../crafting/SpellShapedCraftingRecipe.java | 48 ++++ .../ability/magic/spell/effect/SpellType.java | 3 +- .../unicopia/client/URenderers.java | 12 +- .../unicopia/entity/UTradeOffers.java | 4 +- .../entity/player/PlayerCharmTracker.java | 6 +- .../unicopia/entity/player/PlayerPhysics.java | 5 +- .../unicopia/item/AmuletItem.java | 41 +--- .../unicopia/item/ChargeableItem.java | 56 +++++ .../unicopia/item/EnchantableItem.java | 86 ++++++++ .../unicopia/item/EnchantedStaffItem.java | 206 ++++++++++++++++++ .../unicopia/item/GemstoneItem.java | 78 +------ .../unicopia/item/StaffItem.java | 99 +++++++++ .../minelittlepony/unicopia/item/UItems.java | 5 +- .../unicopia/item/URecipes.java | 2 + .../resources/assets/unicopia/lang/en_us.json | 5 + .../unicopia/models/item/handheld_staff.json | 25 +++ .../unicopia/models/item/magic_staff.json | 7 + .../models/item/meadowbrooks_staff.json | 6 + .../textures/item/magic_staff_base.png | Bin 0 -> 1978 bytes .../textures/item/magic_staff_magic.png | Bin 0 -> 1966 bytes .../textures/item/meadowbrooks_staff.png | Bin 0 -> 3216 bytes .../recipes/meadowbrooks_staff.json | 30 +++ .../data/unicopia/recipes/magic_staff.json | 19 ++ .../unicopia/recipes/meadowbrooks_staff.json | 16 ++ .../unicopia/tags/items/magic_spell_base.json | 7 + 31 files changed, 667 insertions(+), 127 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellShapedCraftingRecipe.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/ChargeableItem.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/EnchantableItem.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/StaffItem.java create mode 100644 src/main/resources/assets/unicopia/models/item/handheld_staff.json create mode 100644 src/main/resources/assets/unicopia/models/item/magic_staff.json create mode 100644 src/main/resources/assets/unicopia/models/item/meadowbrooks_staff.json create mode 100644 src/main/resources/assets/unicopia/textures/item/magic_staff_base.png create mode 100644 src/main/resources/assets/unicopia/textures/item/magic_staff_magic.png create mode 100644 src/main/resources/assets/unicopia/textures/item/meadowbrooks_staff.png create mode 100644 src/main/resources/data/unicopia/advancements/recipes/meadowbrooks_staff.json create mode 100644 src/main/resources/data/unicopia/recipes/magic_staff.json create mode 100644 src/main/resources/data/unicopia/recipes/meadowbrooks_staff.json create mode 100644 src/main/resources/data/unicopia/tags/items/magic_spell_base.json diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java index 12f702d9..0b7b5a06 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java @@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.AmuletItem; +import com.minelittlepony.unicopia.item.ChargeableItem; import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.util.TraceHelper; import com.minelittlepony.unicopia.util.VecHelper; @@ -89,13 +90,13 @@ public class UnicornCastingAbility implements Ability { if (amulet.getResult().isAccepted()) { ItemStack stack = amulet.getValue(); - AmuletItem item = (AmuletItem)stack.getItem(); + ChargeableItem item = (ChargeableItem)stack.getItem(); if (item.canCharge(stack)) { float amount = -Math.min(player.getMagicalReserves().getMana().get(), item.getChargeRemainder(stack)); if (amount < 0) { - AmuletItem.consumeEnergy(stack, amount); + ChargeableItem.consumeEnergy(stack, amount); player.getMagicalReserves().getMana().add(amount * player.getMagicalReserves().getMana().getMax()); player.asWorld().playSoundFromEntity(null, player.asEntity(), USounds.ITEM_AMULET_RECHARGE, SoundCategory.PLAYERS, 1, 1); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java index 0ba42ac1..f0f8bc15 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java @@ -8,7 +8,6 @@ import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.entity.UEntities; -import com.minelittlepony.unicopia.item.GemstoneItem; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; @@ -59,7 +58,7 @@ public final class ThrowableSpell extends AbstractDelegatingSpell { MagicProjectileEntity projectile = UEntities.MAGIC_BEAM.create(world); projectile.setPosition(entity.getX(), entity.getEyeY() - 0.1F, entity.getZ()); projectile.setOwner(entity); - projectile.setItem(GemstoneItem.enchant(UItems.GEMSTONE.getDefaultStack(), spell.getType())); + projectile.setItem(UItems.GEMSTONE.getDefaultStack(spell.getType())); projectile.getSpellSlot().put(spell); projectile.setVelocity(entity, entity.getPitch(), entity.getYaw(), 0, 1.5F, divergance); projectile.setNoGravity(true); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/IngredientWithSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/IngredientWithSpell.java index 797cbe6e..c2494f83 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/IngredientWithSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/IngredientWithSpell.java @@ -9,7 +9,7 @@ import org.jetbrains.annotations.Nullable; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; -import com.minelittlepony.unicopia.item.GemstoneItem; +import com.minelittlepony.unicopia.item.EnchantableItem; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketByteBuf; @@ -32,7 +32,7 @@ public class IngredientWithSpell implements Predicate { @Override public boolean test(ItemStack t) { boolean stackMatch = stack.map(m -> m.test(t)).orElse(true); - boolean spellMatch = spell.map(m -> GemstoneItem.getSpellKey(t).equals(m)).orElse(true); + boolean spellMatch = spell.map(m -> EnchantableItem.getSpellKey(t).equals(m)).orElse(true); return stackMatch && spellMatch; } @@ -41,7 +41,7 @@ public class IngredientWithSpell implements Predicate { stacks = stack.stream() .map(Ingredient::getMatchingStacks) .flatMap(Arrays::stream) - .map(stack -> spell.map(spell -> GemstoneItem.enchant(stack, spell)).orElse(stack)) + .map(stack -> spell.map(spell -> EnchantableItem.enchant(stack, spell)).orElse(stack)) .toArray(ItemStack[]::new); } return stacks; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellCraftingRecipe.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellCraftingRecipe.java index b6d68ed1..52c27f78 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellCraftingRecipe.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellCraftingRecipe.java @@ -8,7 +8,7 @@ import com.google.gson.JsonObject; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.container.inventory.SpellbookInventory; -import com.minelittlepony.unicopia.item.GemstoneItem; +import com.minelittlepony.unicopia.item.EnchantableItem; import com.minelittlepony.unicopia.item.URecipes; import com.minelittlepony.unicopia.util.InventoryUtil; import com.mojang.datafixers.util.Pair; @@ -137,7 +137,7 @@ public class SpellCraftingRecipe implements SpellbookRecipe { SpellType spell = SpellType.getKey(Identifier.tryParse(JsonHelper.getString(json, "spell", ""))); if (spell != SpellType.EMPTY_KEY) { - return GemstoneItem.enchant(stack, spell); + return EnchantableItem.enchant(stack, spell); } return stack; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellDuplicatingRecipe.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellDuplicatingRecipe.java index 89635d45..3c77049c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellDuplicatingRecipe.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellDuplicatingRecipe.java @@ -29,7 +29,7 @@ public class SpellDuplicatingRecipe implements SpellbookRecipe { public void buildCraftingTree(CraftingTreeBuilder builder) { ItemStack[] spells = SpellType.REGISTRY.stream() .filter(SpellType::isObtainable) - .map(type -> GemstoneItem.enchant(UItems.GEMSTONE.getDefaultStack(), type)) + .map(UItems.GEMSTONE::getDefaultStack) .toArray(ItemStack[]::new); builder.input(UItems.BOTCHED_GEM.getDefaultStack()); builder.input(spells); @@ -47,16 +47,16 @@ public class SpellDuplicatingRecipe implements SpellbookRecipe { return InventoryUtil.stream(inventory) .limit(inventory.size() - 1) .filter(i -> !i.isEmpty()) - .noneMatch(i -> !i.isOf(UItems.GEMSTONE) || !GemstoneItem.isEnchanted(i)) + .noneMatch(i -> !i.isOf(UItems.GEMSTONE) || !EnchantableItem.isEnchanted(i)) && material.test(stack) - && !GemstoneItem.isEnchanted(stack); + && !EnchantableItem.isEnchanted(stack); } @Override public ItemStack craft(SpellbookInventory inventory) { return InventoryUtil.stream(inventory) .filter(i -> i.isOf(UItems.GEMSTONE)) - .filter(GemstoneItem::isEnchanted) + .filter(EnchantableItem::isEnchanted) .map(stack -> stack.copy()) .map(stack -> { stack.setCount(2); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellEnhancingRecipe.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellEnhancingRecipe.java index 13070456..4e9879cf 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellEnhancingRecipe.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellEnhancingRecipe.java @@ -37,7 +37,7 @@ public class SpellEnhancingRecipe implements SpellbookRecipe { @Override public boolean matches(SpellbookInventory inventory, World world) { ItemStack stack = inventory.getItemToModify(); - return material.test(stack) && GemstoneItem.isEnchanted(stack); + return material.test(stack) && EnchantableItem.isEnchanted(stack); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellShapedCraftingRecipe.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellShapedCraftingRecipe.java new file mode 100644 index 00000000..cbc2f641 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/SpellShapedCraftingRecipe.java @@ -0,0 +1,48 @@ +package com.minelittlepony.unicopia.ability.magic.spell.crafting; + +import com.google.gson.JsonObject; +import com.minelittlepony.unicopia.item.EnchantableItem; +import com.minelittlepony.unicopia.item.URecipes; +import com.minelittlepony.unicopia.util.InventoryUtil; + +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.recipe.ShapedRecipe; +import net.minecraft.util.Identifier; + +public class SpellShapedCraftingRecipe extends ShapedRecipe { + + public SpellShapedCraftingRecipe(ShapedRecipe recipe) { + super(recipe.getId(), recipe.getGroup(), recipe.getCategory(), recipe.getWidth(), recipe.getHeight(), recipe.getIngredients(), recipe.getOutput()); + } + + @Override + public ItemStack craft(CraftingInventory inventory) { + return InventoryUtil.stream(inventory) + .filter(stack -> stack.getItem() instanceof EnchantableItem) + .filter(EnchantableItem::isEnchanted) + .map(stack -> ((EnchantableItem)stack.getItem()).getSpellEffect(stack)) + .findFirst() + .map(spell -> spell.traits().applyTo(EnchantableItem.enchant(super.craft(inventory), spell.type()))) + .orElseGet(() -> super.craft(inventory)); + } + + @Override + public RecipeSerializer getSerializer() { + return URecipes.CRAFTING_MAGICAL_SERIALIZER; + } + + public static class Serializer extends ShapedRecipe.Serializer { + @Override + public ShapedRecipe read(Identifier id, JsonObject json) { + return new SpellShapedCraftingRecipe(super.read(id, json)); + } + + @Override + public ShapedRecipe read(Identifier id, PacketByteBuf buffer) { + return new SpellShapedCraftingRecipe(super.read(id, buffer)); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java index 93e1823a..add82ba7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java @@ -17,7 +17,6 @@ import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; -import com.minelittlepony.unicopia.item.GemstoneItem; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.util.RegistryUtils; @@ -92,7 +91,7 @@ public final class SpellType implements Affine, SpellPredicate< this.factory = factory; this.traits = traits; traited = new CustomisedSpellType<>(this, traits); - defaultStack = GemstoneItem.enchant(UItems.GEMSTONE.getDefaultStack(), this); + defaultStack = UItems.GEMSTONE.getDefaultStack(this); } public boolean isObtainable() { diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index a43009db..c23f0271 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -17,7 +17,7 @@ import com.minelittlepony.unicopia.client.render.*; import com.minelittlepony.unicopia.client.render.entity.*; import com.minelittlepony.unicopia.entity.UEntities; import com.minelittlepony.unicopia.item.ChameleonItem; -import com.minelittlepony.unicopia.item.GemstoneItem; +import com.minelittlepony.unicopia.item.EnchantableItem; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.particle.UParticles; @@ -117,11 +117,17 @@ public interface URenderers { PolearmRenderer.register(UItems.DIAMOND_POLEARM); PolearmRenderer.register(UItems.NETHERITE_POLEARM); ModelPredicateProviderRegistry.register(UItems.GEMSTONE, new Identifier("affinity"), (stack, world, entity, seed) -> { - return GemstoneItem.isEnchanted(stack) ? 1 + GemstoneItem.getSpellKey(stack).getAffinity().ordinal() : 0; + return EnchantableItem.isEnchanted(stack) ? 1 + EnchantableItem.getSpellKey(stack).getAffinity().ordinal() : 0; }); ColorProviderRegistry.ITEM.register((stack, i) -> { - return i > 0 || !GemstoneItem.isEnchanted(stack) ? -1 : GemstoneItem.getSpellKey(stack).getColor(); + return i > 0 || !EnchantableItem.isEnchanted(stack) ? -1 : EnchantableItem.getSpellKey(stack).getColor(); }, UItems.GEMSTONE); + ColorProviderRegistry.ITEM.register((stack, i) -> { + if (i == 1 && EnchantableItem.isEnchanted(stack)) { + return EnchantableItem.getSpellKey(stack).getColor(); + } + return -1; + }, UItems.MAGIC_STAFF); BlockColorProvider tintedProvider = (state, view, pos, color) -> { if (view == null || pos == null) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/UTradeOffers.java b/src/main/java/com/minelittlepony/unicopia/entity/UTradeOffers.java index f723c414..1b541108 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/UTradeOffers.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/UTradeOffers.java @@ -5,7 +5,7 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.effect.UPotions; -import com.minelittlepony.unicopia.item.GemstoneItem; +import com.minelittlepony.unicopia.item.EnchantableItem; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.util.RegistryUtils; @@ -43,7 +43,7 @@ public interface UTradeOffers { TradeOfferHelper.registerWanderingTraderOffers(1, factories -> { factories.add(buyTiered(UItems.GEMSTONE, 30, UItems.GOLDEN_FEATHER, 1, UItems.GOLDEN_WING, 1, 30, 2, 0.05F)); - factories.add((e, rng) -> new TradeOffer(new ItemStack(UItems.GEMSTONE, 3), GemstoneItem.enchant(UItems.GEMSTONE.getDefaultStack(), SpellType.REGISTRY.getRandom(rng).get().value()), 20, 1, 0.05F)); + factories.add((e, rng) -> new TradeOffer(new ItemStack(UItems.GEMSTONE, 3), EnchantableItem.enchant(UItems.GEMSTONE.getDefaultStack(), SpellType.REGISTRY.getRandom(rng).get().value()), 20, 1, 0.05F)); factories.add(buy(UItems.GEMSTONE, 20, UItems.HAY_FRIES, 5, 50, 3, 0.06F)); factories.add(buy(Items.WHEAT, 17, UItems.HAY_BURGER, 1, 10, 6, 0.08F)); factories.add(buy(ItemTags.SMALL_FLOWERS, 2, UItems.DAFFODIL_DAISY_SANDWICH, 1, 10, 6, 0.08F)); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java index d53a20ed..2bdd554a 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java @@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.entity.player; import com.google.common.collect.Streams; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; -import com.minelittlepony.unicopia.item.GemstoneItem; +import com.minelittlepony.unicopia.item.EnchantableItem; import com.minelittlepony.unicopia.util.NbtSerialisable; import net.minecraft.nbt.NbtCompound; @@ -36,8 +36,8 @@ public class PlayerCharmTracker implements NbtSerialisable { public TypedActionResult> getSpellInHand(Hand hand) { return Streams.stream(pony.asEntity().getHandItems()) - .filter(GemstoneItem::isEnchanted) - .map(stack -> GemstoneItem.consumeSpell(stack, pony.asEntity(), null)) + .filter(EnchantableItem::isEnchanted) + .map(stack -> EnchantableItem.consumeSpell(stack, pony.asEntity(), null)) .findFirst() .orElse(getEquippedSpell(hand).toAction()); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index 31a933f3..0f819cbf 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.entity.*; import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; import com.minelittlepony.unicopia.entity.player.MagicReserves.Bar; import com.minelittlepony.unicopia.item.AmuletItem; +import com.minelittlepony.unicopia.item.ChargeableItem; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.particle.*; @@ -389,9 +390,9 @@ public class PlayerPhysics extends EntityPhysics implements Tickab minDamage *= 3; } - AmuletItem.consumeEnergy(stack, energyConsumed); + ChargeableItem.consumeEnergy(stack, energyConsumed); - if (AmuletItem.getEnergy(stack) < 9) { + if (ChargeableItem.getEnergy(stack) < 9) { entity.playSound(USounds.ITEM_ICARUS_WINGS_WARN, 0.13F, 0.5F); } diff --git a/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java b/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java index 1defd4d5..110f60b1 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java @@ -27,7 +27,7 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.world.World; -public class AmuletItem extends WearableItem { +public class AmuletItem extends WearableItem implements ChargeableItem { private final int maxEnergy; @@ -57,7 +57,7 @@ public class AmuletItem extends WearableItem { } if (isChargable()) { - list.add(Text.translatable("item.unicopia.amulet.energy", (int)Math.floor(getEnergy(stack)), maxEnergy)); + list.add(Text.translatable("item.unicopia.amulet.energy", (int)Math.floor(ChargeableItem.getEnergy(stack)), getMaxCharge())); } } @@ -73,7 +73,7 @@ public class AmuletItem extends WearableItem { @Override public boolean hasGlint(ItemStack stack) { - return !isChargable() || stack.hasEnchantments() || getEnergy(stack) > 0; + return !isChargable() || stack.hasEnchantments() || ChargeableItem.getEnergy(stack) > 0; } @Override @@ -82,13 +82,18 @@ public class AmuletItem extends WearableItem { } public boolean isApplicable(ItemStack stack) { - return stack.getItem() == this && (!isChargable() || getEnergy(stack) > 0); + return stack.getItem() == this && (!isChargable() || ChargeableItem.getEnergy(stack) > 0); } public boolean isApplicable(LivingEntity entity) { return isApplicable(getForEntity(entity)); } + @Override + public int getMaxCharge() { + return maxEnergy; + } + public static ItemStack getForEntity(LivingEntity entity) { return TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.NECKLACE) .filter(stack -> stack.getItem() instanceof AmuletItem) @@ -96,34 +101,6 @@ public class AmuletItem extends WearableItem { .orElse(ItemStack.EMPTY); } - public boolean isChargable() { - return maxEnergy > 0; - } - - public boolean canCharge(ItemStack stack) { - return isChargable() && getEnergy(stack) < maxEnergy; - } - - public float getChargeRemainder(ItemStack stack) { - return Math.max(0, maxEnergy - getEnergy(stack)); - } - - public static void consumeEnergy(ItemStack stack, float amount) { - setEnergy(stack, getEnergy(stack) - amount); - } - - public static float getEnergy(ItemStack stack) { - return stack.hasNbt() && stack.getNbt().contains("energy") ? stack.getNbt().getFloat("energy") : 0; - } - - public static void setEnergy(ItemStack stack, float energy) { - if (energy <= 0) { - stack.removeSubNbt("energy"); - } else { - stack.getOrCreateNbt().putFloat("energy", energy); - } - } - public static class ModifiersBuilder { private static final UUID SLOT_UUID = UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"); diff --git a/src/main/java/com/minelittlepony/unicopia/item/ChargeableItem.java b/src/main/java/com/minelittlepony/unicopia/item/ChargeableItem.java new file mode 100644 index 00000000..b5edcce2 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/ChargeableItem.java @@ -0,0 +1,56 @@ +package com.minelittlepony.unicopia.item; + +import net.minecraft.item.ItemStack; + +public interface ChargeableItem { + + int getMaxCharge(); + + default int getDefaultCharge() { + return 0; + } + + default boolean isChargable() { + return getMaxCharge() > 0; + } + + default boolean hasCharge(ItemStack stack) { + return getEnergy(stack) > 0; + } + + default ItemStack recharge(ItemStack stack) { + return setEnergy(stack, getMaxCharge()); + } + + default boolean canCharge(ItemStack stack) { + return isChargable() && getEnergy(stack) < getMaxCharge(); + } + + default float getChargeRemainder(ItemStack stack) { + return Math.max(0, getMaxCharge() - getEnergy(stack)); + } + + default void onDischarge(ItemStack stack) { + + } + + static void consumeEnergy(ItemStack stack, float amount) { + setEnergy(stack, getEnergy(stack) - amount); + if (stack.getItem() instanceof ChargeableItem c) { + c.onDischarge(stack); + } + } + + static float getEnergy(ItemStack stack) { + return stack.hasNbt() && stack.getNbt().contains("energy") ? stack.getNbt().getFloat("energy") : (stack.getItem() instanceof ChargeableItem c) ? c.getDefaultCharge() : 0; + } + + static ItemStack setEnergy(ItemStack stack, float energy) { + if (energy <= 0) { + stack.removeSubNbt("energy"); + } else { + stack.getOrCreateNbt().putFloat("energy", energy); + } + return stack; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/EnchantableItem.java b/src/main/java/com/minelittlepony/unicopia/item/EnchantableItem.java new file mode 100644 index 00000000..b068fa0d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/EnchantableItem.java @@ -0,0 +1,86 @@ +package com.minelittlepony.unicopia.item; + +import java.util.function.Predicate; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.Affinity; +import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemConvertible; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; +import net.minecraft.util.Identifier; +import net.minecraft.util.TypedActionResult; + +public interface EnchantableItem extends ItemConvertible { + + default ItemStack getDefaultStack(SpellType spell) { + return enchant(asItem().getDefaultStack(), spell); + } + + default CustomisedSpellType getSpellEffect(ItemStack stack) { + return EnchantableItem.getSpellKey(stack).withTraits(SpellTraits.of(stack)); + } + + static TypedActionResult> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable Predicate> filter) { + + if (!isEnchanted(stack)) { + return TypedActionResult.pass(null); + } + + SpellType key = EnchantableItem.getSpellKey(stack); + + if (key.isEmpty()) { + return TypedActionResult.fail(null); + } + + CustomisedSpellType result = key.withTraits(SpellTraits.of(stack)); + + if (filter != null && !filter.test(result)) { + return TypedActionResult.fail(null); + } + + if (!player.world.isClient) { + player.swingHand(player.getStackInHand(Hand.OFF_HAND) == stack ? Hand.OFF_HAND : Hand.MAIN_HAND); + + if (stack.getCount() == 1) { + unenchant(stack); + } else { + player.giveItemStack(unenchant(stack.split(1))); + } + } + + return TypedActionResult.consume(result); + } + + static boolean isEnchanted(ItemStack stack) { + return !stack.isEmpty() && stack.hasNbt() && stack.getNbt().contains("spell"); + } + + static ItemStack enchant(ItemStack stack, SpellType type) { + return enchant(stack, type, type.getAffinity()); + } + + static ItemStack enchant(ItemStack stack, SpellType type, Affinity affinity) { + if (type.isEmpty()) { + return unenchant(stack); + } + stack.getOrCreateNbt().putString("spell", type.getId().toString()); + return type.getTraits().applyTo(stack); + } + + static ItemStack unenchant(ItemStack stack) { + stack.removeSubNbt("spell"); + stack.removeSubNbt("spell_traits"); + return stack; + } + + static SpellType getSpellKey(ItemStack stack) { + return SpellType.getKey(isEnchanted(stack) ? new Identifier(stack.getNbt().getString("spell")) : SpellType.EMPTY_ID); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java b/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java new file mode 100644 index 00000000..67ac4723 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/EnchantedStaffItem.java @@ -0,0 +1,206 @@ +package com.minelittlepony.unicopia.item; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.SpellPredicate; +import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.entity.CastSpellEntity; +import com.minelittlepony.unicopia.entity.UEntities; +import com.minelittlepony.unicopia.entity.player.Pony; + +import net.minecraft.client.item.TooltipContext; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class EnchantedStaffItem extends StaffItem implements EnchantableItem, ChargeableItem { + + private static final Map, SpellType> ENTITY_TYPE_TO_SPELL = new HashMap<>(); + public static SpellType register(EntityType entityType, SpellType spellType) { + ENTITY_TYPE_TO_SPELL.put(entityType, spellType); + return spellType; + } + + public static SpellType getSpellType(Entity entity) { + if (entity instanceof CastSpellEntity cast) { + return cast.getSpellSlot().get(c -> !SpellPredicate.IS_PLACED.test(c), true).map(Spell::getType).orElse(SpellType.empty()); + } + if (entity instanceof PlayerEntity player) { + return Pony.of(player).getCharms().getEquippedSpell(Hand.MAIN_HAND).type(); + } + return ENTITY_TYPE_TO_SPELL.getOrDefault(entity.getType(), SpellType.empty()); + } + + static { + register(EntityType.DROWNED, SpellType.BUBBLE); + register(EntityType.DOLPHIN, SpellType.BUBBLE); + register(EntityType.BLAZE, SpellType.FIRE_BOLT); + register(EntityType.CHICKEN, SpellType.FEATHER_FALL); + register(EntityType.CREEPER, SpellType.CATAPULT); + register(EntityType.HUSK, SpellType.HYDROPHOBIC); + register(EntityType.SNOW_GOLEM, SpellType.FROST); + register(EntityType.FIREBALL, SpellType.FLAME); + register(EntityType.SMALL_FIREBALL, SpellType.FLAME); + register(EntityType.ENDER_DRAGON, SpellType.DISPLACEMENT); + register(EntityType.GUARDIAN, SpellType.AWKWARD); + register(EntityType.ELDER_GUARDIAN, SpellType.AWKWARD); + register(EntityType.DRAGON_FIREBALL, SpellType.INFERNAL); + register(EntityType.CAVE_SPIDER, SpellType.REVEALING); + register(EntityType.ZOMBIE, SpellType.NECROMANCY); + register(EntityType.VEX, SpellType.NECROMANCY); + register(EntityType.SKELETON, SpellType.CATAPULT); + register(EntityType.WITHER_SKELETON, SpellType.CATAPULT); + register(EntityType.SKELETON_HORSE, SpellType.CATAPULT); + register(UEntities.TWITTERMITE, SpellType.LIGHT); + } + + public EnchantedStaffItem(Settings settings) { + super(settings.maxDamage(500)); + } + + @Override + public ItemStack getDefaultStack() { + return EnchantableItem.enchant(super.getDefaultStack(), SpellType.FIRE_BOLT); + } + + @Override + public void appendTooltip(ItemStack stack, @Nullable World world, List lines, TooltipContext context) { + + if (EnchantableItem.isEnchanted(stack)) { + SpellType key = EnchantableItem.getSpellKey(stack); + lines.add(Text.translatable(key.getTranslationKey()).formatted(key.getAffinity().getColor())); + lines.add(Text.translatable(getTranslationKey(stack) + ".charges", (int)Math.floor(ChargeableItem.getEnergy(stack)), getMaxCharge())); + } + } + + @Override + public ActionResult useOnEntity(ItemStack stack, PlayerEntity player, LivingEntity target, Hand hand) { + if (EnchantableItem.isEnchanted(stack)) { + return ActionResult.PASS; + } + + super.useOnEntity(stack, player, target, hand); + + SpellType type = getSpellType(target); + if (!type.isEmpty()) { + target.setHealth(1); + target.setFrozenTicks(9000); + player.setStackInHand(hand, recharge(EnchantableItem.enchant(stack, type))); + } + return ActionResult.SUCCESS; + } + + @Override + public TypedActionResult use(World world, PlayerEntity player, Hand hand) { + ItemStack itemstack = player.getStackInHand(hand); + player.setCurrentHand(hand); + return TypedActionResult.consume(itemstack); + } + + @Override + public void onStoppedUsing(ItemStack stack, World world, LivingEntity entity, int timeLeft) { + int i = getMaxUseTime(stack) - timeLeft; + + if (EnchantableItem.isEnchanted(stack) && hasCharge(stack)) { + if (i > 20) { + Pony.of(entity).ifPresent(pony -> { + pony.subtractEnergyCost(4); + stack.damage(1, pony.asEntity(), p -> p.sendEquipmentBreakStatus(EquipmentSlot.MAINHAND)); + getSpellEffect(stack).create().toThrowable().throwProjectile(pony); + }); + ChargeableItem.consumeEnergy(stack, 1); + } else if (i > 5) { + Pony.of(entity).ifPresent(pony -> { + pony.subtractEnergyCost(4); + stack.damage(1, pony.asEntity(), p -> p.sendEquipmentBreakStatus(EquipmentSlot.MAINHAND)); + getSpellEffect(stack).create().toThrowable().throwProjectile(pony); + }); + ChargeableItem.consumeEnergy(stack, 1); + } + } + } + + @Override + protected boolean castContainedEffect(ItemStack stack, LivingEntity target, LivingEntity attacker) { + if (attacker.isSneaking() && hasCharge(stack)) { + stack.damage(50, attacker, p -> p.sendEquipmentBreakStatus(EquipmentSlot.MAINHAND)); + Caster.of(attacker).ifPresent(c -> c.subtractEnergyCost(4)); + Caster.of(target).ifPresent(c -> getSpellEffect(stack).create().apply(c)); + ChargeableItem.consumeEnergy(stack, 1); + + return true; + } + + return false; + } + + @Override + public void usageTick(World world, LivingEntity entity, ItemStack stack, int ticksRemaining) { + if (entity instanceof LivingEntity) { + LivingEntity living = entity; + + if (living.getActiveItem().getItem() == this) { + Vec3d eyes = entity.getCameraPosVec(1); + + float i = getMaxUseTime(stack) - ticksRemaining; + + world.addParticle(i > 150 ? ParticleTypes.LARGE_SMOKE : ParticleTypes.CLOUD, eyes.x, eyes.y, eyes.z, + (world.random.nextGaussian() - 0.5) / 10, + (world.random.nextGaussian() - 0.5) / 10, + (world.random.nextGaussian() - 0.5) / 10 + ); + world.playSound(null, entity.getBlockPos(), SoundEvents.ENTITY_GUARDIAN_ATTACK, SoundCategory.PLAYERS, 1, i / 20); + + if (i > 200) { + living.clearActiveItem(); + living.damage(DamageSource.MAGIC, 1); + if (EnchantableItem.isEnchanted(stack) && hasCharge(stack)) { + Caster.of(entity).ifPresent(c -> getSpellEffect(stack).create().apply(c)); + ChargeableItem.consumeEnergy(stack, 1); + } + } + } + } + } + + @Override + public int getMaxUseTime(ItemStack stack) { + return 72000; + } + + @Override + public int getMaxCharge() { + return 3; + } + + @Override + public int getDefaultCharge() { + return 3; + } + + @Override + public void onDischarge(ItemStack stack) { + if ((stack.hasNbt() && stack.getNbt().contains("energy") ? stack.getNbt().getFloat("energy") : 0) == 0) { + EnchantableItem.unenchant(stack); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java b/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java index 4d04759e..aa0d6fde 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java @@ -8,10 +8,8 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Unicopia; -import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; -import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.client.FlowingText; import com.minelittlepony.unicopia.entity.player.PlayerCharmTracker; import com.minelittlepony.unicopia.entity.player.Pony; @@ -25,11 +23,10 @@ import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.Hand; -import net.minecraft.util.Identifier; import net.minecraft.util.TypedActionResult; import net.minecraft.world.World; -public class GemstoneItem extends Item implements MultiItem { +public class GemstoneItem extends Item implements MultiItem, EnchantableItem { public GemstoneItem(Settings settings) { super(settings); @@ -43,16 +40,16 @@ public class GemstoneItem extends Item implements MultiItem { ItemStack stack = user.getStackInHand(hand); PlayerCharmTracker charms = Pony.of(user).getCharms(); - TypedActionResult> spell = consumeSpell(stack, user, ((Predicate>)charms.getEquippedSpell(hand)::equals).negate()); + TypedActionResult> spell = EnchantableItem.consumeSpell(stack, user, ((Predicate>)charms.getEquippedSpell(hand)::equals).negate()); CustomisedSpellType existing = charms.getEquippedSpell(hand); if (!existing.isEmpty()) { if (stack.getCount() == 1) { - stack = existing.traits().applyTo(enchant(stack, existing.type())); + stack = existing.traits().applyTo(EnchantableItem.enchant(stack, existing.type())); } else { - user.giveItemStack(existing.traits().applyTo(enchant(stack.split(1), existing.type()))); + user.giveItemStack(existing.traits().applyTo(EnchantableItem.enchant(stack.split(1), existing.type()))); } } @@ -76,8 +73,8 @@ public class GemstoneItem extends Item implements MultiItem { public void appendTooltip(ItemStack stack, @Nullable World world, List lines, TooltipContext tooltipContext) { super.appendTooltip(stack, world, lines, tooltipContext); - if (isEnchanted(stack)) { - SpellType key = getSpellKey(stack); + if (EnchantableItem.isEnchanted(stack)) { + SpellType key = EnchantableItem.getSpellKey(stack); MutableText line = Text.translatable(key.getTranslationKey() + ".lore").formatted(key.getAffinity().getColor()); @@ -94,81 +91,26 @@ public class GemstoneItem extends Item implements MultiItem { return Arrays.stream(Affinity.VALUES) .flatMap(i -> SpellType.byAffinity(i).stream() .filter(type -> type.isObtainable()) - .map(type -> enchant(getDefaultStack(), type, i)) + .map(type -> EnchantableItem.enchant(getDefaultStack(), type, i)) ) .toList(); } @Override public boolean hasGlint(ItemStack stack) { - return super.hasGlint(stack) || (Unicopia.SIDE.getPlayerSpecies().canCast() && isEnchanted(stack)); + return super.hasGlint(stack) || (Unicopia.SIDE.getPlayerSpecies().canCast() && EnchantableItem.isEnchanted(stack)); } @Override public Text getName(ItemStack stack) { - if (isEnchanted(stack)) { + if (EnchantableItem.isEnchanted(stack)) { if (!Unicopia.SIDE.getPlayerSpecies().canCast()) { return Text.translatable(getTranslationKey(stack) + ".obfuscated"); } - return Text.translatable(getTranslationKey(stack) + ".enchanted", getSpellKey(stack).getName()); + return Text.translatable(getTranslationKey(stack) + ".enchanted", EnchantableItem.getSpellKey(stack).getName()); } return super.getName(); } - public static TypedActionResult> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable Predicate> filter) { - - if (!isEnchanted(stack)) { - return TypedActionResult.pass(null); - } - - SpellType key = getSpellKey(stack); - - if (key.isEmpty()) { - return TypedActionResult.fail(null); - } - - CustomisedSpellType result = key.withTraits(SpellTraits.of(stack)); - - if (filter != null && !filter.test(result)) { - return TypedActionResult.fail(null); - } - - if (!player.world.isClient) { - player.swingHand(player.getStackInHand(Hand.OFF_HAND) == stack ? Hand.OFF_HAND : Hand.MAIN_HAND); - - if (stack.getCount() == 1) { - unenchant(stack); - } else { - player.giveItemStack(unenchant(stack.split(1))); - } - } - - return TypedActionResult.consume(result); - } - - public static boolean isEnchanted(ItemStack stack) { - return !stack.isEmpty() && stack.hasNbt() && stack.getNbt().contains("spell"); - } - - public static ItemStack enchant(ItemStack stack, SpellType type) { - return enchant(stack, type, type.getAffinity()); - } - - public static ItemStack enchant(ItemStack stack, SpellType type, Affinity affinity) { - if (type.isEmpty()) { - return unenchant(stack); - } - stack.getOrCreateNbt().putString("spell", type.getId().toString()); - return type.getTraits().applyTo(stack); - } - - public static ItemStack unenchant(ItemStack stack) { - stack.removeSubNbt("spell"); - return stack; - } - - public static SpellType getSpellKey(ItemStack stack) { - return SpellType.getKey(isEnchanted(stack) ? new Identifier(stack.getNbt().getString("spell")) : SpellType.EMPTY_ID); - } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/StaffItem.java b/src/main/java/com/minelittlepony/unicopia/item/StaffItem.java new file mode 100644 index 00000000..07f46a74 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/StaffItem.java @@ -0,0 +1,99 @@ +package com.minelittlepony.unicopia.item; + +import java.util.List; +import java.util.UUID; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.minelittlepony.unicopia.entity.UEntityAttributes; + +import net.minecraft.block.Blocks; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.entity.EntityDimensions; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.attribute.EntityAttribute; +import net.minecraft.entity.attribute.EntityAttributeModifier; +import net.minecraft.entity.attribute.EntityAttributeModifier.Operation; +import net.minecraft.entity.attribute.EntityAttributes; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.SwordItem; +import net.minecraft.item.ToolMaterials; +import net.minecraft.particle.BlockStateParticleEffect; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Formatting; +import net.minecraft.util.Hand; +import net.minecraft.util.UseAction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +public class StaffItem extends SwordItem { + + protected static final UUID ATTACK_REACH_MODIFIER = UUID.fromString("FA235E1C-4280-A865-B01B-CBAE9985ACA3"); + + public StaffItem(Settings settings) { + super(ToolMaterials.WOOD, 2, 4, settings); + } + + @Override + public ActionResult useOnEntity(ItemStack stack, PlayerEntity player, LivingEntity target, Hand hand) { + World w = player.getEntityWorld(); + + EntityDimensions dims = target.getDimensions(target.getPose()); + + for (int i = 0; i < 130; i++) { + w.addParticle(new BlockStateParticleEffect(ParticleTypes.BLOCK, Blocks.OAK_LOG.getDefaultState()), + target.getX() + (target.world.random.nextFloat() - 0.5F) * (dims.width + 1), + (target.getY() + dims.height / 2) + (target.world.random.nextFloat() - 0.5F) * dims.height, + target.getZ() + (target.world.random.nextFloat() - 0.5F) * (dims.width + 1), + 0, 0, 0 + ); + } + + return ActionResult.SUCCESS; + } + + @Override + public void appendTooltip(ItemStack stack, World world, List tooltip, TooltipContext context) { + tooltip.add(Text.translatable(getTranslationKey(stack) + ".lore").formatted(Formatting.GRAY)); + } + + @Override + public boolean postHit(ItemStack stack, LivingEntity entity, LivingEntity attacker) { + super.postHit(stack, entity, attacker); + + return castContainedEffect(stack, entity, attacker); + } + + protected boolean castContainedEffect(ItemStack stack, LivingEntity target, LivingEntity attacker) { + target.getEntityWorld().playSound(null, target.getBlockPos(), SoundEvents.ENTITY_PLAYER_ATTACK_CRIT, attacker.getSoundCategory(), 1, 1); + + target.takeKnockback(attacker.getVelocity().subtract(target.getVelocity()).horizontalLength(), + MathHelper.sin(attacker.getYaw() * 0.017453292F), + -MathHelper.cos(attacker.getYaw() * 0.017453292F) + ); + + return true; + } + + @Override + public UseAction getUseAction(ItemStack stack) { + return UseAction.BOW; + } + + @Override + public Multimap getAttributeModifiers(EquipmentSlot slot) { + Multimap multimap = HashMultimap.create(); + + if (slot == EquipmentSlot.MAINHAND) { + multimap.put(EntityAttributes.GENERIC_ATTACK_DAMAGE, new EntityAttributeModifier(ATTACK_DAMAGE_MODIFIER_ID, "Weapon modifier", getAttackDamage(), Operation.ADDITION)); + multimap.put(UEntityAttributes.EXTENDED_ATTACK_DISTANCE, new EntityAttributeModifier(ATTACK_REACH_MODIFIER, "Weapon modifier", 3, Operation.ADDITION)); + } + + return multimap; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index 99272021..896ae225 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -56,7 +56,7 @@ public interface UItems { Item CRYSTAL_HEART = register("crystal_heart", new CrystalHeartItem(new Item.Settings().maxCount(1)), ItemGroups.TOOLS); Item CRYSTAL_SHARD = register("crystal_shard", new Item(new Item.Settings()), ItemGroups.NATURAL); - Item GEMSTONE = register("gemstone", new GemstoneItem(new Item.Settings()), ItemGroups.NATURAL); + GemstoneItem GEMSTONE = register("gemstone", new GemstoneItem(new Item.Settings()), ItemGroups.NATURAL); Item BOTCHED_GEM = register("botched_gem", new Item(new Item.Settings()), ItemGroups.NATURAL); Item PEGASUS_FEATHER = register("pegasus_feather", new Item(new Item.Settings()), ItemGroups.NATURAL); @@ -99,6 +99,9 @@ public interface UItems { Item GOLDEN_WING = register("golden_wing", new Item(new Item.Settings().rarity(Rarity.UNCOMMON)), ItemGroups.NATURAL); Item DRAGON_BREATH_SCROLL = register("dragon_breath_scroll", new DragonBreathScrollItem(new Item.Settings().rarity(Rarity.UNCOMMON)), ItemGroups.TOOLS); + Item GROGARS_BELL = register("grogars_bell", new Item(new Item.Settings().rarity(Rarity.RARE)), ItemGroups.TOOLS); + Item MEADOWBROOKS_STAFF = register("meadowbrooks_staff", new StaffItem(new Settings().rarity(Rarity.UNCOMMON).maxCount(1).maxDamage(120)), ItemGroups.TOOLS); + Item MAGIC_STAFF = register("magic_staff", new EnchantedStaffItem(new Settings().rarity(Rarity.UNCOMMON).maxCount(1).maxDamage(120)), ItemGroups.TOOLS); Item WOODEN_POLEARM = register("wooden_polearm", new PolearmItem(ToolMaterials.WOOD, 2, -3.6F, 2, new Item.Settings()), ItemGroups.COMBAT); Item STONE_POLEARM = register("stone_polearm", new PolearmItem(ToolMaterials.STONE, 2, -3.6F, 2, new Item.Settings()), ItemGroups.COMBAT); diff --git a/src/main/java/com/minelittlepony/unicopia/item/URecipes.java b/src/main/java/com/minelittlepony/unicopia/item/URecipes.java index 7c1a72c1..21ef9f4c 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/URecipes.java +++ b/src/main/java/com/minelittlepony/unicopia/item/URecipes.java @@ -10,6 +10,7 @@ import net.minecraft.loot.LootTable; import net.minecraft.recipe.Ingredient; import net.minecraft.recipe.RecipeSerializer; import net.minecraft.recipe.RecipeType; +import net.minecraft.recipe.ShapedRecipe; import net.minecraft.recipe.ShapelessRecipe; import net.minecraft.recipe.SpecialRecipeSerializer; import net.minecraft.util.Identifier; @@ -21,6 +22,7 @@ public interface URecipes { RecipeSerializer ZAP_APPLE_SERIALIZER = RecipeSerializer.register("unicopia:crafting_zap_apple", new ZapAppleRecipe.Serializer()); RecipeSerializer GLOWING_SERIALIZER = RecipeSerializer.register("unicopia:crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new)); RecipeSerializer JAR_INSERT_SERIALIZER = RecipeSerializer.register("unicopia:jar_insert", new SpecialRecipeSerializer<>(JarInsertRecipe::new)); + RecipeSerializer CRAFTING_MAGICAL_SERIALIZER = RecipeSerializer.register("unicopia:crafting_magical", new SpellShapedCraftingRecipe.Serializer()); RecipeSerializer TRAIT_REQUIREMENT = RecipeSerializer.register("unicopia:spellbook/crafting", new SpellCraftingRecipe.Serializer()); RecipeSerializer TRAIT_COMBINING = RecipeSerializer.register("unicopia:spellbook/combining", new SpellEnhancingRecipe.Serializer()); RecipeSerializer SPELL_DUPLICATING = RecipeSerializer.register("unicopia:spellbook/duplicating", new SpellDuplicatingRecipe.Serializer()); diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index ccd79266..ccac1db6 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -92,6 +92,11 @@ "item.unicopia.alicorn_amulet": "Alicorn Amulet", "item.unicopia.alicorn_amulet.lore": "Time worn: %d", + + "item.unicopia.magic_staff": "Magic Staff", + "item.unicopia.magic_staff.charges": "Charges: %d / %d", + "item.unicopia.meadowbrooks_staff": "Meadowbrook's Staff", + "item.unicopia.meadowbrooks_staff.lore": "A Heavy Stick", "item.unicopia.wooden_polearm": "Wooden Polearm", "item.unicopia.stone_polearm": "Stone Polearm", diff --git a/src/main/resources/assets/unicopia/models/item/handheld_staff.json b/src/main/resources/assets/unicopia/models/item/handheld_staff.json new file mode 100644 index 00000000..6a51bd98 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/handheld_staff.json @@ -0,0 +1,25 @@ +{ + "parent": "item/handheld", + "display": { + "thirdperson_righthand": { + "rotation": [ 0, 90, 55 ], + "translation": [ 0, 4.0, 2.5 ], + "scale": [ 1.25, 1.25, 1.25 ] + }, + "thirdperson_lefthand": { + "rotation": [ 0, -90, -55 ], + "translation": [ 0, 4.0, 2.5 ], + "scale": [ 1.25, 1.25, 1.25 ] + }, + "firstperson_righthand": { + "rotation": [ 0, 90, 25 ], + "translation": [ 0, 1.9, 0.8 ], + "scale": [ 0.88, 0.88, 0.88 ] + }, + "firstperson_lefthand": { + "rotation": [ 0, -90, -25 ], + "translation": [ 0, 1.9, 0.8 ], + "scale": [ 0.88, 0.88, 0.88 ] + } + } +} diff --git a/src/main/resources/assets/unicopia/models/item/magic_staff.json b/src/main/resources/assets/unicopia/models/item/magic_staff.json new file mode 100644 index 00000000..c484178a --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/magic_staff.json @@ -0,0 +1,7 @@ +{ + "parent": "unicopia:item/handheld_staff", + "textures": { + "layer0": "unicopia:item/magic_staff_base", + "layer1": "unicopia:item/magic_staff_magic" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/models/item/meadowbrooks_staff.json b/src/main/resources/assets/unicopia/models/item/meadowbrooks_staff.json new file mode 100644 index 00000000..1a3489bb --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/meadowbrooks_staff.json @@ -0,0 +1,6 @@ +{ + "parent": "unicopia:item/handheld_staff", + "textures": { + "layer0": "unicopia:item/meadowbrooks_staff" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/textures/item/magic_staff_base.png b/src/main/resources/assets/unicopia/textures/item/magic_staff_base.png new file mode 100644 index 0000000000000000000000000000000000000000..9e8318d83606965af8685d979160fa2059f6d009 GIT binary patch literal 1978 zcmV;r2SxaaP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1bvmK-Sz{O1&N1SGMD(dWNsvP3&PdYyLs|Y^Ku=-4<6~c5u@GB7qQXafAsbpqv^n%&9rve1>h6* zrOvAyBN!F{Bge9U7V-5M$D<`Qwb@of&Nf?ZL93LAN$em;jWP}DM_;MJMaP{ZdgjV< z%&A09T*V5BGvdV2;3!F&sIXM-BADgN7dp;O$8nVu2RDKxNUu1TS2O3}|F*XqjZr5= zgxjB3!7t`X15FfV{tYV-LgS1he*k>8=MRX*CJt5;X2k`wEo+P7=@wgJ4x$By9=%(O zW7``5BAo5v3<(&pfy7fF8<`^!a8&S<;W>+OTtESN&kbI(6A2(kd7h0mkq%q-yrz*t zAi_(K2x^jKaOIqL!MNxYF_gV{=e-X;diBZYAi)J6LWp7JVvZ7B^fAO3HKv$V)T!5? zQB{*>lQ;=-)u)hR(v(upI5cDDjMZ5)CJGlRuJ{s4ELu{@72#7|^)=L3wWgX)<0j2D z-$IK`TWYyeM<{jIeGff$?WyO1P#ZGb@FR>kbfl3l)(%$9181+yea#we)^Xku+21_pjtut!6>uhkF`JS&F>mY zjmIGODjnK(jB#?1!=Mp-va2QjKn& z;w|hi*ZkN4hkDbN10X8afvkK+)GSEbj!}YMl}&czhos_h#>qel=@6O4M_*}R?n5l? z?J9H+@Yubw7KxjX03Fo>c~_n9hXGy}Yop208KgNQ67@a4ffsiTRTcuZV2dsd?vYSw z7j`+eOmPJVXoJp48@zW9Qrl;Nh`g>=DoN3HA<*3R0&2H+Mjh7`qNQi3BcNN(S@^kb z>Y>?%w483%E8=2kYqI7v+$=5YpI{H^bOy_CWp8O>IA@=G8j^O<+0<$nYe}sk`^8F9 zg{-gpo1E?w{SIcIw}KJ(#nWu>6D0Z*Z1~?t+L9Fb8=y~sH@;hHQBZUP3H7vp>YTaK zcV{ocXoLq6t38#uBB*6YT+~kYo|-qV{=maa*}C}-$KUnTd~$Vp>X+)~if74d5Z=e2 zxer3$)()(fQ09G3@?i3-V!1Hd64Vo(>s{NHk&YsGlg+!z_%5lZO;eC&hZG z$3iLIJZLULl$Lt&s8_+OV9_FYPz%;v1SwK_u%g&YMS56jF0G)OOa4$AyW51ABI6ygm4qX?0@OV&zkb>OOLSSFNaR;qG z8A|QYbpfb8egV%W+XT&eh1}8tV`<5O>tPy_txwN+`YnZ}#niBoV0*8@ATW~4F`dc> zq-e$(?mqm|Y5}DbHyxXjQ{d>;TV?7}%vhV4Mk|v4tUHd^YN9j0*~r@XO&AB5 z9!j$YjLEzJC|99e^@3=f_D0qYr67DJA=>pieRT+cA8(31_duZFFI{KD?~sjvg8%>k M07*qoM6N<$g2W2PQ~&?~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/item/magic_staff_magic.png b/src/main/resources/assets/unicopia/textures/item/magic_staff_magic.png new file mode 100644 index 0000000000000000000000000000000000000000..63f9240cd87f10bccd4c9453761f97ef3f8a2000 GIT binary patch literal 1966 zcmV;f2T}NmP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1bvmK-Sz{O1&N1SGMD(dWNsvP3&PdYyLs|Y^Ku=-4<6~c5u@GB7qQXafAsbpqv^n%&9rve1>h6* zrOvAyBN!F{Bge9U7V-5M$D<`Qwb@of&Nf?ZL93LAN$em;jWP}DM_;MJMaP{ZdgjV< z%&A09T*V5BGvdV2;3!F&sIXM-BADgN7dp;O$8nVu2RDKxNUu1TS2O3}|F*XqjZr5= zgxjB3!7t`X15FfV{tYV-LgS1he*k>8=MRX*CJt5;X2k`wEo+P7=@wgJ4x$By9=%(O zW7``5BAo5v3<(&pfy7fF8<`^!a8&S<;W>+OTtESN&kbI(6A2(kd7h0mkq%q-yrz*t zAi_(K2x^jKaOIqL!MNxYF_gV{=e-X;diBZYAi)J6LWp7JVvZ7B^fAO3HKv$V)T!5? zQB{*>lQ;=-)u)hR(v(upI5cDDjMZ5)CJGlRuJ{s4ELu{@72#7|^)=L3wWgX)<0j2D z-$IK`TWYyeM<{jIeGff$?WyO1P#ZGb@FR>kbfl3l)(%$9181+yea#we)^Xku+21_pjtut!6>uhkF`JS&F>mY zjmIGODjnK(jB#?1!=Mp-va2QjKn& z;w|hi*ZkN4hkDbN10X8afvkK+)GSEbj!}YMl}&czhos_h#>qel=@6O4M_*}R?n5l? z?J9H+@Yubw7KxjX03Fo>c~_n9hXGy}Yop208KgNQ67@a4ffsiTRTcuZV2dsd?vYSw z7j`+eOmPJVXoJp48@zW9Qrl;Nh`g>=DoN3HA<*3R0&2H+Mjh7`qNQi3BcNN(S@^kb z>Y>?%w483%E8=2kYqI7v+$=5YpI{H^bOy_CWp8O>IA@=G8j^O<+0<$nYe}sk`^8F9 zg{-gpo1E?w{SIcIw}KJ(#nWu>6D0Z*Z1~?t+L9Fb8=y~sH@;hHQBZUP3H7vp>YTaK zcV{ocXoLq6t38#uBB*6YT+~kYo|-qV{=maa*}C}-$KUnTd~$Vp>X+)~if74d5Z=e2 zxer3$)()(fQ09G3@?i3-V!1Hd64Vo(>s{NHk&YsGlg+!z_%5l;wZ`{cv9tn|#=->Mz=3V=HnB{JWlCQEJPSZ(q`=Dum!oamaXj98{-cD^ z%UESeMz^L>~t<<1W z^K`a$e#t_%b4W2Myf4Co5}0w6KH@=i;qQ2+n{07*qoM6N<$g8qBA AjQ{`u literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/unicopia/textures/item/meadowbrooks_staff.png b/src/main/resources/assets/unicopia/textures/item/meadowbrooks_staff.png new file mode 100644 index 0000000000000000000000000000000000000000..230eedf5d33a1078fd9068ce25b58fb847020157 GIT binary patch literal 3216 zcmV;B3~%#^P)uJ@VVD_UC<6{NG_fI~0ue<-1QkJoA_k0xBC#Thg@9ne9*`iQ#9$Or zQF$}6R&?d%y_c8YA7_1QpS|}zXYYO1x&V;8{kgn!SPFnNo`4_X6{c}T{8k*B#$jdxfFg<9uYy1K45IaYvHg`_dOZM)Sy63ve6hvv z1)yUy0P^?0*fb9UASvow`@mQCp^4`uNg&9uGcn1|&Nk+9SjOUl{-OWr@Hh0;_l(8q z{wNRKos+;6rV8ldy0Owz(}jF`W(JeRp&R{qi2rfmU!TJ;gp(Kmm5I1s5m_f-n#TRsj}B0%?E`vOzxB2#P=n*a3EfYETOrKoe*ICqM@{4K9Go;5xVgZi5G4 z1dM~{UdP6d+Yd3o?MrAqM0Kc|iV92owdyL5UC#5<>aVCa44|hpM4E zs0sQWIt5*Tu0n&*J!lk~f_{hI!w5`*sjxDv4V%CW*ah~3!{C*0BD@;TgA3v9a1~q+ zAA{TB3-ERLHar49hi4Ih5D^-ph8Q6X#0?2VqLBoIkE}zAkxHZUgRb+f=nat zP#6>iMMoK->`~sRLq)(kHo*Vn{;LcG6+edD1=7D>9j^O?D{Qg|tCDK{ym)H7&wDr6*;uGTJg8GHjVbnL{!cWyUB7MT6o-VNo_w8Yq`2<5Ub)hw4L3rj}5@qxMs0 zWMyP6Wy582WNT#4$d1qunl{acmP#w5ouJ*Jy_Zv#bCKi7ZIf$}8d zZdVy&)LYdbX%I9R8VMQ|8r>Q*nyQ)sn)#Z|n)kKvS`4iu ztvy=3T65Yu+7a4Yv^%sXb>ww?bn(=Yu(!=O6^iuTp>)p_Y^{w=i z^lS773}6Fm1Fpe-gF!>Ip{*g$u-szvGhed;vo5pW&GpS$<~8QGEXWp~7V9lKEnZq0SaK{6Sl+dwSOr*Z zvFf(^Xl-N7w{EeXveC4Ov)N}e%%C!Y7^RFWwrE>d+x51mZQt2h+X?JW*!^a2WS?Sx z)P8cQ&Qi|OhNWW;>JChYI)@QQx?`Nj^#uJBl~d&PK+RZLOLos~K(b5>qmrMN0})tOkySZ3_W zICNY@+|jrX%s^&6b2i>5eqa0y%Z;^%^_=a@u3%4b9605ii3Ep)@`TAmhs0fpQ%O!q zl}XcFH*PieWwLj2ZSq`7V9Mc?h17`D)-+sNT-qs~3@?S(ldh7UlRlVXkWrK|vf6I- z?$tAVKYn8-l({mqQ$Q8{O!WzMg`0(=S&msXS#Pt$vrpzo=kRj+a`kh!z=6$;c zwT88(J6|n-WB%w`m$h~4pmp)YIh_ z3ETV2tjiAU!0h1dxU-n=E9e!)6|Z;4?!H=SSy{V>ut&IOq{_dl zbFb#!9eY1iCsp6Bajj|Hr?hX|zPbJE{X++w546-O*Ot`2Kgd0Jx6Z4syT zu9enWavU5N9)I?I-1m1*_?_rJ$vD~agVqoG+9++s?NEDe`%Fht$4F;X=in*dQ{7$m zU2Q)a|9JSc+Uc4zvS-T963!N$T{xF_ZuWe}`RNOZ7sk3{yB}PPym+f8xTpV;-=!;; zJuhGEb?H5K#o@~7t9DmUU1MD9xNd#Dz0azz?I)|B+WM{g+Xrk0I&awC=o(x)cy`EX z=)z6+o0o6-+`4{y+3mqQ%kSJBju{@g%f35#FZJHb`&swrA8dGtepviS>QUumrN{L@ z>;2q1Vm)$Z)P1z?N$8UYW2~{~zhwUMVZ87u`Dx{Z>O|9|`Q+&->FRy-Sjp7DHs zy69KwU-!MxeeuI@&cF4|M9z%AfP?@5 z`Tzg`fam}Kbua(`>RI+y?e7jT@qQ9J+u0o6%FK~y-)rIXKV6G0TmKVy}C^K zLO=?!Uc96!2nD@Mi{RCZIVcTnK`$QbA0Qrt3Wcf{5qoHh;I$`H5WG}DB#pVKpedBv zvTSJ<%Qj(o9?Jeo0v>#)nK$qAeKX&gQ6j>Bg@`apWO2$I%1zJD%JlrK#JTh+(N1%X zz8KtBf5P0{N<#oFEtRM}7oY5Ze@CaehNhP=3McGa$zQJc=S(IyVYUbhcGA!n*W&Q$BaDge~R+q`~sby(nA z#|^t%S_-G=d@VM&&XSWk<8(?wiW8}dgeAC(<=o+1QbK;bTPd_Dh;PiYP+vmF3RzdN> zksE`f@rQadA*_O*s8nS3rCS#O`1y8!