diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/listeners/DisplayItemListener.java b/src/main/java/io/github/sefiraat/crystamaehistoria/listeners/DisplayItemListener.java index 4f2bc1dc..87359a10 100644 --- a/src/main/java/io/github/sefiraat/crystamaehistoria/listeners/DisplayItemListener.java +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/listeners/DisplayItemListener.java @@ -4,14 +4,23 @@ import io.github.thebusybiscuit.slimefun4.libraries.dough.data.persistent.PersistentDataAPI; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.entity.ItemDespawnEvent; import org.bukkit.event.inventory.InventoryPickupItemEvent; public class DisplayItemListener implements Listener { @EventHandler - public void onArmorStandManipulate(InventoryPickupItemEvent e) { + public void onItemPickup(InventoryPickupItemEvent e) { if (PersistentDataAPI.hasBoolean(e.getItem(), Keys.PDC_IS_DISPLAY_ITEM)) { e.setCancelled(true); } } + + @EventHandler + public void onItemDespawn(ItemDespawnEvent e) { + if (PersistentDataAPI.hasBoolean(e.getEntity(), Keys.PDC_IS_DISPLAY_ITEM)) { + e.setCancelled(true); + e.getEntity().setTicksLived(1); + } + } } diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/listeners/MiscListener.java b/src/main/java/io/github/sefiraat/crystamaehistoria/listeners/MiscListener.java index e336ea82..0d1f816f 100644 --- a/src/main/java/io/github/sefiraat/crystamaehistoria/listeners/MiscListener.java +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/listeners/MiscListener.java @@ -2,6 +2,7 @@ import io.github.sefiraat.crystamaehistoria.slimefun.gadgets.MysteriousTicker; import io.github.sefiraat.crystamaehistoria.utils.GeneralUtils; +import io.github.sefiraat.crystamaehistoria.utils.StoryUtils; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import me.mrCookieSlime.Slimefun.api.BlockStorage; import org.bukkit.Material; @@ -10,6 +11,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; @@ -26,6 +28,14 @@ public void onDontTouchMyCrap(PlayerInteractEvent e) { } } + @EventHandler + public void onPlaceStoriedBlock(BlockPlaceEvent e) { + ItemStack itemStack = e.getItemInHand(); + if (StoryUtils.isStoried(itemStack)) { + e.setCancelled(true); + } + } + @EventHandler(priority = EventPriority.LOWEST) public void checkCooldown(PlayerInteractEvent event) { ItemStack itemStack = event.getPlayer().getInventory().getItemInMainHand(); diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/player/BlockRank.java b/src/main/java/io/github/sefiraat/crystamaehistoria/player/BlockRank.java new file mode 100644 index 00000000..87ff61a4 --- /dev/null +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/player/BlockRank.java @@ -0,0 +1,45 @@ +package io.github.sefiraat.crystamaehistoria.player; + +import io.github.sefiraat.crystamaehistoria.utils.theme.ThemeType; +import lombok.Getter; + +public enum BlockRank { + + SME(100, ThemeType.RANK_BLOCK_SME), + MASTER_OF(90, ThemeType.RANK_BLOCK_MASTER_OF), + EXPERT_OF(70, ThemeType.RANK_BLOCK_EXPERT_OF), + RESEARCHED(50, ThemeType.RANK_BLOCK_RESEARCHED), + DETAILED(30, ThemeType.RANK_BLOCK_DETAILED), + KNOWN(20, ThemeType.RANK_BLOCK_KNOWN), + HEARD_OF(10, ThemeType.RANK_BLOCK_HEARD_OF), + UNKNOWN(0, ThemeType.RANK_BLOCK_UNKNOWN); + + private final double numberRequired; + @Getter + private final ThemeType theme; + + BlockRank(double numberRequired, ThemeType themeType) { + this.numberRequired = numberRequired; + this.theme = themeType; + } + + public static BlockRank getByAmount(double percent) { + if (percent >= SME.numberRequired) { + return SME; + } else if (percent >= MASTER_OF.numberRequired) { + return MASTER_OF; + } else if (percent >= EXPERT_OF.numberRequired) { + return EXPERT_OF; + } else if (percent >= RESEARCHED.numberRequired) { + return RESEARCHED; + } else if (percent >= DETAILED.numberRequired) { + return DETAILED; + } else if (percent >= KNOWN.numberRequired) { + return KNOWN; + } else if (percent >= HEARD_OF.numberRequired) { + return HEARD_OF; + } else { + return UNKNOWN; + } + } +} diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/player/PlayerStatistics.java b/src/main/java/io/github/sefiraat/crystamaehistoria/player/PlayerStatistics.java index c020b0df..71003b08 100644 --- a/src/main/java/io/github/sefiraat/crystamaehistoria/player/PlayerStatistics.java +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/player/PlayerStatistics.java @@ -6,14 +6,11 @@ import io.github.sefiraat.crystamaehistoria.utils.theme.ThemeType; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import java.util.UUID; public class PlayerStatistics { @@ -23,7 +20,7 @@ public static void unlockSpell(Player player, SpellType spellType) { } public static void unlockSpell(UUID player, SpellType spellType) { - String path = MessageFormat.format("{0}.{1}.{2}.Unlocked", player, StatType.SPELL, spellType.getId()); + String path = MessageFormat.format("{0}.{1}.{2}.UNLOCKED", player, StatType.SPELL, spellType.getId()); CrystamaeHistoria.getConfigManager().getPlayerStats().set(path, true); } @@ -32,7 +29,7 @@ public static boolean hasUnlockedSpell(Player player, SpellType spellType) { } public static boolean hasUnlockedSpell(UUID player, SpellType spellType) { - String path = MessageFormat.format("{0}.{1}.{2}.Unlocked", player, StatType.SPELL, spellType.getId()); + String path = MessageFormat.format("{0}.{1}.{2}.UNLOCKED", player, StatType.SPELL, spellType.getId()); return CrystamaeHistoria.getConfigManager().getPlayerStats().getBoolean(path); } @@ -43,7 +40,7 @@ public static void addUsage(Player player, SpellType spellType) { public static void addUsage(UUID player, SpellType spellType) { int uses = getUsages(player, spellType); uses++; - String path = MessageFormat.format("{0}.{1}.{2}.Times_Cast", player, StatType.SPELL, spellType.getId()); + String path = MessageFormat.format("{0}.{1}.{2}.TIMES_CAST", player, StatType.SPELL, spellType.getId()); CrystamaeHistoria.getConfigManager().getPlayerStats().set(path, uses); } @@ -52,7 +49,7 @@ public static int getUsages(Player player, SpellType spellType) { } public static int getUsages(UUID player, SpellType spellType) { - String path = MessageFormat.format("{0}.{1}.{2}.Times_Cast", player, StatType.SPELL, spellType.getId()); + String path = MessageFormat.format("{0}.{1}.{2}.TIMES_CAST", player, StatType.SPELL, spellType.getId()); return CrystamaeHistoria.getConfigManager().getPlayerStats().getInt(path); } @@ -61,7 +58,7 @@ public static void unlockUniqueStory(Player player, BlockDefinition definition) } public static void unlockUniqueStory(UUID player, BlockDefinition definition) { - String path = MessageFormat.format("{0}.{1}.{2}.Unlocked", player, StatType.STORY, definition.getMaterial()); + String path = MessageFormat.format("{0}.{1}.{2}.UNLOCKED", player, StatType.STORY, definition.getMaterial()); CrystamaeHistoria.getConfigManager().getPlayerStats().set(path, true); } @@ -74,7 +71,7 @@ public static boolean hasUnlockedUniqueStory(UUID player, BlockDefinition defini } public static boolean hasUnlockedUniqueStory(UUID player, Material material) { - String path = MessageFormat.format("{0}.{1}.{2}.Unlocked", player, StatType.STORY, material); + String path = MessageFormat.format("{0}.{1}.{2}.UNLOCKED", player, StatType.STORY, material); return CrystamaeHistoria.getConfigManager().getPlayerStats().getBoolean(path); } @@ -85,7 +82,7 @@ public static void addChronicle(Player player, BlockDefinition definition) { public static void addChronicle(UUID player, BlockDefinition definition) { int uses = getChronicle(player, definition); uses++; - String path = MessageFormat.format("{0}.{1}.{2}.Times_Chronicled", player, StatType.STORY, definition.getMaterial()); + String path = MessageFormat.format("{0}.{1}.{2}.TIMES_CHRONICLED", player, StatType.STORY, definition.getMaterial()); CrystamaeHistoria.getConfigManager().getPlayerStats().set(path, uses); } @@ -94,16 +91,45 @@ public static int getChronicle(Player player, BlockDefinition definition) { } public static int getChronicle(UUID player, BlockDefinition definition) { - String path = MessageFormat.format("{0}.{1}.{2}.Times_Chronicled", player, StatType.STORY, definition.getMaterial()); + String path = MessageFormat.format("{0}.{1}.{2}.TIMES_CHRONICLED", player, StatType.STORY, definition.getMaterial()); return CrystamaeHistoria.getConfigManager().getPlayerStats().getInt(path); } + public static void addRealisation(Player player, BlockDefinition definition) { + addChronicle(player.getUniqueId(), definition); + } + + public static void addRealisation(UUID player, BlockDefinition definition) { + int uses = getRealisation(player, definition); + uses++; + String path = MessageFormat.format("{0}.{1}.{2}.TIMES_REALISED", player, StatType.STORY, definition.getMaterial()); + CrystamaeHistoria.getConfigManager().getPlayerStats().set(path, uses); + } + + public static int getRealisation(Player player, BlockDefinition definition) { + return getChronicle(player.getUniqueId(), definition); + } + + public static int getRealisation(UUID player, BlockDefinition definition) { + String path = MessageFormat.format("{0}.{1}.{2}.TIMES_REALISED", player, StatType.STORY, definition.getMaterial()); + return CrystamaeHistoria.getConfigManager().getPlayerStats().getInt(path); + } + + @ParametersAreNonnullByDefault + public static BlockRank getBlockRank(UUID uuid, BlockDefinition definition) { + final int chronicleAmount = Math.min(getChronicle(uuid, definition), 100); + final int realisedAmount = Math.min(getRealisation(uuid, definition), 100); + final int blockValue = (chronicleAmount + realisedAmount) / 2; + return BlockRank.getByAmount(blockValue); + } + + public static int getStoriesUnlocked(@Nonnull UUID uuid) { String path = MessageFormat.format("{0}.{1}", uuid, StatType.STORY); ConfigurationSection section = CrystamaeHistoria.getConfigManager().getPlayerStats().getConfigurationSection(path); int unlocked = 0; for (String story : section.getKeys(false)) { - String storyPath = MessageFormat.format("{0}.{1}.{2}.Unlocked", uuid, StatType.STORY, story); + String storyPath = MessageFormat.format("{0}.{1}.{2}.UNLOCKED", uuid, StatType.STORY, story); if (CrystamaeHistoria.getConfigManager().getPlayerStats().getBoolean(storyPath)) unlocked++; } return unlocked; @@ -134,7 +160,7 @@ public static int getSpellsUnlocked(@Nonnull UUID uuid) { ConfigurationSection section = CrystamaeHistoria.getConfigManager().getPlayerStats().getConfigurationSection(path); int unlocked = 0; for (String spell : section.getKeys(false)) { - String storyPath = MessageFormat.format("{0}.{1}.{2}.Unlocked", uuid, StatType.SPELL, spell); + String storyPath = MessageFormat.format("{0}.{1}.{2}.UNLOCKED", uuid, StatType.SPELL, spell); if (CrystamaeHistoria.getConfigManager().getPlayerStats().getBoolean(storyPath)) unlocked++; } return unlocked; diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/Gadgets.java b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/Gadgets.java index 5b6f4e76..00b297d1 100644 --- a/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/Gadgets.java +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/Gadgets.java @@ -10,6 +10,8 @@ import io.github.sefiraat.crystamaehistoria.slimefun.gadgets.MobLamp; import io.github.sefiraat.crystamaehistoria.slimefun.gadgets.MobMat; import io.github.sefiraat.crystamaehistoria.slimefun.gadgets.MysteriousTicker; +import io.github.sefiraat.crystamaehistoria.slimefun.gadgets.TrophyDisplay; +import io.github.sefiraat.crystamaehistoria.slimefun.mechanisms.DisplayStandHolder; import io.github.sefiraat.crystamaehistoria.slimefun.mechanisms.liquefactionbasin.DummyLiquefactionBasinCrafting; import io.github.sefiraat.crystamaehistoria.slimefun.mechanisms.liquefactionbasin.LiquefactionBasinCache; import io.github.sefiraat.crystamaehistoria.slimefun.mechanisms.liquefactionbasin.RecipeItem; @@ -74,6 +76,8 @@ public class Gadgets { private static GreenHouseGlass greenHouseGlass; @Getter private static GreenHouseGlass focusedGreenHouseGlass; + @Getter + private static TrophyDisplay trophyDisplay; public static void setup() { @@ -624,6 +628,30 @@ amalgamateDustEpic, new ItemStack(Material.GLASS), amalgamateDustEpic, 10 ); + // Trophy Stand + RecipeItem trophyDisplayRecipe = new RecipeItem( + new ItemStack(Material.POLISHED_BLACKSTONE_BRICK_WALL), + StoryType.MECHANICAL, 10, + StoryType.HUMAN, 10, + StoryType.PHILOSOPHICAL, 10 + ); + trophyDisplay = new TrophyDisplay( + ItemGroups.GADGETS, + ThemeType.themedSlimefunItemStack( + "CRY_TROPHY_DISPLAY_1", + new ItemStack(Material.POLISHED_BLACKSTONE_BRICK_WALL), + ThemeType.GADGET, + "Trophy Display", + "Used to place your trophies on to show", + "off to the world.", + "", + "Currently allowable trophies include:", + ThemeType.CLICK_INFO.getColor() + "A block in which you have a S.M.E. rank" + ), + DummyLiquefactionBasinCrafting.TYPE, + trophyDisplayRecipe.getDisplayRecipe() + ); + // Slimefun Registry abstractionLamp.register(plugin); dispersionLamp.register(plugin); @@ -645,6 +673,7 @@ amalgamateDustEpic, new ItemStack(Material.GLASS), amalgamateDustEpic, mysteriousPlant.register(plugin); greenHouseGlass.register(plugin); focusedGreenHouseGlass.register(plugin); + trophyDisplay.register(plugin); // Liquefaction Recipes LiquefactionBasinCache.addCraftingRecipe(abstractionLamp, abstractionLampRecipe); @@ -669,5 +698,7 @@ amalgamateDustEpic, new ItemStack(Material.GLASS), amalgamateDustEpic, LiquefactionBasinCache.addCraftingRecipe(mysteriousPlant, mysteriousPlantRecipe); LiquefactionBasinCache.addCraftingRecipe(focusedGreenHouseGlass, focusedGreenHouseGlassRecipe); + + LiquefactionBasinCache.addCraftingRecipe(trophyDisplay, trophyDisplayRecipe); } } diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/gadgets/TrophyDisplay.java b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/gadgets/TrophyDisplay.java new file mode 100644 index 00000000..a53440ec --- /dev/null +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/gadgets/TrophyDisplay.java @@ -0,0 +1,170 @@ +package io.github.sefiraat.crystamaehistoria.slimefun.gadgets; + +import io.github.sefiraat.crystamaehistoria.CrystamaeHistoria; +import io.github.sefiraat.crystamaehistoria.player.BlockRank; +import io.github.sefiraat.crystamaehistoria.player.PlayerStatistics; +import io.github.sefiraat.crystamaehistoria.slimefun.mechanisms.TickingBlockNoGui; +import io.github.sefiraat.crystamaehistoria.stories.BlockDefinition; +import io.github.sefiraat.crystamaehistoria.utils.GeneralUtils; +import io.github.sefiraat.crystamaehistoria.utils.ParticleUtils; +import io.github.sefiraat.crystamaehistoria.utils.TextUtils; +import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent; +import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; +import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; +import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; +import lombok.Getter; +import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; +import me.mrCookieSlime.Slimefun.api.BlockStorage; +import net.md_5.bungee.api.ChatColor; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.block.Block; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +public class TrophyDisplay extends TickingBlockNoGui { + + private static final String PDC_ITEM = "itemUUID"; + + @Getter + private final Map itemMap = new HashMap<>(); + @Getter + private final Map currentTickMap = new HashMap<>(); + + @ParametersAreNonnullByDefault + public TrophyDisplay(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { + super(category, item, recipeType, recipe); + this.addItemHandler((BlockUseHandler) this::onRightClick); + } + + @Override + protected void onFirstTick(@NotNull Block block, @NotNull SlimefunItem slimefunItem, @NotNull Config config) { + final Location blockLocation = block.getLocation(); + String itemUuidString = BlockStorage.getLocationInfo(block.getLocation(), PDC_ITEM); + if (itemUuidString != null) { + itemMap.put(block.getLocation(), UUID.fromString(itemUuidString)); + } + // Set a random current tick + TrophyDisplay.this.currentTickMap.put( + blockLocation, + ThreadLocalRandom.current().nextInt(3, 7) + ); + } + + @Override + protected void onTick(@NotNull Block block, @NotNull SlimefunItem slimefunItem, @NotNull Config config) { + final Location blockLocation = block.getLocation(); + final UUID currentItemUuid = itemMap.get(blockLocation); + + // If an item isn't in place, then don't do anything + if (currentItemUuid != null) { + int currentTick = currentTickMap.get(blockLocation); + + // Only tick periodically + if (currentTick <= 0 && TrophyDisplay.this.itemMap.containsKey(blockLocation)) { + final Item currentItem = (Item) Bukkit.getEntity(currentItemUuid); + final Location itemLocation = currentItem.getLocation(); + final Location desiredLocation = blockLocation.clone().add(0.5, 1.5, 0.5); + + // Check if item has moved off the platform + if (itemLocation.distance(desiredLocation) > 0.3) { + final ItemStack itemStack = currentItem.getItemStack(); + blockLocation.getWorld().dropItemNaturally(blockLocation, itemStack); + BlockStorage.addBlockInfo(block, PDC_ITEM, null); + itemMap.remove(blockLocation); + currentItem.remove(); + } + + ParticleUtils.displayParticleEffect(itemLocation.add(0, 0.2, 0), Particle.WAX_ON, 0.2, 3); + TrophyDisplay.this.currentTickMap.put(blockLocation, ThreadLocalRandom.current().nextInt(4, 8)); + } else { + currentTick--; + TrophyDisplay.this.currentTickMap.put(blockLocation, currentTick); + } + } + } + + @Override + protected void onPlace(@NotNull BlockPlaceEvent event) { + TrophyDisplay.this.currentTickMap.put( + event.getBlock().getLocation(), + ThreadLocalRandom.current().nextInt(3, 7) + ); + } + + @Override + protected void onBreak(@NotNull BlockBreakEvent blockBreakEvent, @NotNull ItemStack itemStack, @NotNull List list) { + Location location = blockBreakEvent.getBlock().getLocation(); + final UUID currentItemUuid = itemMap.get(location); + if (currentItemUuid != null) { + final Item currentItem = (Item) Bukkit.getEntity(currentItemUuid); + final ItemStack displayStack = currentItem.getItemStack(); + location.getWorld().dropItemNaturally(location, displayStack); + BlockStorage.clearBlockInfo(location); + currentItem.remove(); + } + } + + private void onRightClick(PlayerRightClickEvent e) { + final Player player = e.getPlayer(); + + Optional optionalBlock = e.getClickedBlock(); + + if (!optionalBlock.isPresent()) { + return; + } + + e.cancel(); + + final Block blockClicked = optionalBlock.get(); + final UUID currentItemUuid = itemMap.get(blockClicked.getLocation()); + + // Stand already has an item, we try to remove this then return; + if (currentItemUuid != null) { + final Item currentItem = (Item) Bukkit.getEntity(currentItemUuid); + final ItemStack itemStack = currentItem.getItemStack(); + final HashMap rejected = player.getInventory().addItem(itemStack); + BlockStorage.addBlockInfo(blockClicked, PDC_ITEM, null); + itemMap.remove(blockClicked.getLocation()); + if (rejected.isEmpty()) { + currentItem.remove(); + } + return; + } + + final ItemStack itemStack = e.getItem(); + final Material material = itemStack.getType(); + final BlockDefinition definition = CrystamaeHistoria.getStoriesManager().getBlockDefinitionMap().get(material); + + if (definition != null && material != Material.AIR) { + final BlockRank blockRank = PlayerStatistics.getBlockRank( + player.getUniqueId(), + definition + ); + if (blockRank == BlockRank.SME) { + final Location location = blockClicked.getLocation().add(0.5, 1.5, 0.5); + final String name = ChatColor.of("#FFD100") + TextUtils.toTitleCase(material.toString()); + Item item = GeneralUtils.spawnDisplayItem(itemStack.asQuantity(1), location, name); + itemStack.setAmount(itemStack.getAmount() - 1); + BlockStorage.addBlockInfo(blockClicked, PDC_ITEM, item.getUniqueId().toString()); + itemMap.put(blockClicked.getLocation(), item.getUniqueId()); + } + } + } +} diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/itemgroups/StoryCollectionFlexGroup.java b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/itemgroups/StoryCollectionFlexGroup.java index 4ff108b9..5718079a 100644 --- a/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/itemgroups/StoryCollectionFlexGroup.java +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/itemgroups/StoryCollectionFlexGroup.java @@ -1,8 +1,8 @@ package io.github.sefiraat.crystamaehistoria.slimefun.itemgroups; import io.github.sefiraat.crystamaehistoria.CrystamaeHistoria; +import io.github.sefiraat.crystamaehistoria.player.BlockRank; import io.github.sefiraat.crystamaehistoria.player.PlayerStatistics; -import io.github.sefiraat.crystamaehistoria.player.SpellRank; import io.github.sefiraat.crystamaehistoria.player.StoryRank; import io.github.sefiraat.crystamaehistoria.slimefun.ItemGroups; import io.github.sefiraat.crystamaehistoria.slimefun.Materials; @@ -25,12 +25,14 @@ import org.bukkit.inventory.ItemStack; import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.stream.Collectors; /** @@ -55,6 +57,7 @@ public class StoryCollectionFlexGroup extends FlexItemGroup { private static final int CHRONICLING_SLOT = 20; private static final int TIER_SLOT = 22; + private static final int STATS_SLOT = 24; private static final int UNIQUE_SLOT = 40; private static final int[] DIVIDER = new int[]{ @@ -111,7 +114,7 @@ private void setupPage(@Nonnull Player player, @Nonnull PlayerProfile profile, @ }); // Stats - menu.replaceExistingItem(GUIDE_STATS, getStatsStack(player)); + menu.replaceExistingItem(GUIDE_STATS, getPlayerInfoStack(player)); menu.addMenuClickHandler(GUIDE_STATS, (player1, slot, itemStack, clickAction) -> false); for (int i = 0; i < 36; i++) { @@ -161,6 +164,9 @@ private void displayDefinition(@Nonnull Player p, @Nonnull PlayerProfile profile menu.replaceExistingItem(TIER_SLOT, getTierItemStack(definition)); menu.addMenuClickHandler(TIER_SLOT, (player, i, itemStack, clickAction) -> false); + menu.replaceExistingItem(STATS_SLOT, getStatsStack(p.getUniqueId(), definition)); + menu.addMenuClickHandler(STATS_SLOT, (player, i, itemStack, clickAction) -> false); + menu.replaceExistingItem(UNIQUE_SLOT, getUniqueStoryItemStack(definition)); menu.addMenuClickHandler(UNIQUE_SLOT, (player, i, itemStack, clickAction) -> false); @@ -253,7 +259,32 @@ private ItemStack getTierItemStack(@Nonnull BlockDefinition definition) { } } - private ItemStack getStatsStack(Player player) { + @ParametersAreNonnullByDefault + private ItemStack getStatsStack(UUID player, BlockDefinition definition) { + final ChatColor color = ThemeType.CLICK_INFO.getColor(); + final ChatColor passive = ThemeType.PASSIVE.getColor(); + final List lore = new ArrayList<>(); + final BlockRank blockRank = PlayerStatistics.getBlockRank(player, definition); + + final int timesChronicled = PlayerStatistics.getChronicle(player, definition); + final int timesRealised = PlayerStatistics.getRealisation(player, definition); + + final String chronicleCap = timesChronicled > 100 ? "(Capped at 100)" : ""; + final String realisationCap = timesRealised > 100 ? "(Capped at 100)" : ""; + + lore.add(MessageFormat.format("{0}Rank: {1}{2}", color, blockRank.getTheme().getColor(), blockRank.getTheme().getLoreLine())); + lore.add(""); + lore.add(MessageFormat.format("{0}Times Chronicled: {1}{2} {3}", color, passive, timesChronicled, chronicleCap)); + lore.add(MessageFormat.format("{0}Times Realised: {1}{2} {3}", color, passive, timesRealised, realisationCap)); + + return new CustomItemStack( + Material.TARGET, + ThemeType.MAIN.getColor() + "Item Statistics", + lore + ); + } + + private ItemStack getPlayerInfoStack(Player player) { final ChatColor color = ThemeType.CLICK_INFO.getColor(); final ChatColor passive = ThemeType.PASSIVE.getColor(); final List lore = new ArrayList<>(); diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/TickingBlockNoGui.java b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/TickingBlockNoGui.java index a491f781..7f21b6bc 100644 --- a/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/TickingBlockNoGui.java +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/TickingBlockNoGui.java @@ -9,6 +9,7 @@ import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; +import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; @@ -16,11 +17,13 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.HashMap; import java.util.List; +import java.util.Map; public abstract class TickingBlockNoGui extends SlimefunItem { - protected boolean firstTick = true; + protected final Map firstTickMap = new HashMap<>(); protected TickingBlockNoGui(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(itemGroup, item, recipeType, recipe); @@ -49,9 +52,9 @@ public boolean isSynchronized() { @Override public void tick(Block block, SlimefunItem slimefunItem, Config config) { - if (firstTick) { + if (!firstTickMap.containsKey(block.getLocation())) { onFirstTick(block, slimefunItem, config); - firstTick = false; + firstTickMap.put(block.getLocation(), true); } onTick(block, slimefunItem, config); } diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/realisationaltar/RealisationAltar.java b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/realisationaltar/RealisationAltar.java index 09b08a4e..76a6e4bd 100644 --- a/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/realisationaltar/RealisationAltar.java +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/realisationaltar/RealisationAltar.java @@ -1,18 +1,23 @@ package io.github.sefiraat.crystamaehistoria.slimefun.mechanisms.realisationaltar; import io.github.mooy1.infinitylib.machines.TickingMenuBlock; +import io.github.sefiraat.crystamaehistoria.slimefun.mechanisms.chroniclerpanel.ChroniclerPanelCache; import io.github.sefiraat.crystamaehistoria.utils.theme.GuiElements; import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; +import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import lombok.Getter; +import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.inventory.ItemStack; +import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; import java.util.HashMap; import java.util.Map; @@ -27,7 +32,7 @@ public class RealisationAltar extends TickingMenuBlock { }; protected static final int INPUT_SLOT = 22; - protected static final Map CACHE_MAP = new HashMap<>(); + protected static final Map CACHES = new HashMap<>(); @Getter private final int tier; @@ -36,16 +41,25 @@ public class RealisationAltar extends TickingMenuBlock { public RealisationAltar(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, int tier) { super(itemGroup, item, recipeType, recipe); this.tier = tier; + this.addItemHandler(new BlockPlaceHandler(false) { + @Override + public void onPlayerPlace(@Nonnull BlockPlaceEvent event) { + final Location location = event.getBlockPlaced().getLocation(); + final RealisationAltarCache cache = new RealisationAltarCache(BlockStorage.getInventory(location), tier); + cache.setActivePlayer(event.getPlayer()); + CACHES.put(location, cache); + } + }); } public static Map getCaches() { - return CACHE_MAP; + return CACHES; } @Override @ParametersAreNonnullByDefault protected void tick(Block block, BlockMenu blockMenu) { - RealisationAltarCache cache = RealisationAltar.CACHE_MAP.get(block.getLocation()); + RealisationAltarCache cache = RealisationAltar.CACHES.get(block.getLocation()); if (cache != null) { cache.process(); } @@ -73,7 +87,7 @@ protected int[] getOutputSlots() { protected void onBreak(BlockBreakEvent event, BlockMenu blockMenu) { super.onBreak(event, blockMenu); Location location = blockMenu.getLocation(); - RealisationAltarCache realisationAltarCache = CACHE_MAP.remove(location); + RealisationAltarCache realisationAltarCache = CACHES.remove(location); if (realisationAltarCache != null) { realisationAltarCache.kill(); } @@ -84,14 +98,15 @@ protected void onBreak(BlockBreakEvent event, BlockMenu blockMenu) { @ParametersAreNonnullByDefault protected void onNewInstance(BlockMenu blockMenu, Block b) { super.onNewInstance(blockMenu, b); - RealisationAltarCache cache = new RealisationAltarCache(blockMenu, this.tier); - cache.loadMap(); - CACHE_MAP.put(blockMenu.getLocation(), cache); + if (!CACHES.containsKey(blockMenu.getLocation())) { + RealisationAltarCache cache = new RealisationAltarCache(blockMenu, this.tier); + cache.loadMap(); + CACHES.put(blockMenu.getLocation(), cache); + } } @Override protected boolean synchronous() { return true; } - } diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/realisationaltar/RealisationAltarCache.java b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/realisationaltar/RealisationAltarCache.java index 9e934a74..f848eebe 100644 --- a/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/realisationaltar/RealisationAltarCache.java +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/slimefun/mechanisms/realisationaltar/RealisationAltarCache.java @@ -1,6 +1,7 @@ package io.github.sefiraat.crystamaehistoria.slimefun.mechanisms.realisationaltar; import io.github.sefiraat.crystamaehistoria.CrystamaeHistoria; +import io.github.sefiraat.crystamaehistoria.player.PlayerStatistics; import io.github.sefiraat.crystamaehistoria.slimefun.mechanisms.AbstractCache; import io.github.sefiraat.crystamaehistoria.stories.BlockDefinition; import io.github.sefiraat.crystamaehistoria.stories.StoriesManager; @@ -16,6 +17,7 @@ import io.github.thebusybiscuit.slimefun4.libraries.dough.collections.Pair; import io.github.thebusybiscuit.slimefun4.libraries.dough.data.persistent.PersistentDataAPI; import lombok.Getter; +import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; import org.bukkit.Chunk; import org.bukkit.Location; @@ -33,6 +35,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; public class RealisationAltarCache extends AbstractCache { @@ -45,6 +48,11 @@ public class RealisationAltarCache extends AbstractCache { public RealisationAltarCache(BlockMenu blockMenu, int tier) { super(blockMenu); this.maxTier = tier + 1; + + final String activePlayerString = BlockStorage.getLocationInfo(blockMenu.getLocation(), Keys.BS_CP_ACTIVE_PLAYER); + if (activePlayerString != null) { + this.activePlayer = UUID.fromString(activePlayerString); + } } protected void process() { @@ -94,6 +102,7 @@ private boolean processItem(ItemStack itemStack) { potentialBlock.setType(Material.SMALL_AMETHYST_BUD); crystalStoryMap.put(new BlockPosition(potentialBlock.getLocation()), new Pair<>(story.getRarity(), story.getId())); if (StoryUtils.removeStory(itemStack, story) == 0) { + PlayerStatistics.addRealisation(activePlayer, definition); itemStack.setAmount(0); } else { StoriesManager.rebuildStoriedStack(itemStack); diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/utils/GeneralUtils.java b/src/main/java/io/github/sefiraat/crystamaehistoria/utils/GeneralUtils.java index 7ee30b2f..ccd35a1e 100644 --- a/src/main/java/io/github/sefiraat/crystamaehistoria/utils/GeneralUtils.java +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/utils/GeneralUtils.java @@ -232,7 +232,7 @@ public static Item spawnDisplayItem(ItemStack stack, Location location, String n item.setGravity(false); item.setVelocity(new Vector(0, 0, 0)); item.setCanPlayerPickup(false); - item.setPickupDelay(999999); + item.setPickupDelay(Integer.MAX_VALUE); return item; } diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/utils/StoryUtils.java b/src/main/java/io/github/sefiraat/crystamaehistoria/utils/StoryUtils.java index 2c4cca58..42bed402 100644 --- a/src/main/java/io/github/sefiraat/crystamaehistoria/utils/StoryUtils.java +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/utils/StoryUtils.java @@ -185,23 +185,23 @@ public static JsonObject getInitialStoryLimits(ItemStack itemStack) { @ParametersAreNonnullByDefault public static void requestNewStory(ItemStack itemstack) { - final StoriesManager m = CrystamaeHistoria.getStoriesManager(); - final BlockDefinition s = m.getBlockDefinitionMap().get(itemstack.getType()); - final BlockTier t = s.getTier(); - final StoryChances c = t.storyChances; - final List p = s.getPools(); + final StoriesManager manager = CrystamaeHistoria.getStoriesManager(); + final BlockDefinition definition = manager.getBlockDefinitionMap().get(itemstack.getType()); + final BlockTier tier = definition.getTier(); + final StoryChances chance = tier.storyChances; + final List pool = definition.getPools(); int rnd = ThreadLocalRandom.current().nextInt(1, 101); - if (rnd <= c.mythical) { - addStory(itemstack, p, m.getStoryMapMythical()); - } else if (rnd <= c.epic) { - addStory(itemstack, p, m.getStoryMapEpic()); - } else if (rnd <= c.rare) { - addStory(itemstack, p, m.getStoryMapRare()); - } else if (rnd <= c.uncommon) { - addStory(itemstack, p, m.getStoryMapUncommon()); + if (rnd <= chance.mythical) { + addStory(itemstack, pool, manager.getStoryMapMythical()); + } else if (rnd <= chance.epic) { + addStory(itemstack, pool, manager.getStoryMapEpic()); + } else if (rnd <= chance.rare) { + addStory(itemstack, pool, manager.getStoryMapRare()); + } else if (rnd <= chance.uncommon) { + addStory(itemstack, pool, manager.getStoryMapUncommon()); } else { - addStory(itemstack, p, m.getStoryMapCommon()); + addStory(itemstack, pool, manager.getStoryMapCommon()); } } diff --git a/src/main/java/io/github/sefiraat/crystamaehistoria/utils/theme/ThemeType.java b/src/main/java/io/github/sefiraat/crystamaehistoria/utils/theme/ThemeType.java index 49f04374..d83968b0 100644 --- a/src/main/java/io/github/sefiraat/crystamaehistoria/utils/theme/ThemeType.java +++ b/src/main/java/io/github/sefiraat/crystamaehistoria/utils/theme/ThemeType.java @@ -81,7 +81,15 @@ public enum ThemeType { RANK_STORY_LECTURER(ChatColor.of("#ceff00"), "Lecturer"), RANK_STORY_PROFESSOR(ChatColor.of("#99ff00"), "Professor"), RANK_STORY_ADJUNCT_PROFESSOR(ChatColor.of("#6aff00"), "Adjunct Professor"), - RANK_STORY_EMERITUS_PROFESSOR(ChatColor.of("#33ff00"), "Emeritus Professor"); + RANK_STORY_EMERITUS_PROFESSOR(ChatColor.of("#33ff00"), "Emeritus Professor"), + RANK_BLOCK_UNKNOWN(ChatColor.of("#a8ffb1"), "Unknown"), + RANK_BLOCK_HEARD_OF(ChatColor.of("#87ff94"), "Heard-of"), + RANK_BLOCK_KNOWN(ChatColor.of("#66ff77"), "Known"), + RANK_BLOCK_DETAILED(ChatColor.of("#4dff60"), "Detailed"), + RANK_BLOCK_RESEARCHED(ChatColor.of("#29ff40"), "Researched"), + RANK_BLOCK_EXPERT_OF(ChatColor.of("#0fff29"), "Expert-of"), + RANK_BLOCK_MASTER_OF(ChatColor.of("#00db18"), "Master-of"), + RANK_BLOCK_SME(ChatColor.of("#00820e"), "S.M.E."); /** * List of names to be given to ArmourStands, invisible but mods and Minimaps can see them :) diff --git a/src/main/resources/blocks.yml b/src/main/resources/blocks.yml index 1db7606d..6c57290c 100644 --- a/src/main/resources/blocks.yml +++ b/src/main/resources/blocks.yml @@ -1868,147 +1868,170 @@ CARROT: shards: [ 0,0,0,0,1,1,1,0,0 ] CARROT_ON_A_STICK: - tier: 1 + tier: 2 elements: - - + - ANIMAL story: - name: - type: + name: A Great Incentive (Carrot) + type: ANIMAL lore: - - - shards: + - Slowly draws magical power from the creatures + - that this item attracts. + shards: [0,0,0,0,1,1,0,0,1] CARTOGRAPHY_TABLE: - tier: 1 + tier: 2 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Drawn Exploration + type: PHILOSOPHICAL lore: - - - shards: + - Dreaming of seeing the far corners of the + - worlds, this block has to sit and live + - through the acheivments of others. + shards: [0,0,0,1,2,0,0,0,1] CARVED_PUMPKIN: - tier: 1 + tier: 2 elements: - - + - ELEMENTAL + - ANIMAL story: - name: - type: + name: A Magical Life + type: ANIMAL lore: - - - shards: + - It's still unknown how or why this block + - is able to create life. Scholars know magic + - is involved but no one has been able to see + - at which point it intervenes. + shards: [1,0,0,1,0,2,0,0,0] CAULDRON: - tier: 1 + tier: 2 elements: - - + - ELEMENTAL + - HUMAN + - ALCHEMICAL story: - name: - type: + name: A Magical Start + type: ALCHEMICAL lore: - - - shards: + - Often seen as the beginning for most magical + - professions. The cauldron is imbued with + - more magic than most other objects. + shards: [1,0,2,0,1,0,0,0,1] CHAIN: - tier: 1 + tier: 2 elements: - - + - ELEMENTAL + - VOID story: - name: - type: + name: Shackled + type: VOID lore: - - - shards: + - A history of enchained prisoners has made + - the essence of this item scullied and void. + shards: [1,1,0,0,0,0,0,1,0] CHAINMAIL_BOOTS: - tier: 1 + tier: 2 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Greave Greif (Chain) + type: PHILOSOPHICAL lore: - - - shards: + - Like all armour, boots ant nothing more + - than to keep their wearer safe. Unforunatley + - they are overshadowed by other gear. + shards: [0,0,0,1,2,0,0,0,1] CHAINMAIL_CHESTPLATE: - tier: 1 + tier: 2 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: The Great Defender (Chain) + type: HUMAN lore: - - - shards: + - Every hit, scrape and pummel stopped by the + - chestplate reinforces it's magics by giving + - it purpose and drive. + shards: [0,1,0,1,2,0,1,0,0] CHAINMAIL_HELMET: - tier: 1 + tier: 2 elements: - - + - HUMAN + - VOID story: - name: - type: + name: Head above the rest (Chain) + type: VOID lore: - - - shards: + - A magicians most important tool is their own + - mind, any steps taken to protect that tool + - are vital and wise. + shards: [0,0,0,1,1,0,0,1,0] CHAINMAIL_LEGGINGS: - tier: 1 - elements: - - - story: - name: - type: - lore: - - - shards: - -CHAIN_COMMAND_BLOCK: - tier: 1 + tier: 2 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: Leggless (Chain) + type: CELESTIAL lore: - - - shards: + - Like it's other armour brethren, leggings + - absorb crysta from their users in miniscule + - amounts over their tenure. + shards: [0,0,0,1,2,0,1,0,0] CHARCOAL: tier: 1 elements: - - + - ELEMENTAL + - PHILOSOPHICAL story: - name: - type: + name: Burnt Out + type: PHILOSOPHICAL lore: - - - shards: + - In the formation of charcoal, all the innate + - magic of a log is used up leaving only + - remnants. + shards: [1,0,0,0,0,0,0,0,1] CHEST: tier: 1 elements: - - + - HUMAN + - MECHANICAL story: - name: - type: + name: Safe and Sound + type: MECHANICAL lore: - - - shards: + - While attempting to keep the held items + - safe, the chest loses drive for all other + - things. + shards: [0,1,0,0,2,0,0,0,0] CHEST_MINECART: - tier: 1 + tier: 2 elements: - - + - HUMAN + - MECHANICAL story: - name: - type: + name: Safe and Sound... and fun! + type: MECHANICAL lore: - - - shards: + - Previously having lost the drive, being on + - wheels has reignited the spirit of the chest. + shards: [0,2,0,0,2,0,0,0,0] CHICKEN: tier: 1 @@ -2025,92 +2048,110 @@ CHICKEN: shards: [ 0,0,0,0,1,1,0,0,1 ] CHIPPED_ANVIL: - tier: 1 + tier: 3 elements: - - + - MECHANICAL + - HUMAN story: - name: - type: + name: Hammer Time! (Chipped) + type: MECHANICAL lore: - - - shards: + - The essence of every tool that + - has touched the anvil imparts + - a part of itself to the anvil. + shards: [ 0,1,0,0,1,0,0,0,0 ] CHISELED_DEEPSLATE: - tier: 1 + tier: 2 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Artisan (Deepslate) + type: PHILOSOPHICAL lore: - - - shards: + - An artisan, without knowing, gives a portion + - of their magic into the block they craft. + shards: [0,1,0,1,1,0,0,0,1] CHISELED_NETHER_BRICKS: - tier: 1 + tier: 2 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Artisan (Nether Bricks) + type: PHILOSOPHICAL lore: - - - shards: + - An artisan, without knowing, gives a portion + - of their magic into the block they craft. + shards: [0,1,0,1,1,0,0,0,1] CHISELED_POLISHED_BLACKSTONE: - tier: 1 + tier: 2 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Artisan (Polished Blackstone) + type: PHILOSOPHICAL lore: - - - shards: + - An artisan, without knowing, gives a portion + - of their magic into the block they craft. + shards: [0,1,0,1,1,0,0,0,1] CHISELED_QUARTZ_BLOCK: - tier: 1 + tier: 3 elements: - - + - HUMAN + - PHILOSOPHICAL + - CELESTIAL story: - name: - type: + name: Artisan (Quartz) + type: PHILOSOPHICAL lore: - - - shards: + - An artisan, without knowing, gives a portion + - of their magic into the block they craft. + shards: [0,1,0,1,1,0,1,0,1] CHISELED_RED_SANDSTONE: - tier: 1 + tier: 2 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Artisan (Red Sandstone) + type: PHILOSOPHICAL lore: - - - shards: + - An artisan, without knowing, gives a portion + - of their magic into the block they craft. + shards: [0,1,0,1,1,0,0,0,1] CHISELED_SANDSTONE: - tier: 1 + tier: 2 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Artisan (Sandstone) + type: PHILOSOPHICAL lore: - - - shards: + - An artisan, without knowing, gives a portion + - of their magic into the block they craft. + shards: [0,1,0,1,1,0,0,0,1] CHISELED_STONE_BRICKS: - tier: 1 + tier: 2 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Artisan (Stone Bricks) + type: PHILOSOPHICAL lore: - - - shards: + - An artisan, without knowing, gives a portion + - of their magic into the block they craft. + shards: [0,1,0,1,1,0,0,0,1] CHORUS_FLOWER: tier: 2 @@ -2130,57 +2171,55 @@ CHORUS_FLOWER: CHORUS_FRUIT: tier: 1 elements: - - - story: - name: - type: - lore: - - - shards: - -CHORUS_PLANT: - tier: 1 - elements: - - + - VOID story: - name: - type: + name: Transmit + type: VOID lore: - - - shards: + - The latent magics of this fruit are in + - a state of constant flux, quantumly connected + - to various nearby points in space-time. + shards: [0,0,1,0,0,0,0,1,0] CLAY: tier: 1 elements: - - + - ELEMENTAL + - HUMAN story: - name: - type: + name: Pliable (Block) + type: HUMAN lore: - - - shards: + - Eagerly waiting to be formed into something + - new. Clay looks forward to it's furture shape. + shards: [1,0,1,0,1,0,0,0,0] CLAY_BALL: tier: 1 elements: - - + - ELEMENTAL + - HUMAN story: - name: - type: + name: Pliable (Ball) + type: HUMAN lore: - - - shards: + - Eagerly waiting to be formed into something + - new. Clay looks forward to it's furture shape. + shards: [1,0,1,0,1,0,0,0,0] CLOCK: - tier: 1 + tier: 2 elements: - - + - MECHANICAL + - HISTORICAL + - HUMAN story: - name: - type: + name: Time to spare + type: HUMAN lore: - - - shards: + - Criminally underused, the clock ends + - up with lots of time to spare. + shards: [0,1,0,1,1,0,0,0,0] COAL: tier: 1 @@ -2387,28 +2426,6 @@ COD_BUCKET: shards: [ 1,0,0,0,1,1,0,0,0 ] author: Seggan -COMMAND_BLOCK: - tier: 1 - elements: - - - story: - name: - type: - lore: - - - shards: - -COMMAND_BLOCK_MINECART: - tier: 1 - elements: - - - story: - name: - type: - lore: - - - shards: - COMPARATOR: tier: 1 elements: @@ -2604,57 +2621,77 @@ CORNFLOWER: CRACKED_DEEPSLATE_BRICKS: tier: 1 elements: - - + - VOID + - PHILOSOPHICAL story: - name: - type: + name: Cracked (Deepslate) + type: VOID lore: - - - shards: + - This block releases it's magic via + - cracks in it's surface into the world. + - This often results in underground pockets + - of Crystamae. + shards: [1,0,0,0,0,0,0,1,1] CRACKED_DEEPSLATE_TILES: tier: 1 elements: - - + - VOID + - PHILOSOPHICAL story: - name: - type: + name: Cracked (Deepslate Tiles) + type: VOID lore: - - - shards: + - This block releases it's magic via + - cracks in it's surface into the world. + - This often results in underground pockets + - of Crystamae. + shards: [1,0,0,0,0,0,0,1,1] CRACKED_NETHER_BRICKS: tier: 1 elements: - - + - VOID + - PHILOSOPHICAL story: - name: - type: + name: Cracked (Nether Bricks) + type: VOID lore: - - - shards: + - This block releases it's magic via + - cracks in it's surface into the world. + - This often results in underground pockets + - of Crystamae. + shards: [1,0,0,0,0,0,0,1,1] CRACKED_POLISHED_BLACKSTONE_BRICKS: tier: 1 elements: - - + - VOID + - PHILOSOPHICAL story: - name: - type: + name: Cracked (Blackstone Bricks) + type: VOID lore: - - - shards: + - This block releases it's magic via + - cracks in it's surface into the world. + - This often results in underground pockets + - of Crystamae. + shards: [1,0,0,0,0,0,0,1,1] CRACKED_STONE_BRICKS: tier: 1 elements: - - + - VOID + - PHILOSOPHICAL story: - name: - type: + name: Cracked (Stone Bricks) + type: VOID lore: - - - shards: + - This block releases it's magic via + - cracks in it's surface into the world. + - This often results in underground pockets + - of Crystamae. + shards: [1,0,0,0,0,0,0,1,1] CRAFTING_TABLE: tier: 1 @@ -3158,15 +3195,18 @@ CYAN_WOOL: author: OOOOMAGAAA DAMAGED_ANVIL: - tier: 1 + tier: 2 elements: - - + - MECHANICAL + - HUMAN story: - name: - type: + name: Hammer Time! (Damaged) + type: MECHANICAL lore: - - - shards: + - The essence of every tool that + - has touched the anvil imparts + - a part of itself to the anvil. + shards: [ 0,1,0,0,1,0,0,0,0 ] DANDELION: tier: 1 @@ -3884,37 +3924,46 @@ DIAMOND_BLOCK: shards: DIAMOND_BOOTS: - tier: 1 + tier: 4 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Greave Greif (Diamond) + type: PHILOSOPHICAL lore: - - - shards: + - Like all armour, boots ant nothing more + - than to keep their wearer safe. Unforunatley + - they are overshadowed by other gear. + shards: [0,0,0,1,2,0,0,0,1] DIAMOND_CHESTPLATE: - tier: 1 + tier: 4 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: The Great Defender (Diamond) + type: HUMAN lore: - - - shards: + - Every hit, scrape and pummel stopped by the + - chestplate reinforces it's magics by giving + - it purpose and drive. + shards: [0,1,0,1,2,0,1,0,0] DIAMOND_HELMET: - tier: 1 + tier: 4 elements: - - + - HUMAN + - VOID story: - name: - type: + name: Head above the rest (Diamond) + type: VOID lore: - - - shards: + - A magicians most important tool is their own + - mind, any steps taken to protect that tool + - are vital and wise. + shards: [0,0,0,1,1,0,0,1,0] DIAMOND_HOE: tier: 1 @@ -3939,15 +3988,18 @@ DIAMOND_HORSE_ARMOR: shards: DIAMOND_LEGGINGS: - tier: 1 + tier: 4 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: Leggless (Diamond) + type: CELESTIAL lore: - - - shards: + - Like it's other armour brethren, leggings + - absorb crysta from their users in miniscule + - amounts over their tenure. + shards: [0,0,0,1,2,0,1,0,0] DIAMOND_ORE: tier: 3 @@ -4868,15 +4920,18 @@ GOLDEN_AXE: shards: GOLDEN_BOOTS: - tier: 1 + tier: 3 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Greave Greif (Gold) + type: PHILOSOPHICAL lore: - - - shards: + - Like all armour, boots ant nothing more + - than to keep their wearer safe. Unforunatley + - they are overshadowed by other gear. + shards: [0,0,0,1,2,0,0,0,1] GOLDEN_CARROT: tier: 1 @@ -4890,26 +4945,32 @@ GOLDEN_CARROT: shards: GOLDEN_CHESTPLATE: - tier: 1 + tier: 3 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: The Great Defender (Gold) + type: HUMAN lore: - - - shards: + - Every hit, scrape and pummel stopped by the + - chestplate reinforces it's magics by giving + - it purpose and drive. + shards: [0,1,0,1,2,0,1,0,0] GOLDEN_HELMET: - tier: 1 + tier: 3 elements: - - + - HUMAN + - VOID story: - name: - type: + name: Head above the rest (Gold) + type: VOID lore: - - - shards: + - A magicians most important tool is their own + - mind, any steps taken to protect that tool + - are vital and wise. + shards: [0,0,0,1,1,0,0,1,0] GOLDEN_HOE: tier: 1 @@ -4934,15 +4995,18 @@ GOLDEN_HORSE_ARMOR: shards: GOLDEN_LEGGINGS: - tier: 1 + tier: 2 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: Leggless (Gold) + type: CELESTIAL lore: - - - shards: + - Like it's other armour brethren, leggings + - absorb crysta from their users in miniscule + - amounts over their tenure. + shards: [0,0,0,1,2,0,1,0,0] GOLDEN_PICKAXE: tier: 1 @@ -5796,26 +5860,32 @@ IRON_BLOCK: shards: [ 1,2,0,0,1,0,0,0,0 ] IRON_BOOTS: - tier: 1 + tier: 3 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Greave Greif (Iron) + type: PHILOSOPHICAL lore: - - - shards: + - Like all armour, boots ant nothing more + - than to keep their wearer safe. Unforunatley + - they are overshadowed by other gear. + shards: [0,0,0,1,2,0,0,0,1] IRON_CHESTPLATE: - tier: 1 + tier: 3 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: The Great Defender (Iron) + type: HUMAN lore: - - - shards: + - Every hit, scrape and pummel stopped by the + - chestplate reinforces it's magics by giving + - it purpose and drive. + shards: [0,1,0,1,2,0,1,0,0] IRON_DOOR: tier: 2 @@ -5832,15 +5902,18 @@ IRON_DOOR: shards: [ 0,2,0,0,1,0,1,0,1 ] IRON_HELMET: - tier: 1 + tier: 3 elements: - - + - HUMAN + - VOID story: - name: - type: + name: Head above the rest (Iron) + type: VOID lore: - - - shards: + - A magicians most important tool is their own + - mind, any steps taken to protect that tool + - are vital and wise. + shards: [0,0,0,1,1,0,0,1,0] IRON_HOE: tier: 1 @@ -5876,15 +5949,18 @@ IRON_INGOT: shards: IRON_LEGGINGS: - tier: 1 + tier: 3 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: Leggless (Iron) + type: CELESTIAL lore: - - - shards: + - Like it's other armour brethren, leggings + - absorb crysta from their users in miniscule + - amounts over their tenure. + shards: [0,0,0,1,2,0,1,0,0] IRON_NUGGET: tier: 1 @@ -6324,35 +6400,44 @@ LEATHER: LEATHER_BOOTS: tier: 1 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Greave Greif (Leather) + type: PHILOSOPHICAL lore: - - - shards: + - Like all armour, boots ant nothing more + - than to keep their wearer safe. Unforunatley + - they are overshadowed by other gear. + shards: [0,0,0,1,2,0,0,0,1] LEATHER_CHESTPLATE: tier: 1 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: The Great Defender (Leather) + type: HUMAN lore: - - - shards: + - Every hit, scrape and pummel stopped by the + - chestplate reinforces it's magics by giving + - it purpose and drive. + shards: [0,1,0,1,2,0,1,0,0] LEATHER_HELMET: tier: 1 elements: - - + - HUMAN + - VOID story: - name: - type: + name: Head above the rest (Leather) + type: VOID lore: - - - shards: + - A magicians most important tool is their own + - mind, any steps taken to protect that tool + - are vital and wise. + shards: [0,0,0,1,1,0,0,1,0] LEATHER_HORSE_ARMOR: tier: 1 @@ -6368,13 +6453,16 @@ LEATHER_HORSE_ARMOR: LEATHER_LEGGINGS: tier: 1 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: Leggless (Leather) + type: CELESTIAL lore: - - - shards: + - Like it's other armour brethren, leggings + - absorb crysta from their users in miniscule + - amounts over their tenure. + shards: [0,0,0,1,2,0,1,0,0] LECTERN: tier: 1 @@ -7678,37 +7766,46 @@ NETHERITE_BLOCK: author: ashton NETHERITE_BOOTS: - tier: 1 + tier: 5 elements: - - + - HUMAN + - PHILOSOPHICAL story: - name: - type: + name: Greave Greif (Netherite) + type: PHILOSOPHICAL lore: - - - shards: + - Like all armour, boots ant nothing more + - than to keep their wearer safe. Unforunatley + - they are overshadowed by other gear. + shards: [0,0,0,1,2,0,0,0,1] NETHERITE_CHESTPLATE: - tier: 1 + tier: 2 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: The Great Defender (Netherite) + type: HUMAN lore: - - - shards: + - Every hit, scrape and pummel stopped by the + - chestplate reinforces it's magics by giving + - it purpose and drive. + shards: [0,1,0,1,2,0,1,0,0] NETHERITE_HELMET: - tier: 1 + tier: 5 elements: - - + - HUMAN + - VOID story: - name: - type: + name: Head above the rest (Netherite) + type: VOID lore: - - - shards: + - A magicians most important tool is their own + - mind, any steps taken to protect that tool + - are vital and wise. + shards: [0,0,0,1,1,0,0,1,0] NETHERITE_HOE: tier: 1 @@ -7733,15 +7830,18 @@ NETHERITE_INGOT: shards: NETHERITE_LEGGINGS: - tier: 1 + tier: 5 elements: - - + - HUMAN + - CELESTIAL story: - name: - type: + name: Leggless (Netherite) + type: CELESTIAL lore: - - - shards: + - Like it's other armour brethren, leggings + - absorb crysta from their users in miniscule + - amounts over their tenure. + shards: [0,0,0,1,2,0,1,0,0] NETHERITE_PICKAXE: tier: 1 @@ -7908,15 +8008,18 @@ NETHER_SPROUTS: shards: NETHER_STAR: - tier: 1 + tier: 5 elements: - - + - VOID story: - name: - type: + name: Crystaline Nether + type: VOID lore: - - - shards: + - Not all magic fits into the Crystamae + - framework, the sheer amount of void from + - the Wither is of this type. The Nether + - Star encapsulates it all. + shards: [1,0,0,1,1,1,0,2,1] NETHER_WART: tier: 1 @@ -10101,17 +10204,6 @@ REPEATER: - shards: -REPEATING_COMMAND_BLOCK: - tier: 1 - elements: - - - story: - name: - type: - lore: - - - shards: - RESPAWN_ANCHOR: tier: 1 elements: @@ -11704,15 +11796,18 @@ TURTLE_EGG: shards: TURTLE_HELMET: - tier: 1 + tier: 3 elements: - - + - HUMAN + - VOID story: - name: - type: + name: Head above the rest (Scute) + type: VOID lore: - - - shards: + - A magicians most important tool is their own + - mind, any steps taken to protect that tool + - are vital and wise. + shards: [0,0,0,1,1,0,0,1,0] TWISTING_VINES: tier: 1 @@ -11805,15 +11900,16 @@ WARPED_FUNGUS: shards: WARPED_FUNGUS_ON_A_STICK: - tier: 1 + tier: 2 elements: - - + - ANIMAL story: - name: - type: + name: A Great Incentive (Warped Fungus) + type: ANIMAL lore: - - - shards: + - Slowly draws magical power from the creatures + - that this item attracts. + shards: [0,0,0,0,1,1,0,0,1] WARPED_HYPHAE: tier: 1 diff --git a/src/main/resources/generic-stories.yml b/src/main/resources/generic-stories.yml index b05febc1..0184a1c6 100644 --- a/src/main/resources/generic-stories.yml +++ b/src/main/resources/generic-stories.yml @@ -1,5 +1,6 @@ COMMON: Quiet Days: + name: Quiet Days type: ELEMENTAL shards: [ 1,0,1,1,0,0,0,0,0 ] lore: @@ -7,6 +8,7 @@ COMMON: - Everything was quiet and peaceful and serene. Grinding Gears: + name: Grinding Gears type: MECHANICAL shards: [ 0,1,0,0,1,0,0,0,0 ] lore: @@ -14,6 +16,7 @@ COMMON: - will wear down the spirit with ease. Lead into Gold: + name: Lead into Gold type: ALCHEMICAL shards: [ 0,0,1,0,1,0,1,0,0 ] lore: @@ -21,6 +24,7 @@ COMMON: - driven many-a-person mad. Everlasting: + name: Everlasting type: HISTORICAL shards: [ 1,0,1,1,0,0,0,0,0 ] lore: @@ -28,6 +32,7 @@ COMMON: - this block is proven everlasting and resolute. Toil: + name: Toil type: HUMAN shards: [ 0,0,0,0,1,0,1,0,1 ] lore: @@ -35,6 +40,7 @@ COMMON: - ages, aiding where possible; a fruitless task. Free Range: + name: Free Range type: ANIMAL shards: [ 0,0,0,0,0,1,1,0,1 ] lore: @@ -42,6 +48,7 @@ COMMON: - the magics more than animals roaming free. Moonlit: + name: Moonlit type: CELESTIAL shards: [ 1,0,0,0,0,1,1,0,0 ] lore: @@ -49,6 +56,7 @@ COMMON: - the light of a waning moon. Despair: + name: Despair type: VOID shards: [ 0,0,0,0,1,0,0,1,1 ] lore: @@ -56,6 +64,7 @@ COMMON: - recesses of a mind causing depair and grief. Good Life: + name: Good Life type: PHILOSOPHICAL shards: [ 0,0,0,0,1,0,0,0,2 ] lore: @@ -64,6 +73,7 @@ COMMON: UNCOMMON: Quiet Days: + name: Quiet Days type: ELEMENTAL shards: [ 1,0,1,1,0,0,0,0,0 ] lore: @@ -71,6 +81,7 @@ UNCOMMON: - Everything was quiet and peaceful and serene. Grinding Gears: + name: Grinding Gears type: MECHANICAL shards: [ 0,1,0,0,1,0,0,0,0 ] lore: @@ -78,6 +89,7 @@ UNCOMMON: - will wear down the spirit with ease. Lead into Gold: + name: Lead into Gold type: ALCHEMICAL shards: [ 0,0,1,0,1,0,1,0,0 ] lore: @@ -85,6 +97,7 @@ UNCOMMON: - driven many-a-person mad. Everlasting: + name: Everlasting type: HISTORICAL shards: [ 1,0,1,1,0,0,0,0,0 ] lore: @@ -92,6 +105,7 @@ UNCOMMON: - this block is proven everlasting and resolute. Toil: + name: Toil type: HUMAN shards: [ 0,0,0,0,1,0,1,0,1 ] lore: @@ -99,6 +113,7 @@ UNCOMMON: - ages, aiding where possible; a fruitless task. Free Range: + name: Free Range type: ANIMAL shards: [ 0,0,0,0,0,1,1,0,1 ] lore: @@ -106,6 +121,7 @@ UNCOMMON: - the magics more than animals roaming free. Moonlit: + name: Moonlit type: CELESTIAL shards: [ 1,0,0,0,0,1,1,0,0 ] lore: @@ -113,6 +129,7 @@ UNCOMMON: - the light of a waning moon. Despair: + name: Despair type: VOID shards: [ 0,0,0,0,1,0,0,1,1 ] lore: @@ -120,6 +137,7 @@ UNCOMMON: - recesses of a mind causing depair and grief. Good Life: + name: Good Life type: PHILOSOPHICAL shards: [ 0,0,0,0,1,0,0,0,2 ] lore: @@ -128,6 +146,7 @@ UNCOMMON: RARE: Quiet Days: + name: Quiet Days type: ELEMENTAL shards: [ 1,0,1,1,0,0,0,0,0 ] lore: @@ -135,6 +154,7 @@ RARE: - Everything was quiet and peaceful and serene. Grinding Gears: + name: Grinding Gears type: MECHANICAL shards: [ 0,1,0,0,1,0,0,0,0 ] lore: @@ -142,6 +162,7 @@ RARE: - will wear down the spirit with ease. Lead into Gold: + name: Lead into Gold type: ALCHEMICAL shards: [ 0,0,1,0,1,0,1,0,0 ] lore: @@ -149,6 +170,7 @@ RARE: - driven many-a-person mad. Everlasting: + name: Everlasting type: HISTORICAL shards: [ 1,0,1,1,0,0,0,0,0 ] lore: @@ -156,6 +178,7 @@ RARE: - this block is proven everlasting and resolute. Toil: + name: Toil type: HUMAN shards: [ 0,0,0,0,1,0,1,0,1 ] lore: @@ -163,6 +186,7 @@ RARE: - ages, aiding where possible; a fruitless task. Free Range: + name: Free Range type: ANIMAL shards: [ 0,0,0,0,0,1,1,0,1 ] lore: @@ -170,6 +194,7 @@ RARE: - the magics more than animals roaming free. Moonlit: + name: Moonlit type: CELESTIAL shards: [ 1,0,0,0,0,1,1,0,0 ] lore: @@ -177,6 +202,7 @@ RARE: - the light of a waning moon. Despair: + name: Despair type: VOID shards: [ 0,0,0,0,1,0,0,1,1 ] lore: @@ -184,6 +210,7 @@ RARE: - recesses of a mind causing depair and grief. Good Life: + name: Good Life type: PHILOSOPHICAL shards: [ 0,0,0,0,1,0,0,0,2 ] lore: @@ -192,6 +219,7 @@ RARE: EPIC: Quiet Days: + name: Quiet Days type: ELEMENTAL shards: [ 1,0,1,1,0,0,0,0,0 ] lore: @@ -199,6 +227,7 @@ EPIC: - Everything was quiet and peaceful and serene. Grinding Gears: + name: Grinding Gears type: MECHANICAL shards: [ 0,1,0,0,1,0,0,0,0 ] lore: @@ -206,6 +235,7 @@ EPIC: - will wear down the spirit with ease. Lead into Gold: + name: Lead into Gold type: ALCHEMICAL shards: [ 0,0,1,0,1,0,1,0,0 ] lore: @@ -213,6 +243,7 @@ EPIC: - driven many-a-person mad. Everlasting: + name: Everlasting type: HISTORICAL shards: [ 1,0,1,1,0,0,0,0,0 ] lore: @@ -220,6 +251,7 @@ EPIC: - this block is proven everlasting and resolute. Toil: + name: Toil type: HUMAN shards: [ 0,0,0,0,1,0,1,0,1 ] lore: @@ -227,6 +259,7 @@ EPIC: - ages, aiding where possible; a fruitless task. Free Range: + name: Free Range type: ANIMAL shards: [ 0,0,0,0,0,1,1,0,1 ] lore: @@ -234,6 +267,7 @@ EPIC: - the magics more than animals roaming free. Moonlit: + name: Moonlit type: CELESTIAL shards: [ 1,0,0,0,0,1,1,0,0 ] lore: @@ -241,6 +275,7 @@ EPIC: - the light of a waning moon. Despair: + name: Despair type: VOID shards: [ 0,0,0,0,1,0,0,1,1 ] lore: @@ -248,6 +283,7 @@ EPIC: - recesses of a mind causing depair and grief. Good Life: + name: Good Life type: PHILOSOPHICAL shards: [ 0,0,0,0,1,0,0,0,2 ] lore: @@ -256,6 +292,7 @@ EPIC: MYTHICAL: Quiet Days: + name: Quiet Days type: ELEMENTAL shards: [ 1,0,1,1,0,0,0,0,0 ] lore: @@ -263,6 +300,7 @@ MYTHICAL: - Everything was quiet and peaceful and serene. Grinding Gears: + name: Grinding Gears type: MECHANICAL shards: [ 0,1,0,0,1,0,0,0,0 ] lore: @@ -270,6 +308,7 @@ MYTHICAL: - will wear down the spirit with ease. Lead into Gold: + name: Lead into Gold type: ALCHEMICAL shards: [ 0,0,1,0,1,0,1,0,0 ] lore: @@ -277,6 +316,7 @@ MYTHICAL: - driven many-a-person mad. Everlasting: + name: Everlasting type: HISTORICAL shards: [ 1,0,1,1,0,0,0,0,0 ] lore: @@ -284,6 +324,7 @@ MYTHICAL: - this block is proven everlasting and resolute. Toil: + name: Toil type: HUMAN shards: [ 0,0,0,0,1,0,1,0,1 ] lore: @@ -291,6 +332,7 @@ MYTHICAL: - ages, aiding where possible; a fruitless task. Free Range: + name: Free Range type: ANIMAL shards: [ 0,0,0,0,0,1,1,0,1 ] lore: @@ -298,6 +340,7 @@ MYTHICAL: - the magics more than animals roaming free. Moonlit: + name: Moonlit type: CELESTIAL shards: [ 1,0,0,0,0,1,1,0,0 ] lore: @@ -305,6 +348,7 @@ MYTHICAL: - the light of a waning moon. Despair: + name: Despair type: VOID shards: [ 0,0,0,0,1,0,0,1,1 ] lore: @@ -312,6 +356,7 @@ MYTHICAL: - recesses of a mind causing depair and grief. Good Life: + name: Good Life type: PHILOSOPHICAL shards: [ 0,0,0,0,1,0,0,0,2 ] lore: