From 0cb646bb568777703bfe422745efeeb38fb5909c Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 19 Sep 2018 09:09:30 +0200 Subject: [PATCH] Add the bag of holding --- .../com/minelittlepony/unicopia/Unicopia.java | 22 +- .../advancements/AdvancementPredicate.java | 31 +++ .../advancements/BOHDeathTrigger.java | 101 ++++++++ .../unicopia/advancements/UAdvancements.java | 11 + .../inventory/ContainerOfHolding.java | 104 ++++++++ .../inventory/InventoryOfHolding.java | 244 ++++++++++++++++++ .../unicopia/inventory/gui/GuiOfHolding.java | 129 +++++++++ .../unicopia/inventory/gui/Scrollbar.java | 212 +++++++++++++++ .../unicopia/item/IMagicalItem.java | 11 + .../unicopia/item/ItemOfHolding.java | 180 +++++++++++++ .../unicopia/player/PlayerAttributes.java | 23 +- .../unicopia/player/PlayerCapabilities.java | 4 +- .../com/minelittlepony/util/WorldEvent.java | 87 +++++++ .../unicopia/advancements/bag_of_holding.json | 23 ++ .../advancements/bag_of_holding_2.json | 23 ++ .../advancements/bag_of_holding_3.json | 23 ++ .../resources/assets/unicopia/lang/en_US.lang | 19 +- .../unicopia/models/item/bag_of_holding.json | 6 + .../assets/unicopia/textures/items/bag_o.png | Bin 0 -> 3107 bytes 19 files changed, 1243 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/advancements/AdvancementPredicate.java create mode 100644 src/main/java/com/minelittlepony/unicopia/advancements/BOHDeathTrigger.java create mode 100644 src/main/java/com/minelittlepony/unicopia/advancements/UAdvancements.java create mode 100644 src/main/java/com/minelittlepony/unicopia/inventory/ContainerOfHolding.java create mode 100644 src/main/java/com/minelittlepony/unicopia/inventory/InventoryOfHolding.java create mode 100644 src/main/java/com/minelittlepony/unicopia/inventory/gui/GuiOfHolding.java create mode 100644 src/main/java/com/minelittlepony/unicopia/inventory/gui/Scrollbar.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/IMagicalItem.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/ItemOfHolding.java create mode 100644 src/main/java/com/minelittlepony/util/WorldEvent.java create mode 100644 src/main/resources/assets/unicopia/advancements/bag_of_holding.json create mode 100644 src/main/resources/assets/unicopia/advancements/bag_of_holding_2.json create mode 100644 src/main/resources/assets/unicopia/advancements/bag_of_holding_3.json create mode 100644 src/main/resources/assets/unicopia/models/item/bag_of_holding.json create mode 100644 src/main/resources/assets/unicopia/textures/items/bag_o.png diff --git a/src/main/java/com/minelittlepony/unicopia/Unicopia.java b/src/main/java/com/minelittlepony/unicopia/Unicopia.java index fd5dfac3..8f77850f 100644 --- a/src/main/java/com/minelittlepony/unicopia/Unicopia.java +++ b/src/main/java/com/minelittlepony/unicopia/Unicopia.java @@ -5,6 +5,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; import net.minecraft.item.EnumAction; import net.minecraft.item.Item; +import net.minecraft.item.crafting.IRecipe; import net.minecraftforge.client.event.FOVUpdateEvent; import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.event.RegistryEvent; @@ -29,6 +30,7 @@ import net.minecraftforge.fml.relauncher.SideOnly; import com.minelittlepony.jumpingcastle.api.IChannel; import com.minelittlepony.jumpingcastle.api.JumpingCastle; import com.minelittlepony.jumpingcastle.api.Target; +import com.minelittlepony.unicopia.advancements.UAdvancements; import com.minelittlepony.unicopia.client.particle.EntityMagicFX; import com.minelittlepony.unicopia.client.particle.EntityRaindropFX; import com.minelittlepony.unicopia.client.particle.Particles; @@ -67,19 +69,28 @@ public class Unicopia { channel.send(new MsgRequestCapabilities(Minecraft.getMinecraft().player), Target.SERVER); }) // client ------> server - .consume(MsgRequestCapabilities.class) + .consume(MsgRequestCapabilities.class, (msg, channel) -> { + + }) // client <------ server - .consume(MsgPlayerCapabilities.class) + .consume(MsgPlayerCapabilities.class, (msg, channel) -> { + System.out.println("[CLIENT] Got capabilities for player I am " + + Minecraft.getMinecraft().player.getGameProfile().getId()); + }) // client ------> server - .consume(MsgPlayerAbility.class); + .consume(MsgPlayerAbility.class, (msg, channel) -> { + + }); MAGIC_PARTICLE = Particles.instance().registerParticle(new EntityMagicFX.Factory()); RAIN_PARTICLE = Particles.instance().registerParticle(new EntityRaindropFX.Factory()); PowersRegistry.instance().init(); + UAdvancements.init(); + FBS.init(); } @@ -93,6 +104,11 @@ public class Unicopia { UBlocks.registerBlocks(event.getRegistry()); } + @SubscribeEvent + public static void registerRecipesStatic(RegistryEvent.Register event) { + UItems.registerRecipes(event.getRegistry()); + } + @SubscribeEvent public static void registerEntitiesStatic(RegistryEvent.Register event) { UEntities.init(event.getRegistry()); diff --git a/src/main/java/com/minelittlepony/unicopia/advancements/AdvancementPredicate.java b/src/main/java/com/minelittlepony/unicopia/advancements/AdvancementPredicate.java new file mode 100644 index 00000000..9c11bb93 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/advancements/AdvancementPredicate.java @@ -0,0 +1,31 @@ +package com.minelittlepony.unicopia.advancements; + +import com.google.gson.JsonElement; + +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.PlayerAdvancements; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.WorldServer; + +/** + * Predicate for testing whether a player has a previous advancement. + * Allows for unlocking advancements in linear succession. + */ +public class AdvancementPredicate { + + public static AdvancementPredicate deserialize(JsonElement json) { + return new AdvancementPredicate(json.getAsString()); + } + + private final ResourceLocation id; + + public AdvancementPredicate(String advancement) { + this.id = new ResourceLocation(advancement); + } + + public boolean test(WorldServer world, PlayerAdvancements playerAdvancements) { + Advancement advancement = world.getAdvancementManager().getAdvancement(id); + + return advancement != null && playerAdvancements.getProgress(advancement).isDone(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/advancements/BOHDeathTrigger.java b/src/main/java/com/minelittlepony/unicopia/advancements/BOHDeathTrigger.java new file mode 100644 index 00000000..ec48a5bf --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/advancements/BOHDeathTrigger.java @@ -0,0 +1,101 @@ +package com.minelittlepony.unicopia.advancements; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; + +import net.minecraft.advancements.ICriterionTrigger; +import net.minecraft.advancements.PlayerAdvancements; +import net.minecraft.advancements.critereon.AbstractCriterionInstance; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.WorldServer; + +/** + * Advantement trigger for the book of holding. It's an achievement to die so spectacularly! :D + */ +public class BOHDeathTrigger implements ICriterionTrigger { + + private static final ResourceLocation ID = new ResourceLocation("unicopia", "death_by_bag_of_holding"); + + private final Map listeners = Maps.newHashMap(); + + @Override + public ResourceLocation getId() { + return ID; + } + + @Override + public void addListener(PlayerAdvancements key, Listener listener) { + listeners.computeIfAbsent(key, Entry::new).listeners.add(listener);; + } + + @Override + public void removeListener(PlayerAdvancements key, Listener listener) { + if (listeners.containsKey(key)) { + Entry entry = listeners.get(key); + + entry.listeners.remove(listener); + if (entry.listeners.isEmpty()) { + listeners.remove(key); + } + } + } + + @Override + public void removeAllListeners(PlayerAdvancements key) { + if (listeners.containsKey(key)) { + listeners.remove(key); + } + } + + @Override + public Instance deserializeInstance(JsonObject json, JsonDeserializationContext context) { + return new Instance(AdvancementPredicate.deserialize(json.get("advancement"))); + } + + public void trigger(EntityPlayerMP player) { + PlayerAdvancements key = player.getAdvancements(); + + Optional.ofNullable(listeners.get(key)).ifPresent(e -> { + e.trigger((WorldServer)player.world, key); + }); + } + + static class Instance extends AbstractCriterionInstance { + + AdvancementPredicate requirement; + + public Instance(AdvancementPredicate requirement) { + super(ID); + + this.requirement = requirement; + } + + public boolean test(WorldServer world, PlayerAdvancements playerAdvancements) { + return requirement.test(world, playerAdvancements); + } + + } + + class Entry { + private final PlayerAdvancements advancement; + + private final List> listeners = Lists.newArrayList(); + + Entry(PlayerAdvancements key) { + advancement = key; + } + + public void trigger(WorldServer world, PlayerAdvancements playerAdvancements) { + listeners.stream() + .filter(listener -> listener.getCriterionInstance().test(world, playerAdvancements)) + .forEach(winner -> winner.grantCriterion(advancement));; + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/advancements/UAdvancements.java b/src/main/java/com/minelittlepony/unicopia/advancements/UAdvancements.java new file mode 100644 index 00000000..5c0b4e03 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/advancements/UAdvancements.java @@ -0,0 +1,11 @@ +package com.minelittlepony.unicopia.advancements; + +import net.minecraft.advancements.CriteriaTriggers; + +public class UAdvancements { + public static final BOHDeathTrigger BOH_DEATH = new BOHDeathTrigger(); + + public static void init() { + CriteriaTriggers.register(BOH_DEATH); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/inventory/ContainerOfHolding.java b/src/main/java/com/minelittlepony/unicopia/inventory/ContainerOfHolding.java new file mode 100644 index 00000000..5836dfd3 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/inventory/ContainerOfHolding.java @@ -0,0 +1,104 @@ +package com.minelittlepony.unicopia.inventory; + +import java.util.List; + +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.world.World; + +public class ContainerOfHolding extends Container { + + private final InventoryOfHolding inventory; + + private final World world; + + private ItemStack sourceStack; + + public ContainerOfHolding(EntityPlayer player) { + world = player.world; + sourceStack = player.getHeldItem(EnumHand.MAIN_HAND); + inventory = InventoryOfHolding.getInventoryFromStack(sourceStack); + + inventory.openInventory(player); + this.onContainerClosed(player); + + final int LEFT_MARGIN = 8; + final int TOP_MARGIN = 18; + + final int inventoryRows = (int)Math.ceil(inventory.getSizeInventory() / 9); + + for (int i = 0; i < inventory.getSizeInventory(); i++) { + int slotX = i % 9; + int slotY = (int)Math.floor(i / 9); + + addSlotToContainer(new SlotOfHolding(inventory, i, LEFT_MARGIN + slotX * 18, TOP_MARGIN + slotY * 18)); + } + + int hotbarY = TOP_MARGIN + (inventoryRows * 18) + 4; + + for (int i = 0; i < 9; ++i) { + addSlotToContainer(new Slot(player.inventory, i, LEFT_MARGIN + i * 18, hotbarY)); + } + } + + @Override + public void onContainerClosed(EntityPlayer player) { + inventory.writeTostack(sourceStack); + inventory.closeInventory(player); + + + super.onContainerClosed(player); + } + + @Override + public boolean canInteractWith(EntityPlayer playerIn) { + return true; + } + + public List getEntities() { + return inventory.getEntities(world); + } + + public ITextComponent getDisplayName() { + return inventory.getDisplayName(); + } + + @Override + public ItemStack transferStackInSlot(EntityPlayer playerIn, int index) { + ItemStack resultingStack = ItemStack.EMPTY; + Slot slot = inventorySlots.get(index); + + if (slot != null && slot.getHasStack()) { + ItemStack originalStack = slot.getStack(); + resultingStack = originalStack.copy(); + + if (index < inventory.getSizeInventory()) { + if (!mergeItemStack(originalStack, inventory.getSizeInventory(), this.inventorySlots.size(), true)) { + return ItemStack.EMPTY; + } + } else if (!this.mergeItemStack(originalStack, 0, inventory.getSizeInventory(), false)) { + return ItemStack.EMPTY; + } + + if (originalStack.isEmpty()) { + slot.putStack(ItemStack.EMPTY); + } else { + slot.onSlotChanged(); + } + } + + return resultingStack; + } + + class SlotOfHolding extends Slot { + public SlotOfHolding(IInventory inventoryIn, int index, int xPosition, int yPosition) { + super(inventoryIn, index, xPosition, yPosition); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/inventory/InventoryOfHolding.java b/src/main/java/com/minelittlepony/unicopia/inventory/InventoryOfHolding.java new file mode 100644 index 00000000..49390aba --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/inventory/InventoryOfHolding.java @@ -0,0 +1,244 @@ +package com.minelittlepony.unicopia.inventory; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Consumer; + +import com.minelittlepony.unicopia.InbtSerialisable; +import com.minelittlepony.unicopia.advancements.UAdvancements; +import com.minelittlepony.unicopia.item.IMagicalItem; +import com.minelittlepony.util.MagicalDamageSource; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockEnderChest; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.gui.advancements.AdvancementState; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.init.SoundEvents; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.InventoryBasic; +import net.minecraft.item.ItemShulkerBox; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class InventoryOfHolding extends InventoryBasic implements InbtSerialisable { + + public static final int NBT_COMPOUND = 10; + public static final int MIN_SIZE = 18; + + List entities; + + private boolean entitiesLoaded = false; + + List livingEntities = new ArrayList<>(); + + static InventoryOfHolding empty() { + List items = new ArrayList<>(); + List entities = new ArrayList<>(); + + return new InventoryOfHolding(items, entities); + } + + public static InventoryOfHolding getInventoryFromStack(ItemStack stack) { + List items = new ArrayList<>(); + List entities = new ArrayList<>(); + + iterateContents(stack, (i, item) -> { + items.add(item); + return true; + }, tag -> { + entities.add((NBTTagCompound)tag); + }); + + return new InventoryOfHolding(items, entities); + } + + public static void iterateContents(ItemStack stack, BiFunction itemConsumer, Consumer entityConsumer) { + if (stack.hasTagCompound() && stack.getTagCompound().hasKey("inventory")) { + NBTTagCompound compound = stack.getOrCreateSubCompound("inventory"); + + if (compound.hasKey("items")) { + NBTTagList list = compound.getTagList("items", NBT_COMPOUND); + for (int i = 0; i < list.tagCount(); i++) { + ItemStack item = new ItemStack(list.getCompoundTagAt(i)); + if (!item.isEmpty()) { + if (!itemConsumer.apply(i, item)) { + break; + } + } + } + } + } + } + + private InventoryOfHolding(List items, List entities) { + super("unicopia.gui.title.bagofholding", false, items.size() + 9 - (items.size() % 9)); + + this.entities = entities; + + for (int i = 0; i < items.size(); i++) { + setInventorySlotContents(i, items.get(i)); + } + } + + public List getEntities(World world) { + return livingEntities; + } + + public void addBlockEntity(World world, BlockPos pos, IBlockState state, T blockInventory) { + ItemStack blockStack = new ItemStack(state.getBlock(), 1, state.getBlock().damageDropped(state)); + + blockInventory.writeToNBT(blockStack.getOrCreateSubCompound("BlockEntityTag")); + + for (int i = 0; i < blockInventory.getSizeInventory(); i++) { + ItemStack stack = blockInventory.getStackInSlot(i); + + if (isIllegalItem(stack)) { + blockStack.getOrCreateSubCompound("inventory").setBoolean("invalid", true); + break; + } + } + + encodeStackWeight(blockStack, getContentsTotalWorth(blockInventory)); + + world.removeTileEntity(pos); + world.setBlockState(pos, Blocks.AIR.getDefaultState()); + + addItem(blockStack); + world.playSound(null, pos, SoundEvents.UI_TOAST_IN, SoundCategory.PLAYERS, 3.5F, 0.25F); + } + + public void addPrisoner(EntityLiving entity) { + getEntities(entity.world).add(entity); + + NBTTagCompound compound = new NBTTagCompound(); + compound.setString("id", EntityList.getKey(entity).toString()); + entity.writeToNBT(compound); + entities.add(compound); + + entity.setDead(); + + entity.playLivingSound(); + entity.playSound(SoundEvents.UI_TOAST_IN, 3.5F, 0.25F); + } + + public void addItem(EntityItem entity) { + addItem(entity.getItem()); + entity.setDead(); + + entity.playSound(SoundEvents.UI_TOAST_IN, 3.5F, 0.25F); + } + + @Override + public void closeInventory(EntityPlayer player) { + if (checkExplosionConditions()) { + if (player instanceof EntityPlayerMP) { + UAdvancements.BOH_DEATH.trigger((EntityPlayerMP)player); + } + player.attackEntityFrom(MagicalDamageSource.create("paradox"), 1000); + player.world.createExplosion(player, player.posX, player.posY, player.posZ, 5, true); + } + } + + protected boolean checkExplosionConditions() { + for (int i = 0; i < getSizeInventory(); i++) { + if (isIllegalItem(getStackInSlot(i))) { + return true; + } + } + + return false; + } + + protected boolean isIllegalItem(ItemStack stack) { + NBTTagCompound compound = stack.getSubCompound("inventory"); + + return isIllegalBlock(Block.getBlockFromItem(stack.getItem())) + || stack.getItem() instanceof ItemShulkerBox + || (compound != null && compound.hasKey("invalid")) + || (stack.getItem() instanceof IMagicalItem && ((IMagicalItem) stack.getItem()).hasInnerSpace()); + } + + protected boolean isIllegalBlock(Block block) { + return block instanceof BlockEnderChest; + } + + @Override + public void writeToNBT(NBTTagCompound compound) { + NBTTagList nbtItems = new NBTTagList(); + + for (int i = 0; i < getSizeInventory(); i++) { + NBTTagCompound comp = new NBTTagCompound(); + ItemStack stack = getStackInSlot(i); + if (!isIllegalItem(stack)) { + if (!stack.isEmpty()) { + stack.writeToNBT(comp); + nbtItems.appendTag(comp); + } + } + } + compound.setTag("items", nbtItems); + compound.setDouble("weight", getContentsTotalWorth()); + } + + public double getContentsTotalWorth() { + return getContentsTotalWorth(this); + } + + public void writeTostack(ItemStack stack) { + writeToNBT(stack.getOrCreateSubCompound("inventory")); + } + + public static double getContentsTotalWorth(IInventory inventory) { + double total = 0; + + for (int i = 0; i < inventory.getSizeInventory(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + + total += stack.getCount(); + total += decodeStackWeight(stack); + } + + return total; + } + + public static void encodeStackWeight(ItemStack stack, double weight) { + NBTTagCompound compound = stack.getSubCompound("inventory"); + if (weight == 0 && compound != null) { + compound.removeTag("weight"); + if (compound.isEmpty()) { + stack.removeSubCompound("inventory"); + } + } else { + if (weight != 0) { + if (compound == null) { + compound = stack.getOrCreateSubCompound("inventory"); + } + + compound.setDouble("weight", weight); + } + } + } + + public static double decodeStackWeight(ItemStack stack) { + if (!stack.isEmpty()) { + NBTTagCompound compound = stack.getSubCompound("inventory"); + if (compound != null && compound.hasKey("weight")) { + return compound.getDouble("weight"); + } + } + + return 0; + } +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/inventory/gui/GuiOfHolding.java b/src/main/java/com/minelittlepony/unicopia/inventory/gui/GuiOfHolding.java new file mode 100644 index 00000000..dc2b7e57 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/inventory/gui/GuiOfHolding.java @@ -0,0 +1,129 @@ +package com.minelittlepony.unicopia.inventory.gui; + +import java.io.IOException; + +import com.minelittlepony.unicopia.inventory.ContainerOfHolding; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.gui.inventory.GuiInventory; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.entity.EntityLiving; +import net.minecraft.init.SoundEvents; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.IInteractionObject; + +public class GuiOfHolding extends GuiContainer { + private static final ResourceLocation CHEST_GUI_TEXTURE = new ResourceLocation("textures/gui/container/generic_54.png"); + + private final int inventoryRows; + + private final Scrollbar scrollbar = new Scrollbar(); + + public GuiOfHolding(IInteractionObject interaction) { + super(interaction.createContainer(Minecraft.getMinecraft().player.inventory, Minecraft.getMinecraft().player)); + + inventoryRows = (inventorySlots.inventorySlots.size() / 9) - 1; + } + + @Override + public void initGui() { + + super.initGui(); + + scrollbar.reposition( + guiLeft + xSize, + guiTop, + ySize, + (inventoryRows + 1) * 18 + 17); + } + + @Override + public void onGuiClosed() { + super.onGuiClosed(); + mc.player.playSound(SoundEvents.BLOCK_ENDERCHEST_OPEN, 0.5F, 0.5F); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + drawDefaultBackground(); + + scrollbar.render(mouseX, mouseY, partialTicks); + + int scroll = -scrollbar.getScrollAmount(); + + GlStateManager.pushMatrix(); + GlStateManager.translate(0, scroll, 0); + + super.drawScreen(mouseX, mouseY - scroll, partialTicks); + + int h = height; + height = Integer.MAX_VALUE; + renderHoveredToolTip(mouseX, mouseY - scroll); + height = h; + + GlStateManager.popMatrix(); + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { + scrollbar.performAction(mouseX, mouseY); + super.mouseClicked(mouseX, mouseY + scrollbar.getScrollAmount(), mouseButton); + } + + @Override + protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { + super.mouseClickMove(mouseX, mouseY + scrollbar.getScrollAmount(), clickedMouseButton, timeSinceLastClick); + + if (!dragSplitting) { + scrollbar.mouseMove(mouseX, mouseY, timeSinceLastClick); + } + } + + @Override + protected void mouseReleased(int mouseX, int mouseY, int state) { + super.mouseReleased(mouseX, mouseY + scrollbar.getScrollAmount(), state); + scrollbar.mouseUp(mouseX, mouseY); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + + ContainerOfHolding coh = (ContainerOfHolding)inventorySlots; + + fontRenderer.drawString(coh.getDisplayName().getUnformattedText(), 8, 6, 4210752); + + + + } + + @Override + protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { + GlStateManager.color(1, 1, 1, 1); + + mc.getTextureManager().bindTexture(CHEST_GUI_TEXTURE); + + int midX = (width - xSize) / 2; + int midY = (height - ySize) / 2; + + drawTexturedModalRect(midX, midY, 0, 0, xSize, 18); + for (int i = 0; i < inventoryRows; i++) { + drawTexturedModalRect(midX, midY + (18 * (i + 1)), 0, 18, xSize, 18); + } + drawTexturedModalRect(midX, midY + inventoryRows * 18 + 17, 0, 193, xSize, 30); + + ContainerOfHolding coh = (ContainerOfHolding)inventorySlots; + + int left = (width - xSize) / 2; + int top = (height - ySize) / 2; + + int i = 0; + for (EntityLiving entity : coh.getEntities()) { + int x = i % 9; + int y = i / 9; + GuiInventory.drawEntityOnScreen(left + x * 18, top + y * 30, 18, xSize - mouseX, guiTop + 30 - mouseY, entity); + + i++; + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/inventory/gui/Scrollbar.java b/src/main/java/com/minelittlepony/unicopia/inventory/gui/Scrollbar.java new file mode 100644 index 00000000..96dc22f8 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/inventory/gui/Scrollbar.java @@ -0,0 +1,212 @@ +package com.minelittlepony.unicopia.inventory.gui; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.init.SoundEvents; +import net.minecraft.util.math.MathHelper; + +public class Scrollbar { + + private boolean dragging = false; + private boolean touching = false; + + private int scrollY = 0; + + private int thickness = 6; + + private float scrollMomentum = 0; + private float scrollFactor = 0; + + private int maxScrollY = 0; + private int shiftFactor = 0; + + private int elementHeight; + private int contentHeight; + + private int x; + private int y; + + private int initialMouseY; + + public Scrollbar() { + + } + + public void reposition(int x, int y, int elementHeight, int contentHeight) { + this.x = x; + this.y = y; + this.elementHeight = elementHeight; + this.contentHeight = contentHeight; + + maxScrollY = contentHeight - elementHeight; + if (maxScrollY < 0) { + maxScrollY = 0; + } + scrollFactor = elementHeight == 0 ? 1 : contentHeight / elementHeight; + + scrollBy(0); + } + + public int getScrollAmount() { + return scrollY; + } + + public void render(int mouseX, int mouseY, float partialTicks) { + if (!touching && !dragging) { + scrollMomentum *= partialTicks; + if (scrollMomentum > 0) { + scrollBy(scrollMomentum); + } + + if (shiftFactor != 0) { + scrollBy(shiftFactor * scrollFactor); + shiftFactor = computeShiftFactor(mouseX, mouseY); + } + } + + if (maxScrollY <= 0) return; + + renderVertical(); + } + + protected void renderVertical() { + int scrollbarHeight = getScrubberLength(elementHeight, contentHeight); + int scrollbarTop = getScrubberStart(scrollbarHeight, elementHeight, contentHeight); + + renderBackground(y, x, y + elementHeight, x + thickness); + renderBar(x, x + thickness, scrollbarTop, scrollbarTop + scrollbarHeight); + } + + protected int getScrubberStart(int scrollbarHeight, int elementHeight, int contentHeight) { + if (maxScrollY == 0) { + return 0; + } + + int scrollbarTop = y + getScrollAmount() * (elementHeight - scrollbarHeight) / maxScrollY; + if (scrollbarTop < 0) { + return 0; + } + return scrollbarTop; + } + + protected int getScrubberLength(int elementL, int contentL) { + return MathHelper.clamp(elementL * elementL / contentL, 32, elementL - 8); + } + + public boolean isFocused(int mouseX, int mouseY) { + return mouseY >= y + && mouseY <= y + elementHeight + && mouseX >= (x - 10) + && mouseX <= (x + thickness + 1); + } + + private void renderBackground(int top, int left, int bottom, int right) { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + + GlStateManager.color(1, 1, 1, 1); + GlStateManager.disableTexture2D(); + + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ZERO, GlStateManager.DestFactor.ONE); + GlStateManager.disableAlpha(); + GlStateManager.shadeModel(7425); + + bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + bufferbuilder.pos(left, bottom, 0).tex(0, 1).color(0, 0, 0, 150).endVertex(); + bufferbuilder.pos(right, bottom, 0).tex(1, 1).color(0, 0, 0, 150).endVertex(); + bufferbuilder.pos(right, top, 0).tex(1, 0).color(0, 0, 0, 150).endVertex(); + bufferbuilder.pos(left, top, 0).tex(0, 0).color(0, 0, 0, 150).endVertex(); + tessellator.draw(); + + GlStateManager.shadeModel(7424); + GlStateManager.enableAlpha(); + GlStateManager.disableBlend(); + } + + private void renderBar(int left, int right, int top, int bottom) { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + + GlStateManager.color(1, 1, 1, 1); + GlStateManager.disableTexture2D(); + + int B = dragging ? 170 : 128; + int b = dragging ? 252 : 192; + + //actual bar + bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + bufferbuilder.pos(left, bottom, 0).tex(0, 1).color(128, 128, B, 255).endVertex(); + bufferbuilder.pos(right, bottom, 0).tex(1, 1).color(128, 128, B, 255).endVertex(); + bufferbuilder.pos(right, top, 0).tex(1, 0).color(128, 128, B, 255).endVertex(); + bufferbuilder.pos(left, top, 0).tex(0, 0).color(128, 128, B, 255).endVertex(); + tessellator.draw(); + + bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); + bufferbuilder.pos(left, bottom - 1, 0).tex(0, 1).color(192, 192, b, 255).endVertex(); + bufferbuilder.pos(right - 1, bottom - 1, 0).tex(1, 1).color(192, b, 192, 255).endVertex(); + bufferbuilder.pos(right - 1, top, 0).tex(1, 0).color(192, 192, b, 255).endVertex(); + bufferbuilder.pos(left, top, 0.0D).tex(0, 0).color(192, 192, b, 255).endVertex(); + tessellator.draw(); + + GlStateManager.enableTexture2D(); + } + + private int computeShiftFactor(int mouseX, int mouseY) { + int pos = mouseY; + + int scrubberLength = getScrubberLength(elementHeight, contentHeight); + int scrubberStart = getScrubberStart(scrubberLength, elementHeight, contentHeight); + + if (pos < scrubberStart) { + return 1; + } else if (pos > scrubberStart + scrubberLength) { + return -1; + } + + return 0; + } + + public boolean performAction(int mouseX, int mouseY) { + + if (!isFocused(mouseX, mouseY)) { + touching = true; + return true; + } + + shiftFactor = computeShiftFactor(mouseX, mouseY); + + if (shiftFactor == 0) { + Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(SoundEvents.UI_BUTTON_CLICK, 1)); + dragging = true; + } + + return true; + } + + public void mouseMove(int mouseX, int mouseY, float partialTicks) { + if (dragging) { + scrollBy(initialMouseY - mouseY); + } else if (touching) { + scrollMomentum = mouseY - initialMouseY; + + scrollBy((mouseY - initialMouseY) / 4); + } + + initialMouseY = mouseY; + } + + public void mouseUp(int mouseX, int mouseY) { + dragging = touching = false; + shiftFactor = 0; + } + + public void scrollBy(float y) { + scrollY = MathHelper.clamp((int)Math.floor(scrollY - y * scrollFactor), 0, maxScrollY); + } + +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/IMagicalItem.java b/src/main/java/com/minelittlepony/unicopia/item/IMagicalItem.java new file mode 100644 index 00000000..3d535fc3 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/IMagicalItem.java @@ -0,0 +1,11 @@ +package com.minelittlepony.unicopia.item; + +public interface IMagicalItem { + /** + * If true this item serves as host to its own inner dimensional space. + * Bag of Holding will explode if you try to store items of this kind inside of it. + */ + default boolean hasInnerSpace() { + return false; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemOfHolding.java b/src/main/java/com/minelittlepony/unicopia/item/ItemOfHolding.java new file mode 100644 index 00000000..b45a0f95 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/ItemOfHolding.java @@ -0,0 +1,180 @@ +package com.minelittlepony.unicopia.item; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + +import com.minelittlepony.unicopia.Predicates; +import com.minelittlepony.unicopia.UClient; +import com.minelittlepony.unicopia.inventory.ContainerOfHolding; +import com.minelittlepony.unicopia.inventory.InventoryOfHolding; +import com.minelittlepony.unicopia.inventory.gui.GuiOfHolding; +import com.minelittlepony.util.vector.VecHelper; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.IInteractionObject; +import net.minecraft.world.World; + +public class ItemOfHolding extends Item implements IMagicalItem { + + public ItemOfHolding(String domain, String name) { + setCreativeTab(CreativeTabs.TRANSPORTATION); + setTranslationKey(name); + setRegistryName(domain, name); + setMaxStackSize(1); + } + + @Override + public void addInformation(ItemStack stack, @Nullable World worldIn, List tooltip, ITooltipFlag flagIn) { + super.addInformation(stack, worldIn, tooltip, flagIn); + + Map counts = new HashMap<>(); + + InventoryOfHolding.iterateContents(stack, (i, itemstack) -> { + String name = itemstack.getDisplayName(); + + counts.put(name, counts.getOrDefault(name, 0) + itemstack.getCount()); + return true; + }, tag -> { + String name = tag.getString("id"); + + counts.put(name, counts.getOrDefault(name, 0) + 1); + }); + + for (String name : counts.keySet()) { + tooltip.add(String.format("%s x%d", name, counts.get(name))); + } + } + + @Override + public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { + + if (!Predicates.MAGI.test(player)) { + return super.onItemRightClick(world, player, hand); + } + + ItemStack stack = player.getHeldItem(hand); + + if (player.isSneaking()) { + RayTraceResult hit = VecHelper.getObjectMouseOver(player, 5, 0); + + if (hit != null) { + if (hit.typeOfHit == RayTraceResult.Type.BLOCK) { + BlockPos pos = hit.getBlockPos(); + + IBlockState state = world.getBlockState(pos); + TileEntity tile = world.getTileEntity(pos); + + if (tile instanceof IInventory) { + InventoryOfHolding inventory = InventoryOfHolding.getInventoryFromStack(stack); + + inventory.addBlockEntity(world, pos, state, (TileEntity & IInventory)tile); + inventory.writeTostack(stack); + inventory.closeInventory(player); + + return new ActionResult<>(EnumActionResult.SUCCESS, stack); + } + + AxisAlignedBB box = new AxisAlignedBB(pos.offset(hit.sideHit)).grow(0.5); + + List itemsAround = world.getEntitiesInAABBexcluding(player, box, e -> e.isEntityAlive() && e instanceof EntityItem); + + if (itemsAround.size() > 0) { + InventoryOfHolding inventory = InventoryOfHolding.getInventoryFromStack(stack); + + inventory.addItem((EntityItem)itemsAround.get(0)); + inventory.writeTostack(stack); + inventory.closeInventory(player); + + return new ActionResult<>(EnumActionResult.SUCCESS, stack); + } + + } else if (hit.typeOfHit == RayTraceResult.Type.ENTITY && hit.entityHit instanceof EntityLiving) { + + /*if (!(hit.entityHit instanceof EntityPlayer)) { + InventoryOfHolding inventory = InventoryOfHolding.getInventoryFromStack(stack); + + inventory.addPrisoner((EntityLiving)hit.entityHit); + inventory.writeTostack(stack); + inventory.closeInventory(player); + + return new ActionResult<>(EnumActionResult.SUCCESS, stack); + }*/ + } + } + + + return new ActionResult<>(EnumActionResult.FAIL, stack); + } else { + + IInteractionObject inventory = new Inventory(); + + if (UClient.isClientSide() && player instanceof EntityPlayerSP) { + Minecraft.getMinecraft().displayGuiScreen(new GuiOfHolding(inventory)); + player.playSound(SoundEvents.BLOCK_ENDERCHEST_OPEN, 0.5F, 1); + } else { + player.displayGui(inventory); + } + + return new ActionResult<>(EnumActionResult.SUCCESS, stack); + } + } + + public class Inventory implements IInteractionObject { + + @Override + public String getName() { + return "unicopi.gui.title.itemofholding"; + } + + @Override + public boolean hasCustomName() { + return false; + } + + @Override + public ITextComponent getDisplayName() { + return new TextComponentTranslation(getName()); + } + + @Override + public Container createContainer(InventoryPlayer playerInventory, EntityPlayer player) { + return new ContainerOfHolding(player); + } + + @Override + public String getGuiID() { + return "unicopia:itemofholding"; + } + } + + @Override + public boolean hasInnerSpace() { + return true; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/player/PlayerAttributes.java b/src/main/java/com/minelittlepony/unicopia/player/PlayerAttributes.java index 9681e66b..53fbb0ef 100644 --- a/src/main/java/com/minelittlepony/unicopia/player/PlayerAttributes.java +++ b/src/main/java/com/minelittlepony/unicopia/player/PlayerAttributes.java @@ -3,30 +3,43 @@ package com.minelittlepony.unicopia.player; import java.util.UUID; import com.minelittlepony.unicopia.Race; +import com.minelittlepony.unicopia.inventory.InventoryOfHolding; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.ai.attributes.IAttribute; import net.minecraft.entity.ai.attributes.IAttributeInstance; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; class PlayerAttributes { public static final int ADD = 0; public static final int ADD_PERCENTAGE = 1; public static final int MULTIPLY = 2; - public static final PlayerAttributes instance = new PlayerAttributes(); - - private final AttributeModifier EARTH_PONY_STRENGTH = + private static final AttributeModifier EARTH_PONY_STRENGTH = new AttributeModifier(UUID.fromString("777a5505-521e-480b-b9d5-6ea54f259564"), "Earth Pony Strength", 0.6, MULTIPLY); - private final AttributeModifier PEGASUS_SPEED = + private static final AttributeModifier PEGASUS_SPEED = new AttributeModifier(UUID.fromString("9e2699fc-3b8d-4f71-9d2d-fb92ee19b4f7"), "Pegasus Speed", 0.2, MULTIPLY); - private final AttributeModifier PEGASUS_REACH = + private static final AttributeModifier PEGASUS_REACH = new AttributeModifier(UUID.fromString("707b50a8-03e8-40f4-8553-ecf67025fd6d"), "Pegasus Reach", 1.5, ADD); + private double loadStrength = 0; + public void applyAttributes(EntityPlayer entity, Race race) { + loadStrength = 0; + + for (ItemStack item : entity.inventory.mainInventory) { + loadStrength += InventoryOfHolding.decodeStackWeight(item); + } + for (ItemStack item : entity.inventory.armorInventory) { + loadStrength += InventoryOfHolding.decodeStackWeight(item); + } + + entity.capabilities.setPlayerWalkSpeed(0.1F - (float)(loadStrength / 100000)); + applyAttribute(entity, SharedMonsterAttributes.ATTACK_DAMAGE, EARTH_PONY_STRENGTH, race.canUseEarth()); applyAttribute(entity, SharedMonsterAttributes.KNOCKBACK_RESISTANCE, EARTH_PONY_STRENGTH, race.canUseEarth()); applyAttribute(entity, SharedMonsterAttributes.MOVEMENT_SPEED, PEGASUS_SPEED, race.canFly()); diff --git a/src/main/java/com/minelittlepony/unicopia/player/PlayerCapabilities.java b/src/main/java/com/minelittlepony/unicopia/player/PlayerCapabilities.java index 8d7cdad4..433d9f94 100644 --- a/src/main/java/com/minelittlepony/unicopia/player/PlayerCapabilities.java +++ b/src/main/java/com/minelittlepony/unicopia/player/PlayerCapabilities.java @@ -36,6 +36,8 @@ class PlayerCapabilities implements IPlayer, ICaster { private final PlayerGravityDelegate gravity = new PlayerGravityDelegate(this); + private final PlayerAttributes attributes = new PlayerAttributes(); + private float nextStepDistance = 1; private IMagicEffect effect; @@ -131,7 +133,7 @@ class PlayerCapabilities implements IPlayer, ICaster { addExertion(-1); - PlayerAttributes.instance.applyAttributes(entity, getPlayerSpecies()); + attributes.applyAttributes(entity, getPlayerSpecies()); } @Override diff --git a/src/main/java/com/minelittlepony/util/WorldEvent.java b/src/main/java/com/minelittlepony/util/WorldEvent.java new file mode 100644 index 00000000..d7d7290f --- /dev/null +++ b/src/main/java/com/minelittlepony/util/WorldEvent.java @@ -0,0 +1,87 @@ +package com.minelittlepony.util; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +/** + * All of the Auxiliary effects used in minecraft for World.spawnEvent + */ +public enum WorldEvent { + DISPENSER_DISPENSE_BLOCK(1000), + DISPENSER_FAIL(1001), + DISPENSE_SHOOT_PROJECTILE(1002), + LAUNCH_ENDER_PEAR(1003), + LAUNCH_FIREWORKS_ROCKET(1004), + RECORD_DROP(1005), IRON_DOOR_OPEN(1005), + WOODEN_DOOR_OPEN(1006), + WOODEN_TRAPDOOR_OPEN(1007), + GATE_OPEN(1008), + FIRE_EXTENGUISH(1009), + PLAY_RECORD(1010), + IRON_DOOR_SLAM(1011), + WOODEN_DOOR_SLAM(1012), + WOODEN_TRAPDOOR_SLAM(1013), + FENCE_GATE_SWIVEL(1014), + GHAST_SCREAM(1015), + GHAST_SHOOT(1016), + ENDERMAN_SCREAM(1017), + FIRE_SHOOT(1018), + DOOR_SWIVEL(1019), WOOD_DOOR_KNOCK(1019), + REPAIR_ITEM(1020), IRON_DOOR_KNOCK(1020), + DOOR_BROKEN(1021), + WITHER_ATTACK(1022), + WITHER_SHOOT(1024), + ENTITY_TAKEOFF(1025), + MOB_INFECT(1026), + MOB_CURE(1027), + ANVIL_DESTROY(1029), + ANVIL_USE(1030), + ANVIL_LAND(1031), + PORTAL_WARP(1032), + ORGANIC_WET(1033), + ORGANIC_DRY(1034), + BREW_POTION(1035), + DOOR_CLOSE(1036), + DOOR_OPEN(1037), + + + + + + + DISPENSE_PARTICLES(2000), + DESTROY_BLOCK(2001), + XP_POP(2002), PROJECTILE_HIT(2002), + EYE_OF_ENDER(2003), + MOB_SPAWN(2004), + BONEMEAN(2005), + DRAGON_BREATH(2006), + POTION_INSTANT(2007), + DRAGON_DEFEATED(3000), + DRAGON_ROARS(3001), + + UNKNOWN(0); + + private final int id; + + WorldEvent(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public void play(World world, BlockPos pos, int data) { + world.playEvent(getId(), pos, data); + } + + public static WorldEvent fromId(int id) { + for (WorldEvent i : values()) { + if (i.id == id) { + return i; + } + } + return UNKNOWN; + } +} diff --git a/src/main/resources/assets/unicopia/advancements/bag_of_holding.json b/src/main/resources/assets/unicopia/advancements/bag_of_holding.json new file mode 100644 index 00000000..6f3bd585 --- /dev/null +++ b/src/main/resources/assets/unicopia/advancements/bag_of_holding.json @@ -0,0 +1,23 @@ +{ + "display": { + "icon": { + "item": "unicopia:bag_of_holding" + }, + "title": { + "translate": "advancements.adventure.bag_of_holding.title" + }, + "description": { + "translate": "advancements.adventure.bag_of_holding.description" + }, + "frame": "challenge" + }, + "parent": "minecraft:adventure/root", + "criteria": { + "death_by_bag_of_holding": { + "trigger": "unicopia:death_by_bag_of_holding", + "conditions": { + "advancement": "minecraft:adventure/root" + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/advancements/bag_of_holding_2.json b/src/main/resources/assets/unicopia/advancements/bag_of_holding_2.json new file mode 100644 index 00000000..e0086833 --- /dev/null +++ b/src/main/resources/assets/unicopia/advancements/bag_of_holding_2.json @@ -0,0 +1,23 @@ +{ + "display": { + "icon": { + "item": "unicopia:bag_of_holding" + }, + "title": { + "translate": "advancements.adventure.bag_of_holding_2.title" + }, + "description": { + "translate": "advancements.adventure.bag_of_holding_2.description" + }, + "frame": "challenge" + }, + "parent": "unicopia:bag_of_holding", + "criteria": { + "death_by_bag_of_holding": { + "trigger": "unicopia:death_by_bag_of_holding", + "conditions": { + "advancement": "unicopia:bag_of_holding" + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/advancements/bag_of_holding_3.json b/src/main/resources/assets/unicopia/advancements/bag_of_holding_3.json new file mode 100644 index 00000000..b5da8685 --- /dev/null +++ b/src/main/resources/assets/unicopia/advancements/bag_of_holding_3.json @@ -0,0 +1,23 @@ +{ + "display": { + "icon": { + "item": "unicopia:bag_of_holding" + }, + "title": { + "translate": "advancements.adventure.bag_of_holding_3.title" + }, + "description": { + "translate": "advancements.adventure.bag_of_holding_3.description" + }, + "frame": "challenge" + }, + "parent": "unicopia:bag_of_holding_2", + "criteria": { + "death_by_bag_of_holding": { + "trigger": "unicopia:death_by_bag_of_holding", + "conditions": { + "advancement": "unicopia:bag_of_holding_2" + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/lang/en_US.lang b/src/main/resources/assets/unicopia/lang/en_US.lang index f21a7fd3..6ba7a680 100644 --- a/src/main/resources/assets/unicopia/lang/en_US.lang +++ b/src/main/resources/assets/unicopia/lang/en_US.lang @@ -13,6 +13,10 @@ item.cloud.small.name=Bucking Bronco item.cloud.medium.name=Construction Cloud item.cloud.large.name=Wild Cloud +item.mist_door.name=Cloud Door +item.dew_drop.name=Dew Drop +item.cloud_anvil.name=Anvilhead Anvil + item.spell.name=Gem item.spell.shield.name=Gem of Repulsion item.spell.fire.name=Gem of Flame @@ -22,6 +26,7 @@ item.spell.portal.name=Gem of Teleportation item.spell.attract.name=Gem of Retention item.spell.minion.name=Gem of Obedience item.spellbook.name=Spellbook +item.bag_of_holding.name=Bag of Holding item.apple.green.name=Granny Smith Apple item.apple.sweet.name=Sweet Apple Acres Apple @@ -31,7 +36,7 @@ item.apple.zap_cooked.name=Cooked Zap Apple entity.racing_cloud.name=Bucking Bronco entity.construction_cloud.name=Construction Cloud -entity.wild_cloud.name=Cloud +entity.cloud.name=Cloud entity.spell.name=Magic @@ -102,6 +107,8 @@ unicopia.power.thunder=Secondary Pegasus ability unicopia.power.feed=Primary Changeling ability unicopia.power.disguise=Secondary Changeling ability +unicopia.gui.title.bagofholding=Bag of Holding + death.attack.feed=%1$s was drained of all life death.attack.feed.player=%1$s died to feed %2$s death.attack.cold=%1$s died of frost bite @@ -113,3 +120,13 @@ death.attack.fire=%1$s was burnt to a crisp by magic death.attack.fire.player=%1$s was burnt to a crisp by %2$s death.attack.fire.own=%1$s was burnt to a crisp by their own spell death.attack.zap=%1$s ate a Zap Apple +death.attack.paradox=%1$s imploded + +advancements.adventure.bag_of_holding.title=Read the Manual +advancements.adventure.bag_of_holding.description=Successfuly die using the Bag of Holding + +advancements.adventure.bag_of_holding_2.title=Oops! I did it again +advancements.adventure.bag_of_holding_2.description=Die by the Bag of Holding a second time + +advancements.adventure.bag_of_holding_3.title=Oh come on! +advancements.adventure.bag_of_holding_3.description=-_- \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/models/item/bag_of_holding.json b/src/main/resources/assets/unicopia/models/item/bag_of_holding.json new file mode 100644 index 00000000..335de150 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/bag_of_holding.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:items/bag_o" + } +} diff --git a/src/main/resources/assets/unicopia/textures/items/bag_o.png b/src/main/resources/assets/unicopia/textures/items/bag_o.png new file mode 100644 index 0000000000000000000000000000000000000000..ed885db7f8d2b09cf2b6c1f4773cec0013e5a8ef GIT binary patch literal 3107 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 literal 0 HcmV?d00001