Unicorns can now equip spells to their active and passive ability slots

This commit is contained in:
Sollace 2021-12-23 18:52:40 +02:00
parent f10dcb59ec
commit b11fabdecb
16 changed files with 193 additions and 83 deletions

View file

@ -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); player.getEntityWorld().playSound(null, player.getBlockPos(), SoundEvents.ENTITY_PARROT_IMITATE_RAVAGER, SoundCategory.PLAYERS, 1.4F, 0.4F);
iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, true) iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, true)
.orElseGet(() -> SpellType.CHANGELING_DISGUISE.apply(iplayer, SpellTraits.EMPTY)) .orElseGet(() -> SpellType.CHANGELING_DISGUISE.withTraits().apply(iplayer))
.setDisguise(looked); .setDisguise(looked);
if (!player.isCreative()) { if (!player.isCreative()) {

View file

@ -4,14 +4,11 @@ import java.util.Random;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.google.common.collect.Streams;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; 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.entity.player.Pony;
import com.minelittlepony.unicopia.item.AmuletItem; import com.minelittlepony.unicopia.item.AmuletItem;
import com.minelittlepony.unicopia.item.GemstoneItem;
import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -58,7 +55,7 @@ public class UnicornCastingAbility implements Ability<Hit> {
return Hit.of(manaLevel > 0 && ((AmuletItem)amulet.getValue().getItem()).canCharge(amulet.getValue())); 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) { if (spell != ActionResult.PASS) {
return Hit.of(spell != ActionResult.FAIL && manaLevel > 4F); return Hit.of(spell != ActionResult.FAIL && manaLevel > 4F);
@ -82,7 +79,7 @@ public class UnicornCastingAbility implements Ability<Hit> {
return Math.min(manaLevel, ((AmuletItem)amulet.getValue().getItem()).getChargeRemainder(amulet.getValue())); 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; return 4F;
} }
@ -111,7 +108,7 @@ public class UnicornCastingAbility implements Ability<Hit> {
} }
} }
} else { } else {
TypedActionResult<CustomisedSpellType<?>> newSpell = getNewSpell(player); TypedActionResult<CustomisedSpellType<?>> newSpell = player.getCharms().getSpellInHand(Hand.MAIN_HAND);
if (newSpell.getResult() != ActionResult.FAIL) { if (newSpell.getResult() != ActionResult.FAIL) {
CustomisedSpellType<?> spell = newSpell.getValue(); CustomisedSpellType<?> spell = newSpell.getValue();
@ -140,14 +137,6 @@ public class UnicornCastingAbility implements Ability<Hit> {
return TypedActionResult.pass(stack); return TypedActionResult.pass(stack);
} }
private TypedActionResult<CustomisedSpellType<?>> getNewSpell(Pony player) {
return Streams.stream(player.getMaster().getItemsHand())
.filter(GemstoneItem::isEnchanted)
.map(stack -> GemstoneItem.consumeSpell(stack, player.getMaster(), null, null))
.findFirst()
.orElse(TypedActionResult.<CustomisedSpellType<?>>pass(SpellType.SHIELD.withTraits()));
}
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void preApply(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExhaustion().multiply(3.3F); player.getMagicalReserves().getExhaustion().multiply(3.3F);

View file

@ -1,17 +1,13 @@
package com.minelittlepony.unicopia.ability; 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.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; 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.entity.player.Pony;
import com.minelittlepony.unicopia.item.GemstoneItem;
import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
@ -46,7 +42,7 @@ public class UnicornProjectileAbility implements Ability<Hit> {
@Override @Override
public Hit tryActivate(Pony player) { 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 @Override
@ -61,29 +57,14 @@ public class UnicornProjectileAbility implements Ability<Hit> {
@Override @Override
public void apply(Pony player, Hit data) { public void apply(Pony player, Hit data) {
TypedActionResult<CustomisedSpellType<?>> thrown = getNewSpell(player); TypedActionResult<CustomisedSpellType<?>> thrown = player.getCharms().getSpellInHand(Hand.OFF_HAND);
if (thrown.getResult() != ActionResult.FAIL) { if (thrown.getResult() != ActionResult.FAIL) {
@Nullable
CustomisedSpellType<?> spell = thrown.getValue();
if (spell == null) {
spell = SpellType.VORTEX.withTraits();
}
player.subtractEnergyCost(getCostEstimate(player)); player.subtractEnergyCost(getCostEstimate(player));
spell.create().toThrowable().throwProjectile(player); thrown.getValue().create().toThrowable().throwProjectile(player);
} }
} }
private TypedActionResult<CustomisedSpellType<?>> getNewSpell(Pony player) {
return Streams.stream(player.getMaster().getItemsHand())
.filter(GemstoneItem::isEnchanted)
.map(stack -> GemstoneItem.consumeSpell(stack, player.getMaster(), null, null))
.findFirst()
.orElse(TypedActionResult.<CustomisedSpellType<?>>pass(null));
}
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void preApply(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExhaustion().multiply(3.3F); player.getMagicalReserves().getExhaustion().multiply(3.3F);

View file

@ -49,7 +49,7 @@ public final class ThrowableSpell extends AbstractDelegatingSpell {
if (!caster.isClient()) { if (!caster.isClient()) {
MagicProjectileEntity projectile = new MagicProjectileEntity(world, entity); 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.getSpellSlot().put(this);
projectile.setVelocity(entity, entity.getPitch(), entity.getYaw(), 0, 1.5F, 1); projectile.setVelocity(entity, entity.getPitch(), entity.getYaw(), 0, 1.5F, 1);
projectile.setHydrophobic(); projectile.setHydrophobic();

View file

@ -74,7 +74,7 @@ public class TraitRequirementRecipe implements SpellbookRecipe {
SpellType<?> spell = SpellType.getKey(Identifier.tryParse(JsonHelper.getString(json, "spell", ""))); SpellType<?> spell = SpellType.getKey(Identifier.tryParse(JsonHelper.getString(json, "spell", "")));
if (spell != SpellType.EMPTY_KEY) { if (spell != SpellType.EMPTY_KEY) {
return GemstoneItem.enchanted(stack, spell); return GemstoneItem.enchant(stack, spell);
} }
return stack; return stack;
} }

View file

@ -71,7 +71,7 @@ public class CatapultSpell extends AbstractSpell implements ProjectileSpell {
} else { } else {
e.addVelocity( e.addVelocity(
((caster.getWorld().random.nextFloat() * HORIZONTAL_VARIANCE) - HORIZONTAL_VARIANCE + vel.x * 0.8F) * 0.1F, ((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 ((caster.getWorld().random.nextFloat() * HORIZONTAL_VARIANCE) - HORIZONTAL_VARIANCE + vel.z * 0.8F) * 0.1F
); );
} }

View file

@ -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.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
public class CustomisedSpellType<T extends Spell> implements SpellPredicate<T> { import net.minecraft.item.ItemStack;
private final SpellType<T> type; import net.minecraft.nbt.NbtCompound;
private final SpellTraits traits; import net.minecraft.util.TypedActionResult;
public CustomisedSpellType(SpellType<T> type, SpellTraits traits) { public record CustomisedSpellType<T extends Spell> (
this.type = type; SpellType<T> type,
this.traits = traits; SpellTraits traits
} ) implements SpellPredicate<T> {
public boolean isEmpty() { public boolean isEmpty() {
return type.isEmpty(); return type.isEmpty();
@ -33,4 +33,26 @@ public class CustomisedSpellType<T extends Spell> implements SpellPredicate<T> {
public boolean test(Spell spell) { public boolean test(Spell spell) {
return type.test(spell); return type.test(spell);
} }
public ItemStack getDefaultStack() {
return type.getDefualtStack();
}
public TypedActionResult<CustomisedSpellType<?>> 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);
}
} }

View file

@ -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.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell; import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; 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 com.minelittlepony.unicopia.util.Registries;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
@ -75,6 +78,8 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
private final CustomisedSpellType<T> traited; private final CustomisedSpellType<T> traited;
private final SpellTraits traits; private final SpellTraits traits;
private final ItemStack defaultStack;
private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, SpellTraits traits, Factory<T> factory) { private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, SpellTraits traits, Factory<T> factory) {
this.id = id; this.id = id;
this.affinity = affinity; this.affinity = affinity;
@ -83,6 +88,7 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
this.factory = factory; this.factory = factory;
this.traits = traits; this.traits = traits;
traited = new CustomisedSpellType<>(this, traits); traited = new CustomisedSpellType<>(this, traits);
defaultStack = GemstoneItem.enchant(UItems.GEMSTONE.getDefaultStack(), this);
} }
public boolean isObtainable() { public boolean isObtainable() {
@ -93,6 +99,10 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
return id; return id;
} }
public ItemStack getDefualtStack() {
return defaultStack;
}
/** /**
* Gets the tint for this spell when applied to a gem. * Gets the tint for this spell when applied to a gem.
*/ */
@ -182,9 +192,13 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
return (SpellType<T>)EMPTY_KEY; return (SpellType<T>)EMPTY_KEY;
} }
public static <T extends Spell> SpellType<T> getKey(NbtCompound tag) {
return getKey(Identifier.tryParse(tag.getString("effect_id")));
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T extends Spell> SpellType<T> getKey(Identifier id) { public static <T extends Spell> SpellType<T> getKey(@Nullable Identifier id) {
return (SpellType<T>)(EMPTY_ID.equals(id) ? EMPTY_KEY : REGISTRY.getOrEmpty(id).orElse(EMPTY_KEY)); return (SpellType<T>)(id == null || EMPTY_ID.equals(id) ? EMPTY_KEY : REGISTRY.getOrEmpty(id).orElse(EMPTY_KEY));
} }
public static SpellType<?> random(Random random) { public static SpellType<?> random(Random random) {
@ -198,7 +212,7 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
@Nullable @Nullable
public static Spell fromNBT(@Nullable NbtCompound compound) { public static Spell fromNBT(@Nullable NbtCompound compound) {
if (compound != null && compound.contains("effect_id")) { 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) { if (effect != null) {
effect.fromNBT(compound); effect.fromNBT(compound);
@ -212,12 +226,14 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
public static NbtCompound toNBT(Spell effect) { public static NbtCompound toNBT(Spell effect) {
NbtCompound compound = effect.toNBT(); NbtCompound compound = effect.toNBT();
effect.getType().writeId(compound);
compound.putString("effect_id", effect.getType().getId().toString());
return compound; return compound;
} }
public void writeId(NbtCompound tag) {
tag.putString("effect_id", getId().toString());
}
public interface Factory<T extends Spell> { public interface Factory<T extends Spell> {
T create(SpellType<T> type, SpellTraits traits); T create(SpellType<T> type, SpellTraits traits);
} }

View file

@ -127,6 +127,16 @@ public final class SpellTraits implements Iterable<Map.Entry<Trait, Float>> {
}); });
} }
@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) { public static SpellTraits union(SpellTraits...many) {
Map<Trait, Float> traits = new HashMap<>(); Map<Trait, Float> traits = new HashMap<>();
for (SpellTraits i : many) { for (SpellTraits i : many) {

View file

@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilityDispatcher;
import com.minelittlepony.unicopia.ability.AbilitySlot; import com.minelittlepony.unicopia.ability.AbilitySlot;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; 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.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.client.KeyBindingsHandler; import com.minelittlepony.unicopia.client.KeyBindingsHandler;
import com.minelittlepony.unicopia.client.sound.LoopingSoundInstance; 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.entity.player.PlayerEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Arm; import net.minecraft.util.Arm;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Quaternion; import net.minecraft.util.math.Quaternion;
@ -42,6 +44,8 @@ public class UHud extends DrawableHelper {
public static final int PRIMARY_SLOT_SIZE = 49; public static final int PRIMARY_SLOT_SIZE = 49;
private static final float EQUIPPED_GEMSTONE_SCALE = 0.7F;
public TextRenderer font; public TextRenderer font;
final MinecraftClient client = MinecraftClient.getInstance(); final MinecraftClient client = MinecraftClient.getInstance();
@ -82,15 +86,23 @@ public class UHud extends DrawableHelper {
xDirection = client.player.getMainArm() == Arm.LEFT ? -1 : 1; xDirection = client.player.getMainArm() == Arm.LEFT ? -1 : 1;
matrices.push(); 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(); float exhaustion = pony.getMagicalReserves().getExhaustion().getPercentFill();
if (exhaustion > 0.5F) { if (exhaustion > 0.5F) {
Random rng = client.world.random; 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(); AbilityDispatcher abilities = pony.getAbilities();
if (message != null && messageTime > 0) { 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.renderBackground(matrices, abilities, swap, tickDelta));
slots.forEach(slot -> slot.renderLabel(matrices, abilities, tickDelta)); slots.forEach(slot -> slot.renderLabel(matrices, abilities, tickDelta));
RenderSystem.disableBlend();
matrices.pop(); 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()) { if (pony.getSpecies() == Race.CHANGELING && !client.player.isSneaking()) {
pony.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, false).map(AbstractDisguiseSpell::getDisguise) pony.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, false).map(AbstractDisguiseSpell::getDisguise)
.map(EntityAppearance::getAppearance) .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; float time = messageTime - tickDelta;
int progress = Math.min(255, (int)(time * 255F / 20F)); int progress = Math.min(255, (int)(time * 255F / 20F));
if (progress > 8) { if (progress > 8) {
int color = 0xFFFFFF; int color = 0xFFFFFF;
int alpha = progress << 24 & -16777216; int alpha = progress << 24 & -16777216;
color |= alpha; color |= alpha;
@ -239,5 +266,4 @@ public class UHud extends DrawableHelper {
RenderSystem.setShaderTexture(0, HUD_TEXTURE); RenderSystem.setShaderTexture(0, HUD_TEXTURE);
}); });
} }
} }

View file

@ -84,7 +84,7 @@ public class DisguiseCommand {
Pony iplayer = Pony.of(player); Pony iplayer = Pony.of(player);
iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, true) iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, true)
.orElseGet(() -> SpellType.CHANGELING_DISGUISE.apply(iplayer, SpellTraits.EMPTY)) .orElseGet(() -> SpellType.CHANGELING_DISGUISE.withTraits().apply(iplayer))
.setDisguise(entity); .setDisguise(entity);
if (source.getEntity() == player) { if (source.getEntity() == player) {

View file

@ -36,7 +36,7 @@ public interface UTradeOffers {
TradeOfferHelper.registerWanderingTraderOffers(1, factories -> { TradeOfferHelper.registerWanderingTraderOffers(1, factories -> {
factories.add(buyTiered(UItems.GEMSTONE, 30, UItems.GOLDEN_FEATHER, 1, UItems.GOLDEN_WING, 1, 30, 2, 0.05F)); 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(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(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)); factories.add(buy(ItemTags.SMALL_FLOWERS, 2, UItems.DAFFODIL_DAISY_SANDWICH, 1, 10, 6, 0.08F));

View file

@ -7,14 +7,23 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.google.common.collect.Streams;
import com.minelittlepony.unicopia.ability.magic.Affine; 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.NbtSerialisable;
import com.minelittlepony.unicopia.util.Tickable; import com.minelittlepony.unicopia.util.Tickable;
import net.minecraft.item.ItemConvertible; import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound; 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.Identifier;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
public class PlayerCharmTracker implements Tickable, NbtSerialisable { public class PlayerCharmTracker implements Tickable, NbtSerialisable {
@ -23,6 +32,11 @@ public class PlayerCharmTracker implements Tickable, NbtSerialisable {
private final ItemTracker armour = new ItemTracker(); private final ItemTracker armour = new ItemTracker();
private CustomisedSpellType<?>[] handSpells = new CustomisedSpellType<?>[] {
SpellType.SHIELD.withTraits(),
SpellType.CATAPULT.withTraits()
};
PlayerCharmTracker(Pony pony) { PlayerCharmTracker(Pony pony) {
this.pony = pony; this.pony = pony;
} }
@ -36,14 +50,47 @@ public class PlayerCharmTracker implements Tickable, NbtSerialisable {
return armour; return armour;
} }
public CustomisedSpellType<?>[] getHandSpells() {
return handSpells;
}
public CustomisedSpellType<?> getEquippedSpell(Hand hand) {
return handSpells[hand.ordinal()];
}
public TypedActionResult<CustomisedSpellType<?>> 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 @Override
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
compound.put("armour", armour.toNBT()); compound.put("armour", armour.toNBT());
NbtList equippedSpells = new NbtList();
for (CustomisedSpellType<?> spell : handSpells) {
equippedSpells.add(spell.toNBT());
}
compound.put("handSpells", equippedSpells);
} }
@Override @Override
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
armour.fromNBT(compound.getCompound("armour")); 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 { public class ItemTracker implements NbtSerialisable {

View file

@ -59,6 +59,7 @@ import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
@ -511,6 +512,8 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
oldPlayer.getSpellSlot().put(null); oldPlayer.getSpellSlot().put(null);
setSpecies(oldPlayer.getSpecies()); setSpecies(oldPlayer.getSpecies());
getDiscoveries().copyFrom(oldPlayer.getDiscoveries()); 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(); setDirty();
} }

View file

@ -1,7 +1,6 @@
package com.minelittlepony.unicopia.item; package com.minelittlepony.unicopia.item;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.jetbrains.annotations.Nullable; 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.CustomisedSpellType;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; 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.client.item.TooltipContext;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@ -34,6 +35,24 @@ public class GemstoneItem extends Item {
super(settings); super(settings);
} }
@Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
TypedActionResult<ItemStack> result = super.use(world, user, hand);
if (!result.getResult().isAccepted()) {
ItemStack stack = user.getStackInHand(hand);
PlayerCharmTracker charms = Pony.of(user).getCharms();
TypedActionResult<CustomisedSpellType<?>> spell = consumeSpell(stack, user, ((Predicate<CustomisedSpellType<?>>)charms.getEquippedSpell(hand)::equals).negate());
if (spell.getResult().isAccepted()) {
charms.equipSpell(hand, spell.getValue());
return TypedActionResult.success(stack, true);
}
}
return result;
}
@Override @Override
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> lines, TooltipContext tooltipContext) { public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> lines, TooltipContext tooltipContext) {
super.appendTooltip(stack, world, lines, tooltipContext); super.appendTooltip(stack, world, lines, tooltipContext);
@ -58,7 +77,7 @@ public class GemstoneItem extends Item {
for (Affinity i : Affinity.VALUES) { for (Affinity i : Affinity.VALUES) {
SpellType.byAffinity(i).forEach(type -> { SpellType.byAffinity(i).forEach(type -> {
if (type.isObtainable()) { 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(); return super.getName();
} }
public static TypedActionResult<CustomisedSpellType<?>> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable SpellType<?> exclude, @Nullable Predicate<SpellType<?>> test) { public static TypedActionResult<CustomisedSpellType<?>> consumeSpell(ItemStack stack, PlayerEntity player, @Nullable Predicate<CustomisedSpellType<?>> filter) {
if (!isEnchanted(stack)) { if (!isEnchanted(stack)) {
return TypedActionResult.pass(null); return TypedActionResult.pass(null);
} }
SpellType<Spell> key = getSpellKey(stack); SpellType<Spell> key = getSpellKey(stack);
SpellTraits traits = SpellTraits.of(stack);
if (Objects.equals(key, exclude)) { if (key.isEmpty()) {
return TypedActionResult.fail(null); 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); 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); player.swingHand(player.getStackInHand(Hand.OFF_HAND) == stack ? Hand.OFF_HAND : Hand.MAIN_HAND);
if (stack.getCount() == 1) { if (stack.getCount() == 1) {
unenchanted(stack); unenchant(stack);
} else { } 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) { public static boolean isEnchanted(ItemStack stack) {
return !stack.isEmpty() && stack.hasNbt() && stack.getNbt().contains("spell"); return !stack.isEmpty() && stack.hasNbt() && stack.getNbt().contains("spell");
} }
public static ItemStack enchanted(ItemStack stack, SpellType<?> type) { public static ItemStack enchant(ItemStack stack, SpellType<?> type) {
return enchanted(stack, type, type.getAffinity()); 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()); stack.getOrCreateNbt().putString("spell", type.getId().toString());
return type.getTraits().applyTo(stack); return type.getTraits().applyTo(stack);
} }
public static ItemStack unenchanted(ItemStack stack) { public static ItemStack unenchant(ItemStack stack) {
stack.removeSubNbt("spell"); stack.removeSubNbt("spell");
return stack; return stack;
} }

View file

@ -15,18 +15,14 @@ public interface NbtSerialisable {
* *
* @param compound Compound tag to write to. * @param compound Compound tag to write to.
*/ */
default void toNBT(NbtCompound compound) { void toNBT(NbtCompound compound);
}
/** /**
* Called to load this state from nbt * Called to load this state from nbt
* *
* @param compound Compound tag to read from. * @param compound Compound tag to read from.
*/ */
default void fromNBT(NbtCompound compound) { void fromNBT(NbtCompound compound);
}
default NbtCompound toNBT() { default NbtCompound toNBT() {
NbtCompound compound = new NbtCompound(); NbtCompound compound = new NbtCompound();