mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Standardise the spell recipe ingredients/requirements lists
This commit is contained in:
parent
3fcb05de81
commit
2ad431ab4b
20 changed files with 498 additions and 207 deletions
|
@ -114,9 +114,11 @@ public enum Trait implements CommandArgumentEnum<Trait> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Text getName() {
|
public Text getName() {
|
||||||
return Text.translatable("gui.unicopia.trait.label",
|
return Text.translatable("gui.unicopia.trait.label", getShortName()).formatted(Formatting.YELLOW);
|
||||||
Text.translatable("trait." + getId().getNamespace() + "." + getId().getPath() + ".name")
|
}
|
||||||
).formatted(Formatting.YELLOW);
|
|
||||||
|
public Text getShortName() {
|
||||||
|
return Text.translatable("trait." + getId().getNamespace() + "." + getId().getPath() + ".name");
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Text> getTooltipLines() {
|
public List<Text> getTooltipLines() {
|
||||||
|
|
|
@ -66,13 +66,19 @@ public class ParagraphWrappingVisitor implements StyledVisitor<Object> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// append the segment to the line that's being built
|
// append the segment to the line that's being built
|
||||||
if (currentLineCollectedLength > 0) {
|
if (currentLineCollectedLength > 0 && s.startsWith(" ")) {
|
||||||
currentLine.append(" ");
|
currentLine.append(" ");
|
||||||
currentLineCollectedLength += handler.getWidth(" ");
|
currentLineCollectedLength += handler.getWidth(" ");
|
||||||
}
|
}
|
||||||
currentLine.append(fragment);
|
currentLine.append(fragment);
|
||||||
currentLineCollectedLength += grabbedWidth;
|
currentLineCollectedLength += grabbedWidth;
|
||||||
|
|
||||||
|
// append the segment to the line that's being built
|
||||||
|
if (currentLineCollectedLength > 0 && s.endsWith(" ")) {
|
||||||
|
currentLine.append(" ");
|
||||||
|
currentLineCollectedLength += handler.getWidth(" ");
|
||||||
|
}
|
||||||
|
|
||||||
if (newline >= 0) {
|
if (newline >= 0) {
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package com.minelittlepony.unicopia.client.gui.spellbook;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.*;
|
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.*;
|
||||||
|
import com.minelittlepony.unicopia.client.gui.spellbook.element.DynamicContent;
|
||||||
|
|
||||||
import net.minecraft.network.PacketByteBuf;
|
import net.minecraft.network.PacketByteBuf;
|
||||||
import net.minecraft.util.*;
|
import net.minecraft.util.*;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import net.minecraft.client.render.model.json.ModelTransformationMode;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
|
||||||
class IngredientTree implements SpellbookRecipe.CraftingTreeBuilder {
|
public class IngredientTree implements SpellbookRecipe.CraftingTreeBuilder {
|
||||||
private final List<IngredientTree.Entry> entries = new ArrayList<>();
|
private final List<IngredientTree.Entry> entries = new ArrayList<>();
|
||||||
private Optional<IngredientTree.Entry> result = Optional.empty();
|
private Optional<IngredientTree.Entry> result = Optional.empty();
|
||||||
|
|
||||||
|
|
|
@ -1,162 +0,0 @@
|
||||||
package com.minelittlepony.unicopia.client.gui.spellbook;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.minelittlepony.common.client.gui.IViewRoot;
|
|
||||||
import com.minelittlepony.common.client.gui.dimension.Bounds;
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.crafting.IngredientWithSpell;
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe;
|
|
||||||
import com.minelittlepony.unicopia.client.gui.ParagraphWrappingVisitor;
|
|
||||||
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Drawable;
|
|
||||||
import com.minelittlepony.unicopia.container.SpellbookChapterLoader.Flow;
|
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.font.TextRenderer;
|
|
||||||
import net.minecraft.client.gui.DrawContext;
|
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
|
||||||
import net.minecraft.network.PacketByteBuf;
|
|
||||||
import net.minecraft.text.Style;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import net.minecraft.util.*;
|
|
||||||
|
|
||||||
interface PageElement extends Drawable {
|
|
||||||
@Override
|
|
||||||
default void draw(DrawContext context, int mouseX, int mouseY, IViewRoot container) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Bounds bounds();
|
|
||||||
|
|
||||||
default Flow flow() {
|
|
||||||
return Flow.NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
default boolean isInline() {
|
|
||||||
return flow() == Flow.NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
default boolean isFloating() {
|
|
||||||
return !isInline();
|
|
||||||
}
|
|
||||||
|
|
||||||
default void compile(int y, IViewRoot Container) {}
|
|
||||||
|
|
||||||
static PageElement read(DynamicContent.Page page, PacketByteBuf buffer) {
|
|
||||||
byte type = buffer.readByte();
|
|
||||||
return (switch (type) {
|
|
||||||
case 0 -> new Image(buffer.readIdentifier(), boundsFromBuffer(buffer), buffer.readEnumConstant(Flow.class));
|
|
||||||
case 1 -> new Recipe(page, buffer.readIdentifier(), Bounds.empty());
|
|
||||||
case 2 -> new Stack(page, IngredientWithSpell.fromPacket(buffer), boundsFromBuffer(buffer));
|
|
||||||
case 3 -> new TextBlock(page, buffer.readText());
|
|
||||||
default -> throw new IllegalArgumentException("Unexpected value: " + type);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Bounds boundsFromBuffer(PacketByteBuf buffer) {
|
|
||||||
return new Bounds(buffer.readInt(), buffer.readInt(), buffer.readInt(), buffer.readInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
record Image(
|
|
||||||
Identifier texture,
|
|
||||||
Bounds bounds,
|
|
||||||
Flow flow) implements PageElement {
|
|
||||||
@Override
|
|
||||||
public void draw(DrawContext context, int mouseX, int mouseY, IViewRoot container) {
|
|
||||||
context.drawTexture(texture, 0, 0, 0, 0, 0, bounds().width, bounds().height, bounds().width, bounds().height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TextBlock implements PageElement {
|
|
||||||
private final DynamicContent.Page page;
|
|
||||||
|
|
||||||
private final Text unwrappedText;
|
|
||||||
private final List<Line> wrappedText = new ArrayList<>();
|
|
||||||
private final Bounds bounds = Bounds.empty();
|
|
||||||
|
|
||||||
public TextBlock(DynamicContent.Page page,Text text) {
|
|
||||||
this.page = page;
|
|
||||||
unwrappedText = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile(int y, IViewRoot container) {
|
|
||||||
wrappedText.clear();
|
|
||||||
ParagraphWrappingVisitor visitor = new ParagraphWrappingVisitor(
|
|
||||||
yPosition -> page.getLineLimitAt(y + yPosition),
|
|
||||||
(line, yPosition) -> wrappedText.add(new Line(line, page.getLeftMarginAt(y + yPosition)))
|
|
||||||
);
|
|
||||||
unwrappedText.visit(visitor, Style.EMPTY);
|
|
||||||
visitor.forceAdvance();
|
|
||||||
bounds.height = MinecraftClient.getInstance().textRenderer.fontHeight * (wrappedText.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw(DrawContext context, int mouseX, int mouseY, IViewRoot container) {
|
|
||||||
TextRenderer font = MinecraftClient.getInstance().textRenderer;
|
|
||||||
boolean needsMoreXp = page.getLevel() < 0 || Pony.of(MinecraftClient.getInstance().player).getLevel().get() < page.getLevel();
|
|
||||||
MatrixStack matrices = context.getMatrices();
|
|
||||||
matrices.push();
|
|
||||||
wrappedText.forEach(line -> {
|
|
||||||
context.drawText(font, needsMoreXp ? line.text().copy().formatted(Formatting.OBFUSCATED) : line.text().copy(), line.x(), 0, 0, false);
|
|
||||||
matrices.translate(0, font.fontHeight, 0);
|
|
||||||
});
|
|
||||||
matrices.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bounds bounds() {
|
|
||||||
return bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Flow flow() {
|
|
||||||
return Flow.NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private record Line(Text text, int x) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
record Recipe (DynamicContent.Page page, Identifier id, Bounds bounds) implements PageElement {
|
|
||||||
@Override
|
|
||||||
public void compile(int y, IViewRoot container) {
|
|
||||||
if (container instanceof SpellbookScreen book) {
|
|
||||||
bounds().left = book.getX();
|
|
||||||
bounds().top = book.getY();
|
|
||||||
}
|
|
||||||
MinecraftClient.getInstance().world.getRecipeManager().get(id).ifPresent(recipe -> {
|
|
||||||
if (recipe instanceof SpellbookRecipe spellRecipe) {
|
|
||||||
|
|
||||||
boolean needsMoreXp = page.getLevel() < 0 || Pony.of(MinecraftClient.getInstance().player).getLevel().get() < page.getLevel();
|
|
||||||
|
|
||||||
IngredientTree tree = new IngredientTree(
|
|
||||||
bounds().left + page().getBounds().left,
|
|
||||||
bounds().top + page().getBounds().top + y + 10,
|
|
||||||
page().getBounds().width - 20
|
|
||||||
).obfuscateResult(needsMoreXp);
|
|
||||||
spellRecipe.buildCraftingTree(tree);
|
|
||||||
bounds.height = tree.build(container) - 10;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
record Stack (DynamicContent.Page page, IngredientWithSpell ingredient, Bounds bounds) implements PageElement {
|
|
||||||
@Override
|
|
||||||
public void compile(int y, IViewRoot container) {
|
|
||||||
int xx = 0, yy = 0;
|
|
||||||
if (container instanceof SpellbookScreen book) {
|
|
||||||
xx = book.getX();
|
|
||||||
yy = book.getY();
|
|
||||||
}
|
|
||||||
IngredientTree tree = new IngredientTree(
|
|
||||||
bounds().left + xx + page().getBounds().left,
|
|
||||||
bounds().top + yy + page().getBounds().top + y + 10,
|
|
||||||
30
|
|
||||||
);
|
|
||||||
tree.input(ingredient.getMatchingStacks());
|
|
||||||
bounds.height = tree.build(container) - 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,11 @@
|
||||||
package com.minelittlepony.unicopia.client.gui.spellbook;
|
package com.minelittlepony.unicopia.client.gui.spellbook.element;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import com.minelittlepony.common.client.gui.IViewRoot;
|
import com.minelittlepony.common.client.gui.IViewRoot;
|
||||||
import com.minelittlepony.common.client.gui.dimension.Bounds;
|
import com.minelittlepony.common.client.gui.dimension.Bounds;
|
||||||
import com.minelittlepony.unicopia.client.gui.DrawableUtil;
|
import com.minelittlepony.unicopia.client.gui.DrawableUtil;
|
||||||
|
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookScreen;
|
||||||
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Content;
|
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Content;
|
||||||
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Drawable;
|
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Drawable;
|
||||||
import com.minelittlepony.unicopia.container.SpellbookChapterLoader.Flow;
|
import com.minelittlepony.unicopia.container.SpellbookChapterLoader.Flow;
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.minelittlepony.unicopia.client.gui.spellbook.element;
|
||||||
|
|
||||||
|
import com.minelittlepony.common.client.gui.IViewRoot;
|
||||||
|
import com.minelittlepony.common.client.gui.dimension.Bounds;
|
||||||
|
import com.minelittlepony.unicopia.container.SpellbookChapterLoader.Flow;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
record Image(
|
||||||
|
Identifier texture,
|
||||||
|
Bounds bounds,
|
||||||
|
Flow flow) implements PageElement {
|
||||||
|
@Override
|
||||||
|
public void draw(DrawContext context, int mouseX, int mouseY, IViewRoot container) {
|
||||||
|
context.drawTexture(texture, 0, 0, 0, 0, 0, bounds().width, bounds().height, bounds().width, bounds().height);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package com.minelittlepony.unicopia.client.gui.spellbook.element;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
import com.minelittlepony.common.client.gui.IViewRoot;
|
||||||
|
import com.minelittlepony.common.client.gui.dimension.Bounds;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.crafting.IngredientWithSpell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
||||||
|
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Drawable;
|
||||||
|
import com.minelittlepony.unicopia.container.SpellbookChapterLoader.Flow;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.network.PacketByteBuf;
|
||||||
|
import net.minecraft.registry.Registries;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
|
public interface PageElement extends Drawable {
|
||||||
|
@Override
|
||||||
|
default void draw(DrawContext context, int mouseX, int mouseY, IViewRoot container) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Bounds bounds();
|
||||||
|
|
||||||
|
default Flow flow() {
|
||||||
|
return Flow.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean isInline() {
|
||||||
|
return flow() == Flow.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean isFloating() {
|
||||||
|
return !isInline();
|
||||||
|
}
|
||||||
|
|
||||||
|
default void compile(int y, IViewRoot Container) {}
|
||||||
|
|
||||||
|
static PageElement read(DynamicContent.Page page, PacketByteBuf buffer) {
|
||||||
|
byte type = buffer.readByte();
|
||||||
|
return switch (type) {
|
||||||
|
case 0 -> new Image(buffer.readIdentifier(), boundsFromBuffer(buffer), buffer.readEnumConstant(Flow.class));
|
||||||
|
case 1 -> new Recipe(page, buffer.readIdentifier(), Bounds.empty());
|
||||||
|
case 2 -> new Stack(page, IngredientWithSpell.fromPacket(buffer), boundsFromBuffer(buffer));
|
||||||
|
case 3 -> new TextBlock(page, List.of(Suppliers.ofInstance(buffer.readText())));
|
||||||
|
case 4 -> new TextBlock(page, buffer.readList(b -> {
|
||||||
|
int count = b.readVarInt();
|
||||||
|
byte t = b.readByte();
|
||||||
|
return switch (t) {
|
||||||
|
case 1 -> formatLine(capture(b.readIdentifier(), id -> {
|
||||||
|
return Registries.ITEM.get(id).getDefaultStack().getName();
|
||||||
|
}), "item", count);
|
||||||
|
case 2 -> formatLine(Trait.fromId(b.readIdentifier()).orElseThrow()::getShortName, "trait", count);
|
||||||
|
case 3 -> Suppliers.ofInstance(b.readText());
|
||||||
|
case 4 -> formatLine(SpellType.getKey(b.readIdentifier())::getName, "spell", count);
|
||||||
|
default -> throw new IllegalArgumentException("Unexpected value: " + t);
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
default -> throw new IllegalArgumentException("Unexpected value: " + type);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T, V> Supplier<V> capture(T t, Function<T, V> func) {
|
||||||
|
return () -> func.apply(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Supplier<Text> formatLine(Supplier<Text> line, String kind, int count) {
|
||||||
|
return () -> Text.translatable("gui.unicopia.spellbook.page.requirements.entry." + kind, count, line.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Bounds boundsFromBuffer(PacketByteBuf buffer) {
|
||||||
|
return new Bounds(buffer.readInt(), buffer.readInt(), buffer.readInt(), buffer.readInt());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.minelittlepony.unicopia.client.gui.spellbook.element;
|
||||||
|
|
||||||
|
import com.minelittlepony.common.client.gui.IViewRoot;
|
||||||
|
import com.minelittlepony.common.client.gui.dimension.Bounds;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe;
|
||||||
|
import com.minelittlepony.unicopia.client.gui.spellbook.IngredientTree;
|
||||||
|
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookScreen;
|
||||||
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
record Recipe (DynamicContent.Page page, Identifier id, Bounds bounds) implements PageElement {
|
||||||
|
@Override
|
||||||
|
public void compile(int y, IViewRoot container) {
|
||||||
|
if (container instanceof SpellbookScreen book) {
|
||||||
|
bounds().left = book.getX();
|
||||||
|
bounds().top = book.getY();
|
||||||
|
}
|
||||||
|
MinecraftClient.getInstance().world.getRecipeManager().get(id).ifPresent(recipe -> {
|
||||||
|
if (recipe instanceof SpellbookRecipe spellRecipe) {
|
||||||
|
|
||||||
|
boolean needsMoreXp = page.getLevel() < 0 || Pony.of(MinecraftClient.getInstance().player).getLevel().get() < page.getLevel();
|
||||||
|
|
||||||
|
IngredientTree tree = new IngredientTree(
|
||||||
|
bounds().left + page().getBounds().left,
|
||||||
|
bounds().top + page().getBounds().top + y + 10,
|
||||||
|
page().getBounds().width - 20
|
||||||
|
).obfuscateResult(needsMoreXp);
|
||||||
|
spellRecipe.buildCraftingTree(tree);
|
||||||
|
bounds.height = tree.build(container) - 10;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.minelittlepony.unicopia.client.gui.spellbook.element;
|
||||||
|
|
||||||
|
import com.minelittlepony.common.client.gui.IViewRoot;
|
||||||
|
import com.minelittlepony.common.client.gui.dimension.Bounds;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.crafting.IngredientWithSpell;
|
||||||
|
import com.minelittlepony.unicopia.client.gui.spellbook.IngredientTree;
|
||||||
|
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookScreen;
|
||||||
|
|
||||||
|
record Stack (DynamicContent.Page page, IngredientWithSpell ingredient, Bounds bounds) implements PageElement {
|
||||||
|
@Override
|
||||||
|
public void compile(int y, IViewRoot container) {
|
||||||
|
int xx = 0, yy = 0;
|
||||||
|
if (container instanceof SpellbookScreen book) {
|
||||||
|
xx = book.getX();
|
||||||
|
yy = book.getY();
|
||||||
|
}
|
||||||
|
IngredientTree tree = new IngredientTree(
|
||||||
|
bounds().left + xx + page().getBounds().left,
|
||||||
|
bounds().top + yy + page().getBounds().top + y + 10,
|
||||||
|
30
|
||||||
|
);
|
||||||
|
tree.input(ingredient.getMatchingStacks());
|
||||||
|
bounds.height = tree.build(container) - 10;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package com.minelittlepony.unicopia.client.gui.spellbook.element;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import com.minelittlepony.common.client.gui.IViewRoot;
|
||||||
|
import com.minelittlepony.common.client.gui.dimension.Bounds;
|
||||||
|
import com.minelittlepony.unicopia.client.gui.ParagraphWrappingVisitor;
|
||||||
|
import com.minelittlepony.unicopia.container.SpellbookChapterLoader.Flow;
|
||||||
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.text.Style;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Formatting;
|
||||||
|
|
||||||
|
class TextBlock implements PageElement {
|
||||||
|
private final DynamicContent.Page page;
|
||||||
|
|
||||||
|
private final List<TextBlock.Line> wrappedText = new ArrayList<>();
|
||||||
|
private final Bounds bounds = Bounds.empty();
|
||||||
|
private final List<Supplier<Text>> uncompiledLines;
|
||||||
|
|
||||||
|
public TextBlock(DynamicContent.Page page, List<Supplier<Text>> uncompiledLines) {
|
||||||
|
this.page = page;
|
||||||
|
this.uncompiledLines = uncompiledLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void compile(int y, IViewRoot container) {
|
||||||
|
wrappedText.clear();
|
||||||
|
ParagraphWrappingVisitor visitor = new ParagraphWrappingVisitor(
|
||||||
|
yPosition -> page.getLineLimitAt(y + yPosition),
|
||||||
|
(line, yPosition) -> wrappedText.add(new Line(line, page.getLeftMarginAt(y + yPosition)))
|
||||||
|
);
|
||||||
|
uncompiledLines.forEach(line -> {
|
||||||
|
line.get().visit(visitor, Style.EMPTY);
|
||||||
|
visitor.advance();
|
||||||
|
});
|
||||||
|
visitor.forceAdvance();
|
||||||
|
bounds.height = MinecraftClient.getInstance().textRenderer.fontHeight * (wrappedText.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(DrawContext context, int mouseX, int mouseY, IViewRoot container) {
|
||||||
|
TextRenderer font = MinecraftClient.getInstance().textRenderer;
|
||||||
|
boolean needsMoreXp = page.getLevel() < 0 || Pony.of(MinecraftClient.getInstance().player).getLevel().get() < page.getLevel();
|
||||||
|
MatrixStack matrices = context.getMatrices();
|
||||||
|
matrices.push();
|
||||||
|
wrappedText.forEach(line -> {
|
||||||
|
context.drawText(font, needsMoreXp ? line.text().copy().formatted(Formatting.OBFUSCATED) : line.text().copy(), line.x(), 0, 0, false);
|
||||||
|
matrices.translate(0, font.fontHeight, 0);
|
||||||
|
});
|
||||||
|
matrices.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bounds bounds() {
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Flow flow() {
|
||||||
|
return Flow.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Line(Text text, int x) { }
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import com.minelittlepony.common.client.gui.dimension.Bounds;
|
||||||
import com.minelittlepony.unicopia.Debug;
|
import com.minelittlepony.unicopia.Debug;
|
||||||
import com.minelittlepony.unicopia.Unicopia;
|
import com.minelittlepony.unicopia.Unicopia;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.crafting.IngredientWithSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.crafting.IngredientWithSpell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
||||||
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.*;
|
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.*;
|
||||||
import com.minelittlepony.unicopia.network.Channel;
|
import com.minelittlepony.unicopia.network.Channel;
|
||||||
import com.minelittlepony.unicopia.network.MsgServerResources;
|
import com.minelittlepony.unicopia.network.MsgServerResources;
|
||||||
|
@ -129,7 +130,7 @@ public class SpellbookChapterLoader extends JsonDataLoader implements Identifiab
|
||||||
this(
|
this(
|
||||||
Text.Serializer.fromJson(json.get("title")),
|
Text.Serializer.fromJson(json.get("title")),
|
||||||
JsonHelper.getInt(json, "level", 0),
|
JsonHelper.getInt(json, "level", 0),
|
||||||
new ArrayList<Element>()
|
new ArrayList<>()
|
||||||
);
|
);
|
||||||
JsonHelper.getArray(json, "elements", new JsonArray()).forEach(element -> {
|
JsonHelper.getArray(json, "elements", new JsonArray()).forEach(element -> {
|
||||||
elements.add(Element.read(element));
|
elements.add(Element.read(element));
|
||||||
|
@ -164,11 +165,19 @@ public class SpellbookChapterLoader extends JsonDataLoader implements Identifiab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record Recipe (Identifier id) implements Element {
|
record Multi(int count, Element element) implements Element {
|
||||||
@Override
|
@Override
|
||||||
public void toBuffer(PacketByteBuf buffer) {
|
public void toBuffer(PacketByteBuf buffer) {
|
||||||
buffer.writeByte(1);
|
buffer.writeVarInt(count);
|
||||||
buffer.writeIdentifier(id);
|
element.toBuffer(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record Id(byte id, Identifier value) implements Element {
|
||||||
|
@Override
|
||||||
|
public void toBuffer(PacketByteBuf buffer) {
|
||||||
|
buffer.writeByte(id);
|
||||||
|
buffer.writeIdentifier(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +198,31 @@ public class SpellbookChapterLoader extends JsonDataLoader implements Identifiab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record Ingredients(List<Element> entries) implements Element {
|
||||||
|
static Element loadIngredient(JsonObject json) {
|
||||||
|
int count = JsonHelper.getInt(json, "count", 1);
|
||||||
|
if (json.has("item")) {
|
||||||
|
return new Multi(count, new Id((byte)1, Identifier.tryParse(json.get("item").getAsString())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("trait")) {
|
||||||
|
return new Multi(count, new Id((byte)2, Trait.fromId(json.get("trait").getAsString()).orElseThrow().getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("spell")) {
|
||||||
|
return new Multi(count, new Id((byte)4, Identifier.tryParse(json.get("spell").getAsString())));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Multi(count, new TextBlock(Text.Serializer.fromJson(json.get("text"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toBuffer(PacketByteBuf buffer) {
|
||||||
|
buffer.writeByte(4);
|
||||||
|
buffer.writeCollection(entries, (b, c) -> c.toBuffer(b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void write(PacketByteBuf buffer, Element element) {
|
static void write(PacketByteBuf buffer, Element element) {
|
||||||
element.toBuffer(buffer);
|
element.toBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
@ -204,13 +238,22 @@ public class SpellbookChapterLoader extends JsonDataLoader implements Identifiab
|
||||||
Flow.valueOf(JsonHelper.getString(el, "flow", "RIGHT"))
|
Flow.valueOf(JsonHelper.getString(el, "flow", "RIGHT"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.has("recipe")) {
|
if (el.has("recipe")) {
|
||||||
return new Recipe(new Identifier(JsonHelper.getString(el, "recipe")));
|
return new Id((byte)1, new Identifier(JsonHelper.getString(el, "recipe")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.has("item")) {
|
if (el.has("item")) {
|
||||||
return new Stack(IngredientWithSpell.fromJson(el.get("item")), boundsFromJson(el));
|
return new Stack(IngredientWithSpell.fromJson(el.get("item")), boundsFromJson(el));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (el.has("ingredients")) {
|
||||||
|
return new Ingredients(JsonHelper.getArray(el, "ingredients").asList().stream()
|
||||||
|
.map(JsonElement::getAsJsonObject)
|
||||||
|
.map(Ingredients::loadIngredient)
|
||||||
|
.toList()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TextBlock(Text.Serializer.fromJson(json));
|
return new TextBlock(Text.Serializer.fromJson(json));
|
||||||
|
|
|
@ -170,8 +170,6 @@ public class SpellbookEntity extends MobEntity {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
System.out.println(activeTicks);
|
|
||||||
|
|
||||||
boolean daytime = MeteorlogicalUtil.getSkyAngle(getWorld()) < 1;
|
boolean daytime = MeteorlogicalUtil.getSkyAngle(getWorld()) < 1;
|
||||||
if (daytime != prevDaytime) {
|
if (daytime != prevDaytime) {
|
||||||
prevDaytime = daytime;
|
prevDaytime = daytime;
|
||||||
|
|
|
@ -461,6 +461,9 @@
|
||||||
"gui.unicopia.spellbook.page.recipes": "Recipes",
|
"gui.unicopia.spellbook.page.recipes": "Recipes",
|
||||||
"gui.unicopia.spellbook.page.recipes.empty": "0 Recipes Unlocked",
|
"gui.unicopia.spellbook.page.recipes.empty": "0 Recipes Unlocked",
|
||||||
"gui.unicopia.spellbook.page.mana": "Mana",
|
"gui.unicopia.spellbook.page.mana": "Mana",
|
||||||
|
"gui.unicopia.spellbook.page.requirements.entry.item": "- %1$sx %2$s",
|
||||||
|
"gui.unicopia.spellbook.page.requirements.entry.trait": "- At least %1$sx %2$s trait",
|
||||||
|
"gui.unicopia.spellbook.page.requirements.entry.spell": "- %1$sx %2$s gem",
|
||||||
|
|
||||||
"gui.unicopia.action.spells_cleared": "Removed all spells",
|
"gui.unicopia.action.spells_cleared": "Removed all spells",
|
||||||
"gui.unicopia.action.no_spells_cleared": "You have no active spells",
|
"gui.unicopia.action.no_spells_cleared": "You have no active spells",
|
||||||
|
|
|
@ -75,8 +75,14 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/catapult" },
|
{ "recipe": "unicopia:spells/catapult" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- 1x flame gem\n- At least 9x focus trait\n- At least 9x air trait",
|
{
|
||||||
"* One can add apply force by the strength trait"
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:flame" },
|
||||||
|
{ "count": 9, "trait": "unicopia:focus" },
|
||||||
|
{ "count": 9, "trait": "unicopia:air" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"* One can add apply more force by adding the strength trait"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -95,7 +101,13 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/bubble" },
|
{ "recipe": "unicopia:spells/bubble" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- 1x catapult gem\n- At least 9x water trait\n- At least 9x air trait"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:catapult" },
|
||||||
|
{ "count": 9, "trait": "unicopia:water" },
|
||||||
|
{ "count": 9, "trait": "unicopia:air" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -147,7 +159,15 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/feather_fall" },
|
{ "recipe": "unicopia:spells/feather_fall" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- 1x protection gem\n- At least 20x knowlege trait\n- At least 10x life trait\n- At least 10x generosity trait\n- At least 4x chaos trait"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:shield" },
|
||||||
|
{ "count": 20, "trait": "unicopia:knowledge" },
|
||||||
|
{ "count": 10, "trait": "unicopia:life" },
|
||||||
|
{ "count": 10, "trait": "unicopia:generosity" },
|
||||||
|
{ "count": 4, "trait": "unicopia:chaos" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -59,7 +59,13 @@
|
||||||
"text": "Aasa sasa fwefsd q43rgfd wqklmsdfl as, klasn.", "obfuscated": "true"
|
"text": "Aasa sasa fwefsd q43rgfd wqklmsdfl as, klasn.", "obfuscated": "true"
|
||||||
},
|
},
|
||||||
"Building Materials:",
|
"Building Materials:",
|
||||||
"- 2x end rod\n- 20x diamond block\n- 1x crystal heart"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 2, "item": "minecraft:end_rod" },
|
||||||
|
{ "count": 20, "item": "minecraft:diamond_block" },
|
||||||
|
{ "count": 1, "item": "unicopia:crystal_heart" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,8 +61,20 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/vortex" },
|
{ "recipe": "unicopia:spells/vortex" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- 1x protection gem\n- At least 10x strength trait\n- At least 8x knowledge trait\n- At least 9x air trait",
|
{
|
||||||
"+ 10x knowledge to narrow the effect's range to items\n+ add focus trait to increase duration\n+ add power trait to increase range"
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:shield" },
|
||||||
|
{ "count": 10, "trait": "unicopia:strength" },
|
||||||
|
{ "count": 8, "trait": "unicopia:knowledge" },
|
||||||
|
{ "count": 9, "trait": "unicopia:air" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "text": "+ 10x knowledge to narrow the effect's range to items" },
|
||||||
|
{ "text": "+ add focus trait to increase duration\n+ add power trait to increase range" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -170,7 +182,13 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/transformation" },
|
{ "recipe": "unicopia:spells/transformation" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- At least 18x knowledge trait\n- At least 10x life trait\n- At least 4x chaos trait"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 18, "trait": "unicopia:knowledge" },
|
||||||
|
{ "count": 10, "trait": "unicopia:life" },
|
||||||
|
{ "count": 4, "trait": "unicopia:chaos" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -189,7 +207,14 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/reveal" },
|
{ "recipe": "unicopia:spells/reveal" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- A protection gem\n- At least 18x knowledge trait\n- At least 1x life trait\n- At least 4x harmony trait",
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:shield" },
|
||||||
|
{ "count": 18, "trait": "unicopia:knowledge" },
|
||||||
|
{ "count": 1, "trait": "unicopia:life" },
|
||||||
|
{ "count": 4, "trait": "unicopia:order" }
|
||||||
|
]
|
||||||
|
},
|
||||||
"* Increase range by adding the power trait"
|
"* Increase range by adding the power trait"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -258,7 +283,14 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/arcane_protection" },
|
{ "recipe": "unicopia:spells/arcane_protection" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- A protection gem\n- At least 10x strength trait\n- At least 18x knowledge trait\n- At least 1x darkness trait",
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:shield" },
|
||||||
|
{ "count": 10, "trait": "unicopia:strength" },
|
||||||
|
{ "count": 18, "trait": "unicopia:knowledge" },
|
||||||
|
{ "count": 1, "trait": "unicopia:darkness" }
|
||||||
|
]
|
||||||
|
},
|
||||||
"* Increase range by adding the power trait"
|
"* Increase range by adding the power trait"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -277,7 +309,13 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/displacement" },
|
{ "recipe": "unicopia:spells/displacement" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- 1x gemstone\n- At least 18x knowledge trait\n- At least 10x chaos trait"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "item": "unicopia:gemstone" },
|
||||||
|
{ "count": 18, "trait": "unicopia:knowledge" },
|
||||||
|
{ "count": 10, "trait": "unicopia:chaos" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -311,7 +349,14 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/mimic" },
|
{ "recipe": "unicopia:spells/mimic" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- A transmutation gem\n- At least 19x knowledge trait\n- At least 10x life trait\n- At least 4x chaos trait",
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:transformation" },
|
||||||
|
{ "count": 19, "trait": "unicopia:knowledge" },
|
||||||
|
{ "count": 10, "trait": "unicopia:life" },
|
||||||
|
{ "count": 4, "trait": "unicopia:chaos" }
|
||||||
|
]
|
||||||
|
},
|
||||||
"* Add the focus trait to increase the effect's duration"
|
"* Add the focus trait to increase the effect's duration"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -381,7 +426,14 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/dispel_evil" },
|
{ "recipe": "unicopia:spells/dispel_evil" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- An arcane protection gem\n- A displacement gem\n- At least 1x kindness trait\n- At least 1x power trait",
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:arcane_protection" },
|
||||||
|
{ "count": 1, "spell": "unicopia:displacement" },
|
||||||
|
{ "count": 1, "trait": "unicopia:kindness" },
|
||||||
|
{ "count": 1, "trait": "unicopia:power" }
|
||||||
|
]
|
||||||
|
},
|
||||||
"* Add the power trait to increase the effect's range"
|
"* Add the power trait to increase the effect's range"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,11 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/scorch" },
|
{ "recipe": "unicopia:spells/scorch" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- At least 10x fire trait"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 10, "trait": "unicopia:fire" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -56,7 +60,13 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/flame" },
|
{ "recipe": "unicopia:spells/flame" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- 1x gemstone\n- At least 15x fire trait\n- A gem with scorch"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "item": "unicopia:gemstone" },
|
||||||
|
{ "count": 1, "spell": "unicopia:scorch" },
|
||||||
|
{ "count": 15, "trait": "unicopia:fire" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -123,7 +133,13 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/fire_bolt" },
|
{ "recipe": "unicopia:spells/fire_bolt" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- At least 9x focus for control and flight\n- 30x fire trait for energy\n- A gem with flame"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:flame" },
|
||||||
|
{ "count": 9, "trait": "unicopia:focus" },
|
||||||
|
{ "count": 30, "trait": "unicopia:fire" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -234,8 +250,15 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/shield" },
|
{ "recipe": "unicopia:spells/shield" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- 1x gemstone\n- At least 10x strength trait\n- At least 6x focus trait\n- At least 10x power trait",
|
{
|
||||||
"\n+ add power trait to increase effect range"
|
"ingredients": [
|
||||||
|
{ "count": 1, "item": "unicopia:gemstone" },
|
||||||
|
{ "count": 6, "trait": "unicopia:focus" },
|
||||||
|
{ "count": 10, "trait": "unicopia:strength" },
|
||||||
|
{ "count": 10, "trait": "unicopia:power" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"+ add power trait to increase effect range"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,7 +37,11 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/frost" },
|
{ "recipe": "unicopia:spells/frost" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- At least 15x ice trait"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 15, "trait": "unicopia:ice" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -56,7 +60,13 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/chilling_breath" },
|
{ "recipe": "unicopia:spells/chilling_breath" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- A frost gem\n- At least 5x ice trait\n- At least 10x knowledge trait"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:frost" },
|
||||||
|
{ "count": 5, "trait": "unicopia:ice" },
|
||||||
|
{ "count": 10, "trait": "unicopia:knowledge" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -88,17 +98,21 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "",
|
"title": "",
|
||||||
"level": 6,
|
"level": -1,
|
||||||
"elements": []
|
"elements": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "",
|
"title": "",
|
||||||
"level": -1,
|
"level": 6,
|
||||||
"elements": [
|
"elements": [
|
||||||
"Ice Spell II",
|
"Ice Spell II",
|
||||||
"Creates a cooling affect up to a radius of 3 hooves from any surfaces it touches.",
|
"Creates a cooling affect up to a radius of 3 hooves from any surfaces it touches.",
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- At least 15x cold trait",
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 15, "trait": "unicopia:ice" }
|
||||||
|
]
|
||||||
|
},
|
||||||
{ "x": 115, "y": -20, "width": 32, "height": 32, "texture": "minecraft:textures/item/snowball.png" },
|
{ "x": 115, "y": -20, "width": 32, "height": 32, "texture": "minecraft:textures/item/snowball.png" },
|
||||||
{ "x": 115, "y": -20, "width": 16, "height": 16, "texture": "unicopia:textures/gui/trait/ice.png" }
|
{ "x": 115, "y": -20, "width": 16, "height": 16, "texture": "unicopia:textures/gui/trait/ice.png" }
|
||||||
]
|
]
|
||||||
|
@ -129,7 +143,14 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/light" },
|
{ "recipe": "unicopia:spells/light" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- A fire bolt gem\n- At least 10x focus trait\n- At least 30x life trait\n- At least 30x ice trait",
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:fire_bolt" },
|
||||||
|
{ "count": 10, "trait": "unicopia:focus" },
|
||||||
|
{ "count": 30, "trait": "unicopia:life" },
|
||||||
|
{ "count": 30, "trait": "unicopia:ice" }
|
||||||
|
]
|
||||||
|
},
|
||||||
"* By adding more focus you can extend the duration of the spell"
|
"* By adding more focus you can extend the duration of the spell"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -272,9 +293,19 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/hydrophobic" },
|
{ "recipe": "unicopia:spells/hydrophobic" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- A gem with frost\n- A gem with protection\n- At least 6x focus trait",
|
{
|
||||||
"* By adding more focus you can extend the duration of the spell",
|
"ingredients": [
|
||||||
"* Add the generosity trait to tie this spell to a location rather than a user"
|
{ "count": 1, "spell": "unicopia:frost" },
|
||||||
|
{ "count": 1, "spell": "unicopia:shield" },
|
||||||
|
{ "count": 6, "trait": "unicopia:focus" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "text": "* By adding more focus you can extend the duration of the spell" },
|
||||||
|
{ "text": "* Add the generosity trait to tie this spell to a location rather than a user" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -35,7 +35,13 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/siphoning" },
|
{ "recipe": "unicopia:spells/siphoning" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- 1x inferno gem\n- At least 10x poison trait\n- At least 8x blood trait"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:infernal" },
|
||||||
|
{ "count": 10, "trait": "unicopia:poison" },
|
||||||
|
{ "count": 8, "trait": "unicopia:blood" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -59,7 +65,17 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/necromancy" },
|
{ "recipe": "unicopia:spells/necromancy" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- 1x life sapping gem\n- At least 10x strength trait\n- At least 8x knowledge trait\n- At least 8x chaos trait\n- At least 19x darkness trait\n- At least 9x poison trait\n- At least 10x blood trait"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:siphoning" },
|
||||||
|
{ "count": 10, "trait": "unicopia:strength" },
|
||||||
|
{ "count": 8, "trait": "unicopia:knowledge" },
|
||||||
|
{ "count": 8, "trait": "unicopia:chaos" },
|
||||||
|
{ "count": 19, "trait": "unicopia:darkness" },
|
||||||
|
{ "count": 9, "trait": "unicopia:poison" },
|
||||||
|
{ "count": 10, "trait": "unicopia:blood" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -78,7 +94,15 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/dark_vortex" },
|
{ "recipe": "unicopia:spells/dark_vortex" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- 1x arcane attraction gem\n- At least 10x strength trait\n- At least 8x knowledge trait\n- At least 8x chaos trait\n- At least 9x darkness trait"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:vortex" },
|
||||||
|
{ "count": 10, "trait": "unicopia:strength" },
|
||||||
|
{ "count": 8, "trait": "unicopia:knowledge" },
|
||||||
|
{ "count": 8, "trait": "unicopia:chaos" },
|
||||||
|
{ "count": 9, "trait": "unicopia:darkness" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -97,7 +121,15 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/portal" },
|
{ "recipe": "unicopia:spells/portal" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- 1x gemstone\n- 1x displacement gem\n- 1x dark vortext gem\n- At least 18x knowledge trait\n- At least 20x chaos trait"
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "item": "unicopia:gemstone" },
|
||||||
|
{ "count": 1, "spell": "unicopia:displacement" },
|
||||||
|
{ "count": 1, "spell": "unicopia:dark_vortex" },
|
||||||
|
{ "count": 18, "trait": "unicopia:knowledge" },
|
||||||
|
{ "count": 20, "trait": "unicopia:chaos" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -116,7 +148,14 @@
|
||||||
"elements": [
|
"elements": [
|
||||||
{ "recipe": "unicopia:spells/mind_swap" },
|
{ "recipe": "unicopia:spells/mind_swap" },
|
||||||
"Requires:",
|
"Requires:",
|
||||||
"- A mimic gem\n- At least 19x knowledge trait\n- At least 10x life trait\n- At least 40x chaos trait",
|
{
|
||||||
|
"ingredients": [
|
||||||
|
{ "count": 1, "spell": "unicopia:mimic" },
|
||||||
|
{ "count": 19, "trait": "unicopia:knowledge" },
|
||||||
|
{ "count": 10, "trait": "unicopia:life" },
|
||||||
|
{ "count": 40, "trait": "unicopia:chaos" }
|
||||||
|
]
|
||||||
|
},
|
||||||
"* Add the focus trait to increase the effect's duration"
|
"* Add the focus trait to increase the effect's duration"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue