mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Added magic staffs:
3 sticks on a diagonal = meadowbrooks_staff 3 sticks + gem (optionally with spell) on a diagnoal = magic_staff
This commit is contained in:
parent
072f18d6f9
commit
8959c67d53
31 changed files with 667 additions and 127 deletions
|
@ -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<Hit> {
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<ItemStack> {
|
|||
@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<ItemStack> {
|
|||
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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<T extends Spell> 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() {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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<CustomisedSpellType<?>> 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());
|
||||
}
|
||||
|
|
|
@ -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<PlayerEntity> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<CustomisedSpellType<?>> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable Predicate<CustomisedSpellType<?>> filter) {
|
||||
|
||||
if (!isEnchanted(stack)) {
|
||||
return TypedActionResult.pass(null);
|
||||
}
|
||||
|
||||
SpellType<Spell> 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 <T extends Spell> SpellType<T> getSpellKey(ItemStack stack) {
|
||||
return SpellType.getKey(isEnchanted(stack) ? new Identifier(stack.getNbt().getString("spell")) : SpellType.EMPTY_ID);
|
||||
}
|
||||
}
|
|
@ -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<EntityType<?>, SpellType<?>> ENTITY_TYPE_TO_SPELL = new HashMap<>();
|
||||
public static <T extends Spell> SpellType<T> register(EntityType<?> entityType, SpellType<T> 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<Text> 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<ItemStack> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<CustomisedSpellType<?>> spell = consumeSpell(stack, user, ((Predicate<CustomisedSpellType<?>>)charms.getEquippedSpell(hand)::equals).negate());
|
||||
TypedActionResult<CustomisedSpellType<?>> spell = EnchantableItem.consumeSpell(stack, user, ((Predicate<CustomisedSpellType<?>>)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<Text> 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<CustomisedSpellType<?>> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable Predicate<CustomisedSpellType<?>> filter) {
|
||||
|
||||
if (!isEnchanted(stack)) {
|
||||
return TypedActionResult.pass(null);
|
||||
}
|
||||
|
||||
SpellType<Spell> 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 <T extends Spell> SpellType<T> getSpellKey(ItemStack stack) {
|
||||
return SpellType.getKey(isEnchanted(stack) ? new Identifier(stack.getNbt().getString("spell")) : SpellType.EMPTY_ID);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Text> 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<EntityAttribute, EntityAttributeModifier> getAttributeModifiers(EquipmentSlot slot) {
|
||||
Multimap<EntityAttribute, EntityAttributeModifier> 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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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<ShapelessRecipe> ZAP_APPLE_SERIALIZER = RecipeSerializer.register("unicopia:crafting_zap_apple", new ZapAppleRecipe.Serializer());
|
||||
RecipeSerializer<GlowingRecipe> GLOWING_SERIALIZER = RecipeSerializer.register("unicopia:crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new));
|
||||
RecipeSerializer<JarInsertRecipe> JAR_INSERT_SERIALIZER = RecipeSerializer.register("unicopia:jar_insert", new SpecialRecipeSerializer<>(JarInsertRecipe::new));
|
||||
RecipeSerializer<ShapedRecipe> CRAFTING_MAGICAL_SERIALIZER = RecipeSerializer.register("unicopia:crafting_magical", new SpellShapedCraftingRecipe.Serializer());
|
||||
RecipeSerializer<SpellCraftingRecipe> TRAIT_REQUIREMENT = RecipeSerializer.register("unicopia:spellbook/crafting", new SpellCraftingRecipe.Serializer());
|
||||
RecipeSerializer<SpellEnhancingRecipe> TRAIT_COMBINING = RecipeSerializer.register("unicopia:spellbook/combining", new SpellEnhancingRecipe.Serializer());
|
||||
RecipeSerializer<SpellDuplicatingRecipe> SPELL_DUPLICATING = RecipeSerializer.register("unicopia:spellbook/duplicating", new SpellDuplicatingRecipe.Serializer());
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"parent": "unicopia:item/handheld_staff",
|
||||
"textures": {
|
||||
"layer0": "unicopia:item/magic_staff_base",
|
||||
"layer1": "unicopia:item/magic_staff_magic"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "unicopia:item/handheld_staff",
|
||||
"textures": {
|
||||
"layer0": "unicopia:item/meadowbrooks_staff"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"parent": "minecraft:recipes/root",
|
||||
"rewards": {
|
||||
"recipes": [
|
||||
"unicopia:meadowbrooks_staff"
|
||||
]
|
||||
},
|
||||
"criteria": {
|
||||
"has_ingredients": {
|
||||
"trigger": "minecraft:inventory_changed",
|
||||
"conditions": {
|
||||
"items": [
|
||||
{ "item": "minecraft:stick" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"has_the_recipe": {
|
||||
"trigger": "minecraft:recipe_unlocked",
|
||||
"conditions": {
|
||||
"recipe": "unicopia:meadowbrooks_staff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requirements": [
|
||||
[
|
||||
"has_ingredients",
|
||||
"has_the_recipe"
|
||||
]
|
||||
]
|
||||
}
|
19
src/main/resources/data/unicopia/recipes/magic_staff.json
Normal file
19
src/main/resources/data/unicopia/recipes/magic_staff.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"type": "unicopia:crafting_magical",
|
||||
"pattern": [
|
||||
" o",
|
||||
" # ",
|
||||
"# "
|
||||
],
|
||||
"key": {
|
||||
"#": {
|
||||
"item": "minecraft:stick"
|
||||
},
|
||||
"o": {
|
||||
"item": "unicopia:gemstone"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "unicopia:magic_staff"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"pattern": [
|
||||
" #",
|
||||
" # ",
|
||||
"# "
|
||||
],
|
||||
"key": {
|
||||
"#": {
|
||||
"item": "minecraft:stick"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "unicopia:meadowbrooks_staff"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"unicopia:gemstone",
|
||||
"unicopia:magic_staff"
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue