Standardise the spell recipe ingredients/requirements lists

This commit is contained in:
Sollace 2023-08-14 13:05:20 +01:00
parent 3fcb05de81
commit 2ad431ab4b
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
20 changed files with 498 additions and 207 deletions

View file

@ -114,9 +114,11 @@ public enum Trait implements CommandArgumentEnum<Trait> {
}
public Text getName() {
return Text.translatable("gui.unicopia.trait.label",
Text.translatable("trait." + getId().getNamespace() + "." + getId().getPath() + ".name")
).formatted(Formatting.YELLOW);
return Text.translatable("gui.unicopia.trait.label", getShortName()).formatted(Formatting.YELLOW);
}
public Text getShortName() {
return Text.translatable("trait." + getId().getNamespace() + "." + getId().getPath() + ".name");
}
public List<Text> getTooltipLines() {

View file

@ -66,13 +66,19 @@ public class ParagraphWrappingVisitor implements StyledVisitor<Object> {
}
// append the segment to the line that's being built
if (currentLineCollectedLength > 0) {
if (currentLineCollectedLength > 0 && s.startsWith(" ")) {
currentLine.append(" ");
currentLineCollectedLength += handler.getWidth(" ");
}
currentLine.append(fragment);
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) {
advance();
}

View file

@ -2,6 +2,8 @@ package com.minelittlepony.unicopia.client.gui.spellbook;
import java.util.*;
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.util.*;

View file

@ -23,7 +23,7 @@ import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
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 Optional<IngredientTree.Entry> result = Optional.empty();

View file

@ -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;
}
}
}

View file

@ -1,10 +1,11 @@
package com.minelittlepony.unicopia.client.gui.spellbook;
package com.minelittlepony.unicopia.client.gui.spellbook.element;
import java.util.*;
import com.minelittlepony.common.client.gui.IViewRoot;
import com.minelittlepony.common.client.gui.dimension.Bounds;
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.Drawable;
import com.minelittlepony.unicopia.container.SpellbookChapterLoader.Flow;

View file

@ -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);
}
}

View file

@ -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());
}
}

View file

@ -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;
}
});
}
}

View file

@ -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;
}
}

View file

@ -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) { }
}

View file

@ -12,6 +12,7 @@ import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.unicopia.Debug;
import com.minelittlepony.unicopia.Unicopia;
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.network.Channel;
import com.minelittlepony.unicopia.network.MsgServerResources;
@ -129,7 +130,7 @@ public class SpellbookChapterLoader extends JsonDataLoader implements Identifiab
this(
Text.Serializer.fromJson(json.get("title")),
JsonHelper.getInt(json, "level", 0),
new ArrayList<Element>()
new ArrayList<>()
);
JsonHelper.getArray(json, "elements", new JsonArray()).forEach(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
public void toBuffer(PacketByteBuf buffer) {
buffer.writeByte(1);
buffer.writeIdentifier(id);
buffer.writeVarInt(count);
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) {
element.toBuffer(buffer);
}
@ -204,13 +238,22 @@ public class SpellbookChapterLoader extends JsonDataLoader implements Identifiab
Flow.valueOf(JsonHelper.getString(el, "flow", "RIGHT"))
);
}
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")) {
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));

View file

@ -170,8 +170,6 @@ public class SpellbookEntity extends MobEntity {
}
});
System.out.println(activeTicks);
boolean daytime = MeteorlogicalUtil.getSkyAngle(getWorld()) < 1;
if (daytime != prevDaytime) {
prevDaytime = daytime;

View file

@ -461,6 +461,9 @@
"gui.unicopia.spellbook.page.recipes": "Recipes",
"gui.unicopia.spellbook.page.recipes.empty": "0 Recipes Unlocked",
"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.no_spells_cleared": "You have no active spells",

View file

@ -75,8 +75,14 @@
"elements": [
{ "recipe": "unicopia:spells/catapult" },
"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": [
{ "recipe": "unicopia:spells/bubble" },
"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": [
{ "recipe": "unicopia:spells/feather_fall" },
"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" }
]
}
]
},
{

View file

@ -59,7 +59,13 @@
"text": "Aasa sasa fwefsd q43rgfd wqklmsdfl as, klasn.", "obfuscated": "true"
},
"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" }
]
}
]
},
{

View file

@ -61,8 +61,20 @@
"elements": [
{ "recipe": "unicopia:spells/vortex" },
"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": [
{ "recipe": "unicopia:spells/transformation" },
"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": [
{ "recipe": "unicopia:spells/reveal" },
"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"
]
},
@ -258,7 +283,14 @@
"elements": [
{ "recipe": "unicopia:spells/arcane_protection" },
"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"
]
},
@ -277,7 +309,13 @@
"elements": [
{ "recipe": "unicopia:spells/displacement" },
"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": [
{ "recipe": "unicopia:spells/mimic" },
"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"
]
},
@ -381,7 +426,14 @@
"elements": [
{ "recipe": "unicopia:spells/dispel_evil" },
"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"
]
}

View file

@ -37,7 +37,11 @@
"elements": [
{ "recipe": "unicopia:spells/scorch" },
"Requires:",
"- At least 10x fire trait"
{
"ingredients": [
{ "count": 10, "trait": "unicopia:fire" }
]
}
]
},
{
@ -56,7 +60,13 @@
"elements": [
{ "recipe": "unicopia:spells/flame" },
"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": [
{ "recipe": "unicopia:spells/fire_bolt" },
"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": [
{ "recipe": "unicopia:spells/shield" },
"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"
]
},
{

View file

@ -37,7 +37,11 @@
"elements": [
{ "recipe": "unicopia:spells/frost" },
"Requires:",
"- At least 15x ice trait"
{
"ingredients": [
{ "count": 15, "trait": "unicopia:ice" }
]
}
]
},
{
@ -56,7 +60,13 @@
"elements": [
{ "recipe": "unicopia:spells/chilling_breath" },
"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": "",
"level": 6,
"level": -1,
"elements": []
},
{
"title": "",
"level": -1,
"level": 6,
"elements": [
"Ice Spell II",
"Creates a cooling affect up to a radius of 3 hooves from any surfaces it touches.",
"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": 16, "height": 16, "texture": "unicopia:textures/gui/trait/ice.png" }
]
@ -129,7 +143,14 @@
"elements": [
{ "recipe": "unicopia:spells/light" },
"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"
]
},
@ -272,9 +293,19 @@
"elements": [
{ "recipe": "unicopia:spells/hydrophobic" },
"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",
"* Add the generosity trait to tie this spell to a location rather than a user"
{
"ingredients": [
{ "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" }
]
}
]
}
]

View file

@ -35,7 +35,13 @@
"elements": [
{ "recipe": "unicopia:spells/siphoning" },
"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": [
{ "recipe": "unicopia:spells/necromancy" },
"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": [
{ "recipe": "unicopia:spells/dark_vortex" },
"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": [
{ "recipe": "unicopia:spells/portal" },
"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": [
{ "recipe": "unicopia:spells/mind_swap" },
"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"
]
}