From b11fabdecb79dac4d096412e731c02c1ab06170d Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 23 Dec 2021 18:52:40 +0200 Subject: [PATCH] Unicorns can now equip spells to their active and passive ability slots --- .../ability/ChangelingDisguiseAbility.java | 2 +- .../ability/UnicornCastingAbility.java | 17 ++----- .../ability/UnicornProjectileAbility.java | 27 ++--------- .../ability/magic/spell/ThrowableSpell.java | 2 +- .../crafting/TraitRequirementRecipe.java | 2 +- .../magic/spell/effect/CatapultSpell.java | 2 +- .../spell/effect/CustomisedSpellType.java | 36 +++++++++++--- .../ability/magic/spell/effect/SpellType.java | 28 ++++++++--- .../magic/spell/trait/SpellTraits.java | 10 ++++ .../unicopia/client/gui/UHud.java | 42 +++++++++++++---- .../unicopia/command/DisguiseCommand.java | 2 +- .../unicopia/entity/UTradeOffers.java | 2 +- .../entity/player/PlayerCharmTracker.java | 47 +++++++++++++++++++ .../unicopia/entity/player/Pony.java | 3 ++ .../unicopia/item/GemstoneItem.java | 46 +++++++++++++----- .../unicopia/util/NbtSerialisable.java | 8 +--- 16 files changed, 193 insertions(+), 83 deletions(-) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java index 0b443adc..90cabd7b 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java @@ -61,7 +61,7 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility { player.getEntityWorld().playSound(null, player.getBlockPos(), SoundEvents.ENTITY_PARROT_IMITATE_RAVAGER, SoundCategory.PLAYERS, 1.4F, 0.4F); iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, true) - .orElseGet(() -> SpellType.CHANGELING_DISGUISE.apply(iplayer, SpellTraits.EMPTY)) + .orElseGet(() -> SpellType.CHANGELING_DISGUISE.withTraits().apply(iplayer)) .setDisguise(looked); if (!player.isCreative()) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java index 1cc2e4e4..e6a0657d 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java @@ -4,14 +4,11 @@ import java.util.Random; import org.jetbrains.annotations.Nullable; -import com.google.common.collect.Streams; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; -import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.AmuletItem; -import com.minelittlepony.unicopia.item.GemstoneItem; import com.minelittlepony.unicopia.particle.MagicParticleEffect; import net.minecraft.item.ItemStack; @@ -58,7 +55,7 @@ public class UnicornCastingAbility implements Ability { return Hit.of(manaLevel > 0 && ((AmuletItem)amulet.getValue().getItem()).canCharge(amulet.getValue())); } - ActionResult spell = getNewSpell(player).getResult(); + ActionResult spell = player.getCharms().getSpellInHand(Hand.MAIN_HAND).getResult(); if (spell != ActionResult.PASS) { return Hit.of(spell != ActionResult.FAIL && manaLevel > 4F); @@ -82,7 +79,7 @@ public class UnicornCastingAbility implements Ability { return Math.min(manaLevel, ((AmuletItem)amulet.getValue().getItem()).getChargeRemainder(amulet.getValue())); } - if (getNewSpell(player).getResult() == ActionResult.CONSUME) { + if (player.getCharms().getSpellInHand(Hand.MAIN_HAND).getResult() == ActionResult.CONSUME) { return 4F; } @@ -111,7 +108,7 @@ public class UnicornCastingAbility implements Ability { } } } else { - TypedActionResult> newSpell = getNewSpell(player); + TypedActionResult> newSpell = player.getCharms().getSpellInHand(Hand.MAIN_HAND); if (newSpell.getResult() != ActionResult.FAIL) { CustomisedSpellType spell = newSpell.getValue(); @@ -140,14 +137,6 @@ public class UnicornCastingAbility implements Ability { return TypedActionResult.pass(stack); } - private TypedActionResult> getNewSpell(Pony player) { - return Streams.stream(player.getMaster().getItemsHand()) - .filter(GemstoneItem::isEnchanted) - .map(stack -> GemstoneItem.consumeSpell(stack, player.getMaster(), null, null)) - .findFirst() - .orElse(TypedActionResult.>pass(SpellType.SHIELD.withTraits())); - } - @Override public void preApply(Pony player, AbilitySlot slot) { player.getMagicalReserves().getExhaustion().multiply(3.3F); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornProjectileAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornProjectileAbility.java index c040a0f4..ecb4a486 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornProjectileAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornProjectileAbility.java @@ -1,17 +1,13 @@ package com.minelittlepony.unicopia.ability; -import org.jetbrains.annotations.Nullable; - -import com.google.common.collect.Streams; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; -import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.player.Pony; -import com.minelittlepony.unicopia.item.GemstoneItem; import com.minelittlepony.unicopia.particle.MagicParticleEffect; import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; import net.minecraft.util.Identifier; import net.minecraft.util.TypedActionResult; @@ -46,7 +42,7 @@ public class UnicornProjectileAbility implements Ability { @Override public Hit tryActivate(Pony player) { - return Hit.of(getNewSpell(player).getResult() != ActionResult.FAIL); + return Hit.of(player.getCharms().getSpellInHand(Hand.OFF_HAND).getResult() != ActionResult.FAIL); } @Override @@ -61,29 +57,14 @@ public class UnicornProjectileAbility implements Ability { @Override public void apply(Pony player, Hit data) { - TypedActionResult> thrown = getNewSpell(player); + TypedActionResult> thrown = player.getCharms().getSpellInHand(Hand.OFF_HAND); if (thrown.getResult() != ActionResult.FAIL) { - @Nullable - CustomisedSpellType spell = thrown.getValue(); - - if (spell == null) { - spell = SpellType.VORTEX.withTraits(); - } - player.subtractEnergyCost(getCostEstimate(player)); - spell.create().toThrowable().throwProjectile(player); + thrown.getValue().create().toThrowable().throwProjectile(player); } } - private TypedActionResult> getNewSpell(Pony player) { - return Streams.stream(player.getMaster().getItemsHand()) - .filter(GemstoneItem::isEnchanted) - .map(stack -> GemstoneItem.consumeSpell(stack, player.getMaster(), null, null)) - .findFirst() - .orElse(TypedActionResult.>pass(null)); - } - @Override public void preApply(Pony player, AbilitySlot slot) { player.getMagicalReserves().getExhaustion().multiply(3.3F); 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 3d682ae6..c4bf6684 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 @@ -49,7 +49,7 @@ public final class ThrowableSpell extends AbstractDelegatingSpell { if (!caster.isClient()) { MagicProjectileEntity projectile = new MagicProjectileEntity(world, entity); - projectile.setItem(GemstoneItem.enchanted(UItems.GEMSTONE.getDefaultStack(), spell.getType())); + projectile.setItem(GemstoneItem.enchant(UItems.GEMSTONE.getDefaultStack(), spell.getType())); projectile.getSpellSlot().put(this); projectile.setVelocity(entity, entity.getPitch(), entity.getYaw(), 0, 1.5F, 1); projectile.setHydrophobic(); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/TraitRequirementRecipe.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/TraitRequirementRecipe.java index cd0e6ef5..452d0971 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/TraitRequirementRecipe.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/crafting/TraitRequirementRecipe.java @@ -74,7 +74,7 @@ public class TraitRequirementRecipe implements SpellbookRecipe { SpellType spell = SpellType.getKey(Identifier.tryParse(JsonHelper.getString(json, "spell", ""))); if (spell != SpellType.EMPTY_KEY) { - return GemstoneItem.enchanted(stack, spell); + return GemstoneItem.enchant(stack, spell); } return stack; } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java index afbd5679..e0278629 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CatapultSpell.java @@ -71,7 +71,7 @@ public class CatapultSpell extends AbstractSpell implements ProjectileSpell { } else { e.addVelocity( ((caster.getWorld().random.nextFloat() * HORIZONTAL_VARIANCE) - HORIZONTAL_VARIANCE + vel.x * 0.8F) * 0.1F, - 0.1F + (getTraits().get(Trait.STRENGTH, -MAX_STRENGTH, MAX_STRENGTH) - 50) / 16D, + 0.1F + (getTraits().get(Trait.STRENGTH, -MAX_STRENGTH, MAX_STRENGTH) - 40) / 16D, ((caster.getWorld().random.nextFloat() * HORIZONTAL_VARIANCE) - HORIZONTAL_VARIANCE + vel.z * 0.8F) * 0.1F ); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java index 5bb1837b..f0d1cb56 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/CustomisedSpellType.java @@ -7,14 +7,14 @@ import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; -public class CustomisedSpellType implements SpellPredicate { - private final SpellType type; - private final SpellTraits traits; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.TypedActionResult; - public CustomisedSpellType(SpellType type, SpellTraits traits) { - this.type = type; - this.traits = traits; - } +public record CustomisedSpellType ( + SpellType type, + SpellTraits traits + ) implements SpellPredicate { public boolean isEmpty() { return type.isEmpty(); @@ -33,4 +33,26 @@ public class CustomisedSpellType implements SpellPredicate { public boolean test(Spell spell) { return type.test(spell); } + + public ItemStack getDefaultStack() { + return type.getDefualtStack(); + } + + public TypedActionResult> toAction() { + return isEmpty() ? TypedActionResult.fail(this) : TypedActionResult.pass(this); + } + + public NbtCompound toNBT() { + NbtCompound tag = new NbtCompound(); + type.writeId(tag); + tag.put("traits", traits.toNbt()); + return tag; + } + + public static CustomisedSpellType fromNBT(NbtCompound compound) { + SpellType type = SpellType.getKey(compound); + SpellTraits traits = SpellTraits.fromNbt(compound.getCompound("traits")).orElse(type.getTraits()); + + return type.withTraits(traits); + } } 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 2b8c3bc2..4cd1eb50 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 @@ -20,8 +20,11 @@ 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.Registries; +import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.text.Text; import net.minecraft.text.TranslatableText; @@ -75,6 +78,8 @@ public final class SpellType implements Affine, SpellPredicate< private final CustomisedSpellType traited; private final SpellTraits traits; + private final ItemStack defaultStack; + private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, SpellTraits traits, Factory factory) { this.id = id; this.affinity = affinity; @@ -83,6 +88,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); } public boolean isObtainable() { @@ -93,6 +99,10 @@ public final class SpellType implements Affine, SpellPredicate< return id; } + public ItemStack getDefualtStack() { + return defaultStack; + } + /** * Gets the tint for this spell when applied to a gem. */ @@ -182,9 +192,13 @@ public final class SpellType implements Affine, SpellPredicate< return (SpellType)EMPTY_KEY; } + public static SpellType getKey(NbtCompound tag) { + return getKey(Identifier.tryParse(tag.getString("effect_id"))); + } + @SuppressWarnings("unchecked") - public static SpellType getKey(Identifier id) { - return (SpellType)(EMPTY_ID.equals(id) ? EMPTY_KEY : REGISTRY.getOrEmpty(id).orElse(EMPTY_KEY)); + public static SpellType getKey(@Nullable Identifier id) { + return (SpellType)(id == null || EMPTY_ID.equals(id) ? EMPTY_KEY : REGISTRY.getOrEmpty(id).orElse(EMPTY_KEY)); } public static SpellType random(Random random) { @@ -198,7 +212,7 @@ public final class SpellType implements Affine, SpellPredicate< @Nullable public static Spell fromNBT(@Nullable NbtCompound compound) { if (compound != null && compound.contains("effect_id")) { - Spell effect = getKey(new Identifier(compound.getString("effect_id"))).create(SpellTraits.EMPTY); + Spell effect = getKey(compound).create(SpellTraits.EMPTY); if (effect != null) { effect.fromNBT(compound); @@ -212,12 +226,14 @@ public final class SpellType implements Affine, SpellPredicate< public static NbtCompound toNBT(Spell effect) { NbtCompound compound = effect.toNBT(); - - compound.putString("effect_id", effect.getType().getId().toString()); - + effect.getType().writeId(compound); return compound; } + public void writeId(NbtCompound tag) { + tag.putString("effect_id", getId().toString()); + } + public interface Factory { T create(SpellType type, SpellTraits traits); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java index 57097387..b72a17ae 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/trait/SpellTraits.java @@ -127,6 +127,16 @@ public final class SpellTraits implements Iterable> { }); } + @Override + public int hashCode() { + return traits.hashCode(); + } + + @Override + public boolean equals(Object other) { + return this == other || other instanceof SpellTraits && Objects.equals(traits, ((SpellTraits) other).traits); + } + public static SpellTraits union(SpellTraits...many) { Map traits = new HashMap<>(); for (SpellTraits i : many) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java index 2de55c3a..5477244c 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java @@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilitySlot; import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; +import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.client.KeyBindingsHandler; import com.minelittlepony.unicopia.client.sound.LoopingSoundInstance; @@ -29,6 +30,7 @@ import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.Arm; +import net.minecraft.util.Hand; import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Quaternion; @@ -42,6 +44,8 @@ public class UHud extends DrawableHelper { public static final int PRIMARY_SLOT_SIZE = 49; + private static final float EQUIPPED_GEMSTONE_SCALE = 0.7F; + public TextRenderer font; final MinecraftClient client = MinecraftClient.getInstance(); @@ -82,15 +86,23 @@ public class UHud extends DrawableHelper { xDirection = client.player.getMainArm() == Arm.LEFT ? -1 : 1; matrices.push(); - matrices.translate(((scaledWidth - 50) / 2) + (104 * xDirection), scaledHeight - 50, 0); + + int hudX = ((scaledWidth - 50) / 2) + (104 * xDirection); + int hudY = scaledHeight - 50; + int hudZ = 0; + float exhaustion = pony.getMagicalReserves().getExhaustion().getPercentFill(); if (exhaustion > 0.5F) { Random rng = client.world.random; - matrices.translate(rng.nextFloat() - 0.5F, rng.nextFloat() - 0.5F, rng.nextFloat() - 0.5F); + hudX += rng.nextFloat() - 0.5F; + hudY += rng.nextFloat() - 0.5F; + hudZ += rng.nextFloat() - 0.5F; } + matrices.translate(hudX, hudY, hudZ); + AbilityDispatcher abilities = pony.getAbilities(); if (message != null && messageTime > 0) { @@ -106,10 +118,15 @@ public class UHud extends DrawableHelper { slots.forEach(slot -> slot.renderBackground(matrices, abilities, swap, tickDelta)); slots.forEach(slot -> slot.renderLabel(matrices, abilities, tickDelta)); - RenderSystem.disableBlend(); - matrices.pop(); + if (pony.getSpecies().canCast()) { + renderSpell(pony.getCharms().getEquippedSpell(Hand.MAIN_HAND), hudX + 15 - xDirection * 8, hudY + 2); + renderSpell(pony.getCharms().getEquippedSpell(Hand.OFF_HAND), hudX + 15 - xDirection * 0, hudY - 3); + } + + RenderSystem.disableBlend(); + if (pony.getSpecies() == Race.CHANGELING && !client.player.isSneaking()) { pony.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, false).map(AbstractDisguiseSpell::getDisguise) .map(EntityAppearance::getAppearance) @@ -137,15 +154,25 @@ public class UHud extends DrawableHelper { } } - private void renderMessage(MatrixStack matrices, float tickDelta) { + private void renderSpell(CustomisedSpellType spell, int x, int y) { + if (!spell.isEmpty()) { + MatrixStack modelStack = RenderSystem.getModelViewStack(); + modelStack.push(); + modelStack.translate(x, y, 0); + modelStack.scale(EQUIPPED_GEMSTONE_SCALE, EQUIPPED_GEMSTONE_SCALE, EQUIPPED_GEMSTONE_SCALE); + RenderSystem.applyModelViewMatrix(); + client.getItemRenderer().renderGuiItemIcon(spell.getDefaultStack(), 0, 0); + modelStack.pop(); + RenderSystem.applyModelViewMatrix(); + } + } + private void renderMessage(MatrixStack matrices, float tickDelta) { float time = messageTime - tickDelta; int progress = Math.min(255, (int)(time * 255F / 20F)); if (progress > 8) { - int color = 0xFFFFFF; - int alpha = progress << 24 & -16777216; color |= alpha; @@ -239,5 +266,4 @@ public class UHud extends DrawableHelper { RenderSystem.setShaderTexture(0, HUD_TEXTURE); }); } - } diff --git a/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java b/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java index 135daf28..e47b8189 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java @@ -84,7 +84,7 @@ public class DisguiseCommand { Pony iplayer = Pony.of(player); iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, true) - .orElseGet(() -> SpellType.CHANGELING_DISGUISE.apply(iplayer, SpellTraits.EMPTY)) + .orElseGet(() -> SpellType.CHANGELING_DISGUISE.withTraits().apply(iplayer)) .setDisguise(entity); if (source.getEntity() == player) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/UTradeOffers.java b/src/main/java/com/minelittlepony/unicopia/entity/UTradeOffers.java index fd614461..3e0d3428 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/UTradeOffers.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/UTradeOffers.java @@ -36,7 +36,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.enchanted(UItems.GEMSTONE.getDefaultStack(), SpellType.random(rng)), 20, 1, 0.05F)); + factories.add((e, rng) -> new TradeOffer(new ItemStack(UItems.GEMSTONE, 3), GemstoneItem.enchant(UItems.GEMSTONE.getDefaultStack(), SpellType.random(rng)), 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 71551b6a..c5e206b2 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java @@ -7,14 +7,23 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Stream; +import com.google.common.collect.Streams; import com.minelittlepony.unicopia.ability.magic.Affine; +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.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; import net.minecraft.item.ItemConvertible; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtList; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.Hand; import net.minecraft.util.Identifier; +import net.minecraft.util.TypedActionResult; import net.minecraft.util.registry.Registry; public class PlayerCharmTracker implements Tickable, NbtSerialisable { @@ -23,6 +32,11 @@ public class PlayerCharmTracker implements Tickable, NbtSerialisable { private final ItemTracker armour = new ItemTracker(); + private CustomisedSpellType[] handSpells = new CustomisedSpellType[] { + SpellType.SHIELD.withTraits(), + SpellType.CATAPULT.withTraits() + }; + PlayerCharmTracker(Pony pony) { this.pony = pony; } @@ -36,14 +50,47 @@ public class PlayerCharmTracker implements Tickable, NbtSerialisable { return armour; } + public CustomisedSpellType[] getHandSpells() { + return handSpells; + } + + public CustomisedSpellType getEquippedSpell(Hand hand) { + return handSpells[hand.ordinal()]; + } + + public TypedActionResult> getSpellInHand(Hand hand) { + return Streams.stream(pony.getMaster().getItemsHand()) + .filter(GemstoneItem::isEnchanted) + .map(stack -> GemstoneItem.consumeSpell(stack, pony.getMaster(), null)) + .findFirst() + .orElse(getEquippedSpell(hand).toAction()); + } + + public void equipSpell(Hand hand, CustomisedSpellType spell) { + handSpells[hand.ordinal()] = spell; + pony.getMaster().playSound(SoundEvents.UI_BUTTON_CLICK, 0.25F, 1.75F); + pony.setDirty(); + } + @Override public void toNBT(NbtCompound compound) { compound.put("armour", armour.toNBT()); + NbtList equippedSpells = new NbtList(); + for (CustomisedSpellType spell : handSpells) { + equippedSpells.add(spell.toNBT()); + } + compound.put("handSpells", equippedSpells); } @Override public void fromNBT(NbtCompound compound) { armour.fromNBT(compound.getCompound("armour")); + if (compound.contains("handSpells", NbtElement.LIST_TYPE)) { + NbtList list = compound.getList("handSpells", NbtElement.COMPOUND_TYPE); + for (int i = 0; i < handSpells.length && i < list.size(); i++) { + handSpells[i] = CustomisedSpellType.fromNBT(list.getCompound(i)); + } + } } public class ItemTracker implements NbtSerialisable { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 7d894534..637c6111 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -59,6 +59,7 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; import net.minecraft.text.TranslatableText; +import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -511,6 +512,8 @@ public class Pony extends Living implements Transmittable, Copieab oldPlayer.getSpellSlot().put(null); setSpecies(oldPlayer.getSpecies()); getDiscoveries().copyFrom(oldPlayer.getDiscoveries()); + getCharms().equipSpell(Hand.MAIN_HAND, oldPlayer.getCharms().getEquippedSpell(Hand.MAIN_HAND)); + getCharms().equipSpell(Hand.OFF_HAND, oldPlayer.getCharms().getEquippedSpell(Hand.OFF_HAND)); setDirty(); } diff --git a/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java b/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java index 34298cb4..2cd7ac98 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/GemstoneItem.java @@ -1,7 +1,6 @@ package com.minelittlepony.unicopia.item; import java.util.List; -import java.util.Objects; import java.util.function.Predicate; import org.jetbrains.annotations.Nullable; @@ -12,6 +11,8 @@ 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.entity.player.PlayerCharmTracker; +import com.minelittlepony.unicopia.entity.player.Pony; import net.minecraft.client.item.TooltipContext; import net.minecraft.entity.player.PlayerEntity; @@ -34,6 +35,24 @@ public class GemstoneItem extends Item { super(settings); } + @Override + public TypedActionResult use(World world, PlayerEntity user, Hand hand) { + TypedActionResult result = super.use(world, user, hand); + + if (!result.getResult().isAccepted()) { + ItemStack stack = user.getStackInHand(hand); + PlayerCharmTracker charms = Pony.of(user).getCharms(); + + TypedActionResult> spell = consumeSpell(stack, user, ((Predicate>)charms.getEquippedSpell(hand)::equals).negate()); + if (spell.getResult().isAccepted()) { + charms.equipSpell(hand, spell.getValue()); + return TypedActionResult.success(stack, true); + } + } + + return result; + } + @Override public void appendTooltip(ItemStack stack, @Nullable World world, List lines, TooltipContext tooltipContext) { super.appendTooltip(stack, world, lines, tooltipContext); @@ -58,7 +77,7 @@ public class GemstoneItem extends Item { for (Affinity i : Affinity.VALUES) { SpellType.byAffinity(i).forEach(type -> { if (type.isObtainable()) { - items.add(enchanted(getDefaultStack(), type, i)); + items.add(enchant(getDefaultStack(), type, i)); } }); } @@ -82,20 +101,21 @@ public class GemstoneItem extends Item { return super.getName(); } - public static TypedActionResult> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable SpellType exclude, @Nullable Predicate> test) { + public static TypedActionResult> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable Predicate> filter) { if (!isEnchanted(stack)) { return TypedActionResult.pass(null); } SpellType key = getSpellKey(stack); - SpellTraits traits = SpellTraits.of(stack); - if (Objects.equals(key, exclude)) { + if (key.isEmpty()) { return TypedActionResult.fail(null); } - if (key.isEmpty() || (test != null && !test.test(key))) { + CustomisedSpellType result = key.withTraits(SpellTraits.of(stack)); + + if (filter != null && !filter.test(result)) { return TypedActionResult.fail(null); } @@ -103,29 +123,29 @@ public class GemstoneItem extends Item { player.swingHand(player.getStackInHand(Hand.OFF_HAND) == stack ? Hand.OFF_HAND : Hand.MAIN_HAND); if (stack.getCount() == 1) { - unenchanted(stack); + unenchant(stack); } else { - player.giveItemStack(unenchanted(stack.split(1))); + player.giveItemStack(unenchant(stack.split(1))); } } - return TypedActionResult.consume(key.withTraits(traits)); + return TypedActionResult.consume(result); } public static boolean isEnchanted(ItemStack stack) { return !stack.isEmpty() && stack.hasNbt() && stack.getNbt().contains("spell"); } - public static ItemStack enchanted(ItemStack stack, SpellType type) { - return enchanted(stack, type, type.getAffinity()); + public static ItemStack enchant(ItemStack stack, SpellType type) { + return enchant(stack, type, type.getAffinity()); } - public static ItemStack enchanted(ItemStack stack, SpellType type, Affinity affinity) { + public static ItemStack enchant(ItemStack stack, SpellType type, Affinity affinity) { stack.getOrCreateNbt().putString("spell", type.getId().toString()); return type.getTraits().applyTo(stack); } - public static ItemStack unenchanted(ItemStack stack) { + public static ItemStack unenchant(ItemStack stack) { stack.removeSubNbt("spell"); return stack; } diff --git a/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java b/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java index 9d49141b..69f5f6ec 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java +++ b/src/main/java/com/minelittlepony/unicopia/util/NbtSerialisable.java @@ -15,18 +15,14 @@ public interface NbtSerialisable { * * @param compound Compound tag to write to. */ - default void toNBT(NbtCompound compound) { - - } + void toNBT(NbtCompound compound); /** * Called to load this state from nbt * * @param compound Compound tag to read from. */ - default void fromNBT(NbtCompound compound) { - - } + void fromNBT(NbtCompound compound); default NbtCompound toNBT() { NbtCompound compound = new NbtCompound();