Implement botched gems: Crafting a combination that doesn't result in a working spell will now produce a "botched gem" that's only useful for collecting traits.

This commit is contained in:
Sollace 2022-08-28 17:12:33 +02:00
parent 60acaf64dd
commit 48f5943a5b
31 changed files with 248 additions and 118 deletions

View file

@ -47,10 +47,6 @@ public class Unicopia implements ModInitializer {
return new Identifier(DEFAULT_NAMESPACE, name); return new Identifier(DEFAULT_NAMESPACE, name);
} }
public Unicopia() {
getConfig();
}
@Override @Override
public void onInitialize() { public void onInitialize() {
Channel.bootstrap(); Channel.bootstrap();

View file

@ -6,7 +6,8 @@ import java.util.function.Predicate;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.google.gson.JsonObject; import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.item.GemstoneItem; import com.minelittlepony.unicopia.item.GemstoneItem;
@ -15,8 +16,11 @@ import net.minecraft.network.PacketByteBuf;
import net.minecraft.recipe.Ingredient; import net.minecraft.recipe.Ingredient;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper; import net.minecraft.util.JsonHelper;
import net.minecraft.util.collection.DefaultedList;
public class IngredientWithSpell implements Predicate<ItemStack> { public class IngredientWithSpell implements Predicate<ItemStack> {
private static final Predicate<Ingredient> INGREDIENT_IS_PRESENT = ((Predicate<Ingredient>)(Ingredient::isEmpty)).negate();
private Optional<Ingredient> stack = Optional.empty(); private Optional<Ingredient> stack = Optional.empty();
private Optional<SpellType<?>> spell = Optional.empty(); private Optional<SpellType<?>> spell = Optional.empty();
@ -43,45 +47,39 @@ public class IngredientWithSpell implements Predicate<ItemStack> {
return stacks; return stacks;
} }
public boolean isEmpty() {
return stack.filter(INGREDIENT_IS_PRESENT).isEmpty() && spell.isEmpty();
}
public void write(PacketByteBuf buf) { public void write(PacketByteBuf buf) {
stack.ifPresentOrElse(i -> { buf.writeOptional(stack, (b, i) -> i.write(b));
buf.writeBoolean(true); buf.writeOptional(spell.map(SpellType::getId), PacketByteBuf::writeIdentifier);
i.write(buf);
}, () -> buf.writeBoolean(false));
spell.ifPresentOrElse(i -> {
buf.writeBoolean(true);
buf.writeIdentifier(i.getId());
}, () -> buf.writeBoolean(false));
} }
public static IngredientWithSpell fromPacket(PacketByteBuf buf) { public static IngredientWithSpell fromPacket(PacketByteBuf buf) {
IngredientWithSpell ingredient = new IngredientWithSpell(); IngredientWithSpell ingredient = new IngredientWithSpell();
ingredient.stack = buf.readOptional(Ingredient::fromPacket);
if (buf.readBoolean()) { ingredient.spell = buf.readOptional(PacketByteBuf::readIdentifier).flatMap(SpellType.REGISTRY::getOrEmpty);
ingredient.stack = Optional.ofNullable(Ingredient.fromPacket(buf));
}
if (buf.readBoolean()) {
ingredient.spell = SpellType.REGISTRY.getOrEmpty(buf.readIdentifier());
}
return ingredient; return ingredient;
} }
public static IngredientWithSpell fromJson(JsonObject json) { public static IngredientWithSpell fromJson(JsonElement json) {
IngredientWithSpell ingredient = new IngredientWithSpell(); IngredientWithSpell ingredient = new IngredientWithSpell();
if (json.has("item") || json.has("spell")) {
if (json.has("item")) {
ingredient.stack = Optional.ofNullable(Ingredient.fromJson(JsonHelper.getObject(json, "item")));
}
if (json.has("spell")) {
ingredient.spell = SpellType.REGISTRY.getOrEmpty(Identifier.tryParse(JsonHelper.getString(json, "spell")));
}
} else {
ingredient.stack = Optional.ofNullable(Ingredient.fromJson(json)); ingredient.stack = Optional.ofNullable(Ingredient.fromJson(json));
if (json.isJsonObject() && json.getAsJsonObject().has("spell")) {
ingredient.spell = SpellType.REGISTRY.getOrEmpty(Identifier.tryParse(JsonHelper.getString(json.getAsJsonObject(), "spell")));
} }
return ingredient; return ingredient;
} }
public static DefaultedList<IngredientWithSpell> fromJson(JsonArray json) {
DefaultedList<IngredientWithSpell> ingredients = DefaultedList.of();
for (int i = 0; i < json.size(); i++) {
IngredientWithSpell ingredient = fromJson(json.get(i));
if (ingredient.isEmpty()) continue;
ingredients.add(ingredient);
}
return ingredients;
}
} }

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability.magic.spell.crafting; package com.minelittlepony.unicopia.ability.magic.spell.crafting;
import java.util.List;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
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;
@ -13,36 +15,63 @@ import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.ShapedRecipe; import net.minecraft.recipe.ShapedRecipe;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper; import net.minecraft.util.JsonHelper;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.world.World; import net.minecraft.world.World;
/** /**
* Recipe that requires an item and a certain number of traits to produce a result. * A recipe for creating a new spell from input traits and items.
*/ */
public class TraitRequirementRecipe implements SpellbookRecipe { public class SpellCraftingRecipe implements SpellbookRecipe {
private final Identifier id; private final Identifier id;
private final IngredientWithSpell requirement;
/**
* The ingredient to modify
*/
private final IngredientWithSpell material;
/**
* The required traits
*/
private final TraitIngredient requiredTraits; private final TraitIngredient requiredTraits;
/**
* Items required for crafting.
*/
private final List<IngredientWithSpell> requiredItems;
/**
* The resulting item
*/
private final ItemStack output; private final ItemStack output;
private TraitRequirementRecipe(Identifier id, IngredientWithSpell requirement, TraitIngredient requiredTraits, ItemStack output) { private SpellCraftingRecipe(Identifier id, IngredientWithSpell material, TraitIngredient requiredTraits, List<IngredientWithSpell> requiredItems, ItemStack output) {
this.id = id; this.id = id;
this.requirement = requirement; this.material = material;
this.requiredTraits = requiredTraits; this.requiredTraits = requiredTraits;
this.requiredItems = requiredItems;
this.output = output; this.output = output;
} }
@Override @Override
public void buildCraftingTree(CraftingTreeBuilder builder) { public void buildCraftingTree(CraftingTreeBuilder builder) {
builder.input(requirement.getMatchingStacks()); builder.input(material.getMatchingStacks());
for (var ingredient : requiredItems) {
builder.input(ingredient.getMatchingStacks());
}
requiredTraits.min().ifPresent(min -> { requiredTraits.min().ifPresent(min -> {
min.forEach(e -> builder.input(e.getKey(), e.getValue())); min.forEach(e -> builder.input(e.getKey(), e.getValue()));
}); });
builder.result(output); builder.result(output);
} }
@Override
public int getPriority() {
return 0;
}
@Override @Override
public boolean matches(SpellbookInventory inventory, World world) { public boolean matches(SpellbookInventory inventory, World world) {
return requirement.test(inventory.getItemToModify()) && requiredTraits.test(inventory.getTraits()); return material.test(inventory.getItemToModify()) && requiredTraits.test(inventory.getTraits());
} }
@Override @Override
@ -86,28 +115,31 @@ public class TraitRequirementRecipe implements SpellbookRecipe {
return stack; return stack;
} }
public static class Serializer implements RecipeSerializer<TraitRequirementRecipe> { public static class Serializer implements RecipeSerializer<SpellCraftingRecipe> {
@Override @Override
public TraitRequirementRecipe read(Identifier id, JsonObject json) { public SpellCraftingRecipe read(Identifier id, JsonObject json) {
return new TraitRequirementRecipe(id, return new SpellCraftingRecipe(id,
IngredientWithSpell.fromJson(JsonHelper.getObject(json, "material")), IngredientWithSpell.fromJson(json.get("material")),
TraitIngredient.fromJson(JsonHelper.getObject(json, "traits")), TraitIngredient.fromJson(JsonHelper.getObject(json, "traits")),
IngredientWithSpell.fromJson(JsonHelper.asArray(json.get("ingredients"), "ingredients")),
outputFromJson(JsonHelper.getObject(json, "result"))); outputFromJson(JsonHelper.getObject(json, "result")));
} }
@Override @Override
public TraitRequirementRecipe read(Identifier id, PacketByteBuf buf) { public SpellCraftingRecipe read(Identifier id, PacketByteBuf buf) {
return new TraitRequirementRecipe(id, return new SpellCraftingRecipe(id,
IngredientWithSpell.fromPacket(buf), IngredientWithSpell.fromPacket(buf),
TraitIngredient.fromPacket(buf), TraitIngredient.fromPacket(buf),
buf.readCollection(DefaultedList::ofSize, IngredientWithSpell::fromPacket),
buf.readItemStack() buf.readItemStack()
); );
} }
@Override @Override
public void write(PacketByteBuf buf, TraitRequirementRecipe recipe) { public void write(PacketByteBuf buf, SpellCraftingRecipe recipe) {
recipe.requirement.write(buf); recipe.material.write(buf);
recipe.requiredTraits.write(buf); recipe.requiredTraits.write(buf);
buf.writeCollection(recipe.requiredItems, (b, i) -> i.write(b));
buf.writeItemStack(recipe.output); buf.writeItemStack(recipe.output);
} }
} }

View file

@ -0,0 +1,86 @@
package com.minelittlepony.unicopia.ability.magic.spell.crafting;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.container.SpellbookScreenHandler.SpellbookInventory;
import com.minelittlepony.unicopia.item.*;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.util.Identifier;
import net.minecraft.world.World;
/**
* Recipe for adding traits to an existing spell.
*/
public class SpellEnhancingRecipe implements SpellbookRecipe {
private final Identifier id;
private final IngredientWithSpell material;
private SpellEnhancingRecipe(Identifier id, IngredientWithSpell material) {
this.id = id;
this.material = material;
}
@Override
public void buildCraftingTree(CraftingTreeBuilder builder) {
}
@Override
public int getPriority() {
return 1;
}
@Override
public boolean matches(SpellbookInventory inventory, World world) {
ItemStack stack = inventory.getItemToModify();
return !stack.isEmpty() && stack.getItem() == UItems.GEMSTONE && GemstoneItem.isEnchanted(stack);
}
@Override
public ItemStack craft(SpellbookInventory inventory) {
return SpellTraits.of(inventory.getItemToModify())
.add(inventory.getTraits())
.applyTo(inventory.getItemToModify());
}
@Override
public boolean fits(int width, int height) {
return (width * height) > 0;
}
@Override
public ItemStack getOutput() {
return UItems.GEMSTONE.getDefaultStack();
}
@Override
public Identifier getId() {
return id;
}
@Override
public RecipeSerializer<?> getSerializer() {
return URecipes.TRAIT_COMBINING;
}
public static class Serializer implements RecipeSerializer<SpellEnhancingRecipe> {
@Override
public SpellEnhancingRecipe read(Identifier id, JsonObject json) {
return new SpellEnhancingRecipe(id, IngredientWithSpell.fromJson(json.get("material")));
}
@Override
public SpellEnhancingRecipe read(Identifier id, PacketByteBuf buf) {
return new SpellEnhancingRecipe(id, IngredientWithSpell.fromPacket(buf));
}
@Override
public void write(PacketByteBuf buf, SpellEnhancingRecipe recipe) {
recipe.material.write(buf);
}
}
}

View file

@ -27,6 +27,8 @@ public interface SpellbookRecipe extends Recipe<SpellbookInventory> {
void buildCraftingTree(CraftingTreeBuilder builder); void buildCraftingTree(CraftingTreeBuilder builder);
int getPriority();
interface CraftingTreeBuilder { interface CraftingTreeBuilder {
void input(ItemStack...stack); void input(ItemStack...stack);

View file

@ -56,6 +56,10 @@ public final class SpellTraits implements Iterable<Map.Entry<Trait, Float>> {
return amount == 0 ? this : map(v -> v + amount); return amount == 0 ? this : map(v -> v + amount);
} }
public SpellTraits add(SpellTraits traits) {
return union(this, traits);
}
public SpellTraits map(Function<Float, Float> function) { public SpellTraits map(Function<Float, Float> function) {
return map((k, v) -> function.apply(v)); return map((k, v) -> function.apply(v));
} }

View file

@ -1,12 +1,13 @@
package com.minelittlepony.unicopia.container; package com.minelittlepony.unicopia.container;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.URecipes; import com.minelittlepony.unicopia.item.URecipes;
import com.minelittlepony.unicopia.util.InventoryUtil; import com.minelittlepony.unicopia.util.InventoryUtil;
import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Pair;
@ -147,10 +148,12 @@ public class SpellbookScreenHandler extends ScreenHandler {
if (!world.isClient && !gemSlot.getStack().isEmpty()) { if (!world.isClient && !gemSlot.getStack().isEmpty()) {
outputSlot.setStack( outputSlot.setStack(
world.getServer().getRecipeManager() world.getServer().getRecipeManager()
.getFirstMatch(URecipes.SPELLBOOK, input, world) .getAllMatches(URecipes.SPELLBOOK, input, world)
.stream().sorted(Comparator.comparing(SpellbookRecipe::getPriority))
.findFirst()
.filter(recipe -> result.shouldCraftRecipe(world, (ServerPlayerEntity)this.inventory.player, recipe)) .filter(recipe -> result.shouldCraftRecipe(world, (ServerPlayerEntity)this.inventory.player, recipe))
.map(recipe -> recipe.craft(input)) .map(recipe -> recipe.craft(input))
.orElse(ItemStack.EMPTY)); .orElse(UItems.BOTCHED_GEM.getDefaultStack()));
((ServerPlayerEntity)this.inventory.player).networkHandler.sendPacket(new ScreenHandlerSlotUpdateS2CPacket(syncId, nextRevision(), outputSlot.id, outputSlot.getStack())); ((ServerPlayerEntity)this.inventory.player).networkHandler.sendPacket(new ScreenHandlerSlotUpdateS2CPacket(syncId, nextRevision(), outputSlot.id, outputSlot.getStack()));
} }
@ -431,7 +434,7 @@ public class SpellbookScreenHandler extends ScreenHandler {
public void setStack(ItemStack stack) { public void setStack(ItemStack stack) {
super.setStack(stack); super.setStack(stack);
if (!stack.isEmpty()) { if (!stack.isEmpty()) {
player.playSound(USounds.GUI_SPELL_CRAFT_SUCCESS, SoundCategory.MASTER, 1, 0.3F); player.playSound(stack.getItem() == UItems.BOTCHED_GEM ? USounds.GUI_ABILITY_FAIL : USounds.GUI_SPELL_CRAFT_SUCCESS, SoundCategory.MASTER, 1, 0.3F);
} }
} }

View file

@ -57,6 +57,7 @@ public interface UItems {
Item CRYSTAL_SHARD = register("crystal_shard", new Item(new Item.Settings().group(ItemGroup.MATERIALS))); Item CRYSTAL_SHARD = register("crystal_shard", new Item(new Item.Settings().group(ItemGroup.MATERIALS)));
Item GEMSTONE = register("gemstone", new GemstoneItem(new Item.Settings().group(ItemGroup.MATERIALS))); Item GEMSTONE = register("gemstone", new GemstoneItem(new Item.Settings().group(ItemGroup.MATERIALS)));
Item BOTCHED_GEM = register("botched_gem", new Item(new Item.Settings().group(ItemGroup.MATERIALS)));
Item PEGASUS_FEATHER = register("pegasus_feather", new Item(new Item.Settings().group(ItemGroup.MATERIALS))); Item PEGASUS_FEATHER = register("pegasus_feather", new Item(new Item.Settings().group(ItemGroup.MATERIALS)));
Item GRYPHON_FEATHER = register("gryphon_feather", new Item(new Item.Settings().group(ItemGroup.MATERIALS))); Item GRYPHON_FEATHER = register("gryphon_feather", new Item(new Item.Settings().group(ItemGroup.MATERIALS)));

View file

@ -3,8 +3,7 @@ package com.minelittlepony.unicopia.item;
import java.util.List; import java.util.List;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe; import com.minelittlepony.unicopia.ability.magic.spell.crafting.*;
import com.minelittlepony.unicopia.ability.magic.spell.crafting.TraitRequirementRecipe;
import net.fabricmc.fabric.api.loot.v2.LootTableEvents; import net.fabricmc.fabric.api.loot.v2.LootTableEvents;
import net.minecraft.loot.LootTable; import net.minecraft.loot.LootTable;
@ -22,7 +21,8 @@ public interface URecipes {
RecipeSerializer<ShapelessRecipe> ZAP_APPLE_SERIALIZER = RecipeSerializer.register("unicopia:crafting_zap_apple", new ZapAppleRecipe.Serializer()); RecipeSerializer<ShapelessRecipe> ZAP_APPLE_SERIALIZER = RecipeSerializer.register("unicopia:crafting_zap_apple", new ZapAppleRecipe.Serializer());
RecipeSerializer<GlowingRecipe> GLOWING_SERIALIZER = RecipeSerializer.register("unicopia:crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new)); RecipeSerializer<GlowingRecipe> GLOWING_SERIALIZER = RecipeSerializer.register("unicopia:crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new));
RecipeSerializer<JarInsertRecipe> JAR_INSERT_SERIALIZER = RecipeSerializer.register("unicopia:jar_insert", new SpecialRecipeSerializer<>(JarInsertRecipe::new)); RecipeSerializer<JarInsertRecipe> JAR_INSERT_SERIALIZER = RecipeSerializer.register("unicopia:jar_insert", new SpecialRecipeSerializer<>(JarInsertRecipe::new));
RecipeSerializer<TraitRequirementRecipe> TRAIT_REQUIREMENT = RecipeSerializer.register("unicopia:spellbook/crafting", new TraitRequirementRecipe.Serializer()); RecipeSerializer<SpellCraftingRecipe> TRAIT_REQUIREMENT = RecipeSerializer.register("unicopia:spellbook/crafting", new SpellCraftingRecipe.Serializer());
RecipeSerializer<SpellEnhancingRecipe> TRAIT_COMBINING = RecipeSerializer.register("unicopia:spellbook/combining", new SpellEnhancingRecipe.Serializer());
static DefaultedList<Ingredient> getIngredients(JsonArray json) { static DefaultedList<Ingredient> getIngredients(JsonArray json) {
DefaultedList<Ingredient> defaultedList = DefaultedList.of(); DefaultedList<Ingredient> defaultedList = DefaultedList.of();

View file

@ -39,6 +39,7 @@
"item.unicopia.gemstone": "Gemstone", "item.unicopia.gemstone": "Gemstone",
"item.unicopia.gemstone.enchanted": "%s Gem", "item.unicopia.gemstone.enchanted": "%s Gem",
"item.unicopia.gemstone.obfuscated": "Mysterious Gem", "item.unicopia.gemstone.obfuscated": "Mysterious Gem",
"item.unicopia.botched_gem": "Botched Gem",
"item.unicopia.pegasus_feather": "Pegasus Feather", "item.unicopia.pegasus_feather": "Pegasus Feather",
"item.unicopia.gryphon_feather": "Gryphon Feather", "item.unicopia.gryphon_feather": "Gryphon Feather",

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/botched_gem"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

View file

@ -1,12 +1,13 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": {
"item": { "item": "unicopia:gemstone" }, "item": "unicopia:gemstone",
"spell": "unicopia:dark_vortex" "spell": "unicopia:dark_vortex"
}, },
"traits": { "traits": {
"darkness": 30, "power": 30, "blood": 30 "darkness": 30, "power": 30, "blood": 30
}, },
"ingredients": [],
"result": { "result": {
"item": "unicopia:alicorn_amulet" "item": "unicopia:alicorn_amulet"
} }

View file

@ -1,12 +1,12 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:flame"
},
"traits": { "traits": {
"focus": 9, "air": 9 "focus": 9, "air": 9
}, },
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:flame" }
],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:catapult" "spell": "unicopia:catapult"

View file

@ -1,12 +1,12 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:vortex"
},
"traits": { "traits": {
"strength": 10, "knowledge": 8, "darkness": 9, "chaos": 8 "strength": 10, "knowledge": 8, "darkness": 9, "chaos": 8
}, },
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:vortex" }
],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:dark_vortex" "spell": "unicopia:dark_vortex"

View file

@ -1,13 +1,13 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:shield"
},
"traits": { "traits": {
"knowledge": 20, "life": 10, "chaos": 4, "knowledge": 20, "life": 10, "chaos": 4,
"generosity": 10 "generosity": 10
}, },
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:shield" }
],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:feather_fall" "spell": "unicopia:feather_fall"

View file

@ -1,12 +1,12 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:flame"
},
"traits": { "traits": {
"focus": 9, "air": 9, "fire": 30 "focus": 9, "air": 9, "fire": 30
}, },
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:flame" }
],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:fire_bolt" "spell": "unicopia:fire_bolt"

View file

@ -1,12 +1,12 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:scorch"
},
"traits": { "traits": {
"fire": 20 "fire": 20
}, },
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:scorch" }
],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:flame" "spell": "unicopia:flame"

View file

@ -1,12 +1,10 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:none"
},
"traits": { "traits": {
"ice": 1 "ice": 1
}, },
"ingredients": [],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:frost" "spell": "unicopia:frost"

View file

@ -1,12 +1,12 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:flame"
},
"traits": { "traits": {
"fire": 50, "dark": 10 "fire": 50, "dark": 10
}, },
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:flame" }
],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:infernal" "spell": "unicopia:infernal"

View file

@ -1,12 +1,12 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:fire_bolt"
},
"traits": { "traits": {
"ice": 30, "life": 30, "focus": 10 "ice": 30, "life": 30, "focus": 10
}, },
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:fire_bolt" }
],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:light" "spell": "unicopia:light"

View file

@ -1,13 +1,13 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:siphoning"
},
"traits": { "traits": {
"strength": 10, "knowledge": 8, "darkness": 19, "chaos": 8, "strength": 10, "knowledge": 8, "darkness": 19, "chaos": 8,
"blood": 10, "poison": 9 "blood": 10, "poison": 9
}, },
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:siphoning" }
],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:necromancy" "spell": "unicopia:necromancy"

View file

@ -1,12 +1,12 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:shield"
},
"traits": { "traits": {
"knowledge": 18, "life": 1, "order": 4 "knowledge": 18, "life": 1, "order": 4
}, },
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:shield" }
],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:reveal" "spell": "unicopia:reveal"

View file

@ -1,12 +1,10 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:none"
},
"traits": { "traits": {
"fire": 10 "fire": 10
}, },
"ingredients": [],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:scorch" "spell": "unicopia:scorch"

View file

@ -1,12 +1,10 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:none"
},
"traits": { "traits": {
"strength": 10, "focus": 6, "power": 10 "strength": 10, "focus": 6, "power": 10
}, },
"ingredients": [],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:shield" "spell": "unicopia:shield"

View file

@ -1,12 +1,12 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:infernal"
},
"traits": { "traits": {
"blood": 8, "poison": 10 "blood": 8, "poison": 10
}, },
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:infernal" }
],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:siphoning" "spell": "unicopia:siphoning"

View file

@ -1,12 +1,10 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:none"
},
"traits": { "traits": {
"knowledge": 18, "life": 10, "chaos": 4 "knowledge": 18, "life": 10, "chaos": 4
}, },
"ingredients": [],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:transformation" "spell": "unicopia:transformation"

View file

@ -1,12 +1,12 @@
{ {
"type": "unicopia:spellbook/crafting", "type": "unicopia:spellbook/crafting",
"material": { "material": { "item": "unicopia:gemstone", "spell": "unicopia:none" },
"item": { "item": "unicopia:gemstone" },
"spell": "unicopia:shield"
},
"traits": { "traits": {
"strength": 10, "knowledge": 8 "strength": 10, "knowledge": 8
}, },
"ingredients": [
{ "item": "unicopia:gemstone", "spell": "unicopia:shield" }
],
"result": { "result": {
"item": "unicopia:gemstone", "item": "unicopia:gemstone",
"spell": "unicopia:vortex" "spell": "unicopia:vortex"

View file

@ -0,0 +1,4 @@
{
"type": "unicopia:spellbook/combining",
"material": { "item": "unicopia:botched_gem" }
}

View file

@ -0,0 +1,4 @@
{
"type": "unicopia:spellbook/combining",
"material": { "item": "unicopia:gemstone" }
}